Files
GmRelayBot/tests/GmRelay.Bot.Tests/Rendering/TelegramSessionBatchRendererTests.cs
T
Toutsu 47b22c7401 test: extend TelegramSessionBatchRendererTests with regression cases
- Empty sessions
- HTML encoding in title
- Confirmed status buttons
- No join link handling

Issue: #33
2026-05-21 15:19:08 +03:00

152 lines
6.8 KiB
C#

using GmRelay.Bot.Infrastructure.Telegram;
using GmRelay.Shared.Domain;
using GmRelay.Shared.Rendering;
using Telegram.Bot.Types.ReplyMarkups;
namespace GmRelay.Bot.Tests.Rendering;
public sealed class TelegramSessionBatchRendererTests
{
[Fact]
public void Render_ShouldProduceCorrectHtmlAndButtons()
{
var firstSessionId = Guid.NewGuid();
var secondSessionId = Guid.NewGuid();
var cancelledSessionId = Guid.NewGuid();
var sessions = new[]
{
new SessionBatchDto(secondSessionId, new DateTime(2026, 4, 27, 18, 0, 0, DateTimeKind.Utc), SessionStatus.Planned, 4, "https://example.com/game2"),
new SessionBatchDto(cancelledSessionId, new DateTime(2026, 4, 28, 18, 0, 0, DateTimeKind.Utc), SessionStatus.Cancelled, null, ""),
new SessionBatchDto(firstSessionId, new DateTime(2026, 4, 26, 18, 0, 0, DateTimeKind.Utc), SessionStatus.Planned, 2, "https://example.com/game1")
};
var participants = new[]
{
new ParticipantBatchDto(secondSessionId, "Alice", "alice", ParticipantRegistrationStatus.Active),
new ParticipantBatchDto(secondSessionId, "Charlie", null, ParticipantRegistrationStatus.Waitlisted),
new ParticipantBatchDto(cancelledSessionId, "Bob", null, ParticipantRegistrationStatus.Active)
};
var view = SessionBatchViewBuilder.Build("Campaign", sessions, participants);
var (text, markup) = TelegramSessionBatchRenderer.Render(view);
Assert.Contains("Campaign", text);
Assert.Contains("@alice", text);
Assert.Contains("Charlie", text);
Assert.Contains("Bob", text);
Assert.Contains("Сессия отменена", text);
Assert.Contains("Ссылка на игру", text);
Assert.Contains("https://example.com/game1", text);
Assert.Contains("https://example.com/game2", text);
var buttons = markup.InlineKeyboard.SelectMany(row => row).ToList();
Assert.Equal(4, buttons.Count); // 2 sessions x 2 buttons each
Assert.Contains(buttons, b => b.CallbackData == $"join_session:{firstSessionId}");
Assert.Contains(buttons, b => b.CallbackData == $"leave_session:{firstSessionId}");
Assert.Contains(buttons, b => b.CallbackData == $"join_session:{secondSessionId}");
Assert.Contains(buttons, b => b.CallbackData == $"leave_session:{secondSessionId}");
Assert.DoesNotContain(buttons, b => b.CallbackData?.StartsWith("cancel") == true);
Assert.DoesNotContain(buttons, b => b.CallbackData?.StartsWith("reschedule") == true);
}
[Fact]
public void Render_ShouldSkipButtonsForCancelledSessions()
{
var cancelledSessionId = Guid.NewGuid();
var sessions = new[] { new SessionBatchDto(cancelledSessionId, DateTime.UtcNow, SessionStatus.Cancelled, null, "") };
var participants = Array.Empty<ParticipantBatchDto>();
var view = SessionBatchViewBuilder.Build("Test", sessions, participants);
var (_, markup) = TelegramSessionBatchRenderer.Render(view);
Assert.Empty(markup.InlineKeyboard);
}
[Fact]
public void Render_ShouldShowWaitlistButtonWhenFull()
{
var sessionId = Guid.NewGuid();
var sessions = new[] { new SessionBatchDto(sessionId, DateTime.UtcNow, SessionStatus.Planned, 1, "https://example.com/game") };
var participants = new[] { new ParticipantBatchDto(sessionId, "Alice", "alice", ParticipantRegistrationStatus.Active) };
var view = SessionBatchViewBuilder.Build("Test", sessions, participants);
var (_, markup) = TelegramSessionBatchRenderer.Render(view);
var buttons = markup.InlineKeyboard.SelectMany(row => row).ToList();
var joinButton = buttons.First(b => b.CallbackData?.StartsWith("join_session:") == true);
Assert.Contains("ожидания", joinButton.Text);
}
[Fact]
public void Render_ShouldHandleEmptySessions()
{
var view = SessionBatchViewBuilder.Build("Empty", Array.Empty<SessionBatchDto>(), Array.Empty<ParticipantBatchDto>());
var (text, markup) = TelegramSessionBatchRenderer.Render(view);
Assert.Contains("Empty", text);
Assert.DoesNotContain("📅", text);
Assert.Empty(markup.InlineKeyboard);
}
[Fact]
public void Render_ShouldEncodeHtmlInTitle()
{
var sessionId = Guid.NewGuid();
var sessions = new[] { new SessionBatchDto(sessionId, DateTime.UtcNow, SessionStatus.Planned, 4, "") };
var participants = Array.Empty<ParticipantBatchDto>();
var view = SessionBatchViewBuilder.Build("<script>alert(1)</script>", sessions, participants);
var (text, _) = TelegramSessionBatchRenderer.Render(view);
Assert.Contains("&lt;script&gt;alert(1)&lt;/script&gt;", text);
Assert.DoesNotContain("<script>", text);
}
[Fact]
public void Render_ShouldShowConfirmedStatusButtons()
{
var sessionId = Guid.NewGuid();
var sessions = new[] { new SessionBatchDto(sessionId, DateTime.UtcNow, SessionStatus.Confirmed, 4, "") };
var participants = Array.Empty<ParticipantBatchDto>();
var view = SessionBatchViewBuilder.Build("Test", sessions, participants);
var (_, markup) = TelegramSessionBatchRenderer.Render(view);
var buttons = markup.InlineKeyboard.SelectMany(row => row).ToList();
Assert.Equal(2, buttons.Count);
Assert.Contains(buttons, b => b.CallbackData == $"join_session:{sessionId}");
Assert.Contains(buttons, b => b.CallbackData == $"leave_session:{sessionId}");
}
[Fact]
public void Render_ShouldHandleNoJoinLink()
{
var sessionId = Guid.NewGuid();
var sessions = new[] { new SessionBatchDto(sessionId, DateTime.UtcNow, SessionStatus.Planned, 4, "") };
var participants = Array.Empty<ParticipantBatchDto>();
var view = SessionBatchViewBuilder.Build("Test", sessions, participants);
var (text, markup) = TelegramSessionBatchRenderer.Render(view);
var buttons = markup.InlineKeyboard.SelectMany(row => row).ToList();
Assert.DoesNotContain("Ссылка на игру", text);
Assert.Contains("📅", text);
Assert.Equal(2, buttons.Count);
}
[Fact]
public void Render_ShouldEncodeHtmlInJoinLink()
{
var sessionId = Guid.NewGuid();
var sessions = new[] { new SessionBatchDto(sessionId, DateTime.UtcNow, SessionStatus.Planned, 4, "https://example.com/test?a=1&b=2") };
var participants = Array.Empty<ParticipantBatchDto>();
var view = SessionBatchViewBuilder.Build("Test", sessions, participants);
var (text, _) = TelegramSessionBatchRenderer.Render(view);
Assert.Contains("a=1&amp;b=2", text);
Assert.DoesNotContain("a=1&b=2" + "\"", text); // make sure & is encoded
}
}