15040eb954
In the session creation wizard (Telegram + Discord), the Capacity step only exposed waitlist on/off buttons. The 'no waitlist' button silently advanced to the next step without setting MaxPlayers, so users who tried to create a session with no player cap were blocked with 'Не заполнены поля: лимит мест'. The DB contract and CreateSessionCommand already supported null MaxPlayers (int?, ck_sessions_max_players check in V006), and the web form already exposes 'Без лимита' as an empty InputNumber — only the wizard flow was broken. Changes: - Add '♾ Без лимита' choice button to Capacity in shared WizardStepViewBuilder.BuildCapacity (Telegram) and to RenderCapacity / RenderPoolSlotCapacity in DiscordWizardStep (Discord). - Add 'no_limit' branch to GameCreationWizard.ApplyCapacityChoice that sets MaxPlayers to null and advances to Visibility. - Change GameCreationWizard.SetMaxPlayers signature from int to int? so the 'no limit' branch compiles. - Change CreateSessionCommand builder in both Telegram and Discord submitters to take int? maxPlayers and drop the '?? 0' that would have turned null into 0 (violating the DB CHECK and the 'no limit' contract). - In Discord BuildConfirmDescription, render '👥 Без лимита, waitlist вкл/выкл' when MaxPlayers is null (the previous code silently omitted the line). - Expose BuildCommand as internal in both submitters and add InternalsVisibleTo('GmRelay.Bot.Tests') to the DiscordBot assembly for unit-test access. Tests (9 new): - WizardStepRenderTests.CapacityStep_HasWaitlistButtons — asserts the 'Без лимита' button is present. - GameCreationWizardStepTransitionsTests.NoLimitCapacityButton_… — asserts the choice advances to Visibility and leaves MaxPlayers null in the JSON draft. - GameCreationWizardStepTransitionsTests.ChoiceCallback_AdvancesToExpectedStep — new Theory row for Capacity/no_limit. - CreateSessionHandlerBuildCommandTests (new) — null/value propagation through the Telegram submitter's BuildCommand. - DiscordWizardStepCapacityRenderTests (new) — 'Без лимита' button is rendered for both Capacity and PoolSlotCapacity, with the expected custom-id shape. - DiscordWizardSubmitterBuildCommandTests (new) — null/value propagation through the Discord submitter's BuildCommand. Closes #123
65 lines
2.5 KiB
C#
65 lines
2.5 KiB
C#
using GmRelay.DiscordBot.Features.Sessions.Wizard;
|
|
using GmRelay.Shared.Features.Sessions.CreateSession.Wizard;
|
|
using NetCord.Rest;
|
|
using Xunit;
|
|
|
|
namespace GmRelay.Bot.Tests.Discord.Wizard;
|
|
|
|
/// <summary>
|
|
/// Renderer tests for the Discord wizard's Capacity / PoolSlotCapacity steps.
|
|
/// Locks in the presence of the "♾ Без лимита" button so the user can pick
|
|
/// a session with no player cap (null in <c>sessions.max_players</c>), the
|
|
/// same affordance the Telegram wizard provides.
|
|
/// </summary>
|
|
public sealed class DiscordWizardStepCapacityRenderTests
|
|
{
|
|
[Fact]
|
|
public void RenderCapacity_ContainsNoLimitButton()
|
|
{
|
|
var draft = new WizardDraft { Step = WizardStepNames.Capacity };
|
|
var render = DiscordWizardStep.Render(draft, new WizardPayload());
|
|
|
|
var labels = ExtractButtonLabels(render);
|
|
Assert.Contains(labels, l => l.Contains("Без лимита", System.StringComparison.Ordinal));
|
|
}
|
|
|
|
[Fact]
|
|
public void RenderPoolSlotCapacity_ContainsNoLimitButton()
|
|
{
|
|
var draft = new WizardDraft { Step = WizardStepNames.PoolSlotCapacity };
|
|
var render = DiscordWizardStep.Render(draft, new WizardPayload());
|
|
|
|
var labels = ExtractButtonLabels(render);
|
|
Assert.Contains(labels, l => l.Contains("Без лимита", System.StringComparison.Ordinal));
|
|
}
|
|
|
|
[Fact]
|
|
public void RenderCapacity_NoLimitButton_HasChoiceCustomIdForNoLimit()
|
|
{
|
|
var draft = new WizardDraft { Step = WizardStepNames.Capacity };
|
|
var render = DiscordWizardStep.Render(draft, new WizardPayload());
|
|
|
|
var buttons = ExtractButtons(render);
|
|
var noLimit = buttons.SingleOrDefault(b => b.Label?.Contains("Без лимита", System.StringComparison.Ordinal) == true);
|
|
Assert.NotNull(noLimit);
|
|
Assert.StartsWith("wizard:btn:choice:Capacity:no_limit", noLimit!.CustomId);
|
|
}
|
|
|
|
private static System.Collections.Generic.List<string> ExtractButtonLabels(
|
|
DiscordWizardStep.DiscordWizardRender render) =>
|
|
render.Components
|
|
.OfType<ActionRowProperties>()
|
|
.SelectMany(r => r.Components)
|
|
.OfType<ButtonProperties>()
|
|
.Select(b => b.Label ?? string.Empty)
|
|
.ToList();
|
|
|
|
private static System.Collections.Generic.List<ButtonProperties> ExtractButtons(
|
|
DiscordWizardStep.DiscordWizardRender render) =>
|
|
render.Components
|
|
.OfType<ActionRowProperties>()
|
|
.SelectMany(r => r.Components)
|
|
.OfType<ButtonProperties>()
|
|
.ToList();
|
|
}
|