test(wizard): add submit, cleanup, router delegation tests
This commit is contained in:
+119
@@ -0,0 +1,119 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GmRelay.Bot.Features.Sessions.CreateSession.Wizard;
|
||||
using GmRelay.Bot.Infrastructure.Telegram;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using NSubstitute;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Types;
|
||||
using static GmRelay.Bot.Tests.Features.Sessions.CreateSession.Wizard.WizardTestFakes;
|
||||
|
||||
namespace GmRelay.Bot.Tests.Features.Sessions.CreateSession.Wizard;
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the <see cref="UpdateRouter"/> delegates to the wizard when
|
||||
/// the GM has an active (non-expired) draft, and falls through to normal
|
||||
/// handling when no draft is active. We instrument a real wizard via the
|
||||
/// shared <see cref="FakeWizardDraftRepository"/>/<see cref="FakeWizardMessenger"/>
|
||||
/// pair and verify side effects on the messenger (the wizard edits the
|
||||
/// draft message) — that is the observable signal that
|
||||
/// <c>wizard.HandleUpdateAsync</c> was called.
|
||||
/// </summary>
|
||||
public sealed class UpdateRouterDelegationTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task ActiveDraft_Existing_RoutesToWizard()
|
||||
{
|
||||
var sut = BuildRouter(out var drafts, out var messenger);
|
||||
|
||||
var draft = NewDraft(WizardStepNames.Title);
|
||||
drafts.Seed(draft);
|
||||
|
||||
var update = TextUpdate("Curse of Strahd", ownerId: draft.OwnerTelegramId);
|
||||
|
||||
await sut.RouteAsync(update, CancellationToken.None);
|
||||
|
||||
// Wizard edits the draft message when it processes a title.
|
||||
Assert.NotEmpty(messenger.Edits);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ActiveDraft_Existing_OnCallback_AlsoRoutesToWizard()
|
||||
{
|
||||
var sut = BuildRouter(out var drafts, out _);
|
||||
|
||||
var draft = NewDraft(WizardStepNames.Title);
|
||||
drafts.Seed(draft);
|
||||
|
||||
// "wizard:cancel" — wizard owns the cancel callback. The router
|
||||
// delegates control-callbacks (resume/reset) but lets the wizard
|
||||
// handle wizard:* callbacks.
|
||||
var update = CallbackUpdate(WizardCallbackData.Cancel(), ownerId: draft.OwnerTelegramId);
|
||||
|
||||
await sut.RouteAsync(update, CancellationToken.None);
|
||||
|
||||
// Cancel deletes the draft via the wizard.
|
||||
Assert.Contains(draft.Id, drafts.DeletedIds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NoActiveDraft_FallsThrough()
|
||||
{
|
||||
var sut = BuildRouter(out _, out var messenger);
|
||||
|
||||
// No active draft → router should NOT call the wizard. It will
|
||||
// attempt to run the /help command via the fallback command path.
|
||||
// We send a /help message; the router has no draft to act on.
|
||||
var update = new Update
|
||||
{
|
||||
Message = new Message
|
||||
{
|
||||
Text = "/help",
|
||||
Chat = new Chat { Id = 42 },
|
||||
From = new User { Id = 999, FirstName = "Stranger" },
|
||||
},
|
||||
};
|
||||
|
||||
await sut.RouteAsync(update, CancellationToken.None);
|
||||
|
||||
// The wizard should not have edited anything (no draft was active).
|
||||
Assert.Empty(messenger.Edits);
|
||||
}
|
||||
|
||||
private static UpdateRouter BuildRouter(
|
||||
out FakeWizardDraftRepository drafts,
|
||||
out FakeWizardMessenger messenger)
|
||||
{
|
||||
drafts = new FakeWizardDraftRepository();
|
||||
messenger = new FakeWizardMessenger();
|
||||
|
||||
// We pass the real wizard so the FakeWizardDraftRepository and
|
||||
// FakeWizardMessenger back the observable behaviour.
|
||||
var wizard = new GameCreationWizard(drafts, messenger, NullLogger<GameCreationWizard>.Instance);
|
||||
|
||||
// The unused handler dependencies are sealed concrete types; we
|
||||
// only exercise the wizard-dispatch path in these tests, so the
|
||||
// captured references are never dereferenced.
|
||||
var router = new UpdateRouter(
|
||||
rsvpHandler: null!,
|
||||
createSessionHandler: null!,
|
||||
joinSessionHandler: null!,
|
||||
leaveSessionHandler: null!,
|
||||
promoteWaitlistedPlayerHandler: null!,
|
||||
cancelSessionHandler: null!,
|
||||
deleteSessionHandler: null!,
|
||||
listSessionsHandler: null!,
|
||||
exportCalendarHandler: null!,
|
||||
initiateRescheduleHandler: null!,
|
||||
rescheduleTimeInputHandler: null!,
|
||||
rescheduleVoteHandler: null!,
|
||||
wizard: wizard,
|
||||
drafts: drafts,
|
||||
bot: Substitute.For<ITelegramBotClient>(),
|
||||
configuration: Substitute.For<IConfiguration>(),
|
||||
logger: NullLogger<UpdateRouter>.Instance);
|
||||
|
||||
return router;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user