logo SERENITY
Game Systems Foundation
Search Results for

    Show / Hide Table of Contents

    Class SerenityStepWizardWindowTests

    Tests for SerenityStepWizardWindow<TStep> — the descriptor-driven scaffolding that replaced every stepped wizard's hand-rolled header/breadcrumb/body/footer/error-gate quintet. Driven entirely through the base's public and protected seams on Serenity.UnityGlobal.Tests.Editor.SerenityStepWizardTestWindow: no OnGUI pass, so these assert the navigation, visibility and gating rules rather than IMGUI layout — except where a doc block below says otherwise. The frame-ordering tests that need a real repaint drive one through EditorWindow.SendEvent, skipping themselves when a headless run has no graphics device to deliver it. RunFrame_OnAFreshScratchWindow_DoesNotThrowOnItsFirstFrame(), RunFrame_MutatingAShowingRowsTitle_ReProjectsOnTheNextFrame() and TogglingTheHiddenRule_ReProjectsOnTheNextFrameWithoutMovingTheReader() instead drive the non-drawing PrepareFrame preamble directly — they must run headless, since a headless run is exactly where the first one's regression was found — and need no console-error suppression, since PrepareFrame makes no GUILayout/EditorGUILayout call.

    Inheritance
    object
    SerenityStepWizardWindowTests
    Inherited Members
    object.ToString()
    object.Equals(object)
    object.Equals(object, object)
    object.ReferenceEquals(object, object)
    object.GetHashCode()
    object.GetType()
    object.MemberwiseClone()
    Namespace: Serenity.UnityGlobal.Tests.Editor
    Assembly: Tests.Editor.dll
    Syntax
    public class SerenityStepWizardWindowTests

    Constructors

    SerenityStepWizardWindowTests()

    Declaration
    public SerenityStepWizardWindowTests()

    Methods

    BuildSteps_PutsTheWizardOnItsFirstStep()

    Declaration
    public void BuildSteps_PutsTheWizardOnItsFirstStep()

    CreateWindow()

    Declaration
    public void CreateWindow()

    DestroyWindow()

    Declaration
    public void DestroyWindow()

    DrawFooter_SkipsTheFooterRowWhenTheDescriptorHidesIt()

    Drives a real repaint the same way OnBeforeDrawStep_RunsBeforeTheCurrentStepsDraw() does, landed on the trailing NoFooter step, whose descriptor sets ShowsFooter = false. NoFooter is both current and last in the table, so the breadcrumb's forward-jump gate — which only asks about steps ahead of the current one — never reads its error either; that leaves the footer's own CurrentStepError() call as the only possible reader. A zero invocation count proves DrawFooter skipped that read, and therefore the whole footer row, without touching pixels.

    Declaration
    public void DrawFooter_SkipsTheFooterRowWhenTheDescriptorHidesIt()

    ErrorGate_AllowsGoingBackFromAnErroredStep()

    Declaration
    public void ErrorGate_AllowsGoingBackFromAnErroredStep()

    ErrorGate_BlocksAForwardJumpPastAnErroredStep()

    Declaration
    public void ErrorGate_BlocksAForwardJumpPastAnErroredStep()

    ErrorGate_ReportsTheCurrentStepsOwnError()

    Declaration
    public void ErrorGate_ReportsTheCurrentStepsOwnError()

    FinishWithAsset_LandsOnTheDoneStepEvenWhileAnEarlierStepReportsAnError()

    Declaration
    public void FinishWithAsset_LandsOnTheDoneStepEvenWhileAnEarlierStepReportsAnError()

    FinishWithAsset_SilencesTheStepErrorTheWriteItselfWouldReport()

    Declaration
    public void FinishWithAsset_SilencesTheStepErrorTheWriteItselfWouldReport()

    GoTo_AStepTheTableDoesNotHold_Throws()

    Declaration
    public void GoTo_AStepTheTableDoesNotHold_Throws()

    GoTo_AimedAtAHiddenRowThatResolvesToTheCurrentStep_RunsNeitherHook()

    Regression: the RAW target of a jump can be a hidden row that SerenityStepWizardProjection<TStep>.NearestVisibleProjectedIndex resolves right back to the step already showing — here, hiding Rig (table index 1) while standing on Installation (table index 2) makes a jump aimed at Rig resolve to Installation itself. The move must be judged against that RESOLVED landing, not the raw target, or OnLeave/OnEnter fire on a move that never actually moved anywhere.

    Declaration
    public void GoTo_AimedAtAHiddenRowThatResolvesToTheCurrentStep_RunsNeitherHook()

    GoTo_FiresTheLandedOnStepsOnEnter()

    Declaration
    public void GoTo_FiresTheLandedOnStepsOnEnter()

    GoTo_PastAHiddenStep_LandsOnTheStepItWasAimedAt()

    Declaration
    public void GoTo_PastAHiddenStep_LandsOnTheStepItWasAimedAt()

    GoTo_TheStepAlreadyShowing_DoesNotFireOnEnterAgain()

    Declaration
    public void GoTo_TheStepAlreadyShowing_DoesNotFireOnEnterAgain()

    GoTo_ToTheCurrentStep_DoesNotResetTheBodyScroll()

    Same fix, observed on the controller side: GoTo aimed at the step already showing must not reach SerenityWizardStepController.MoveToIgnoringGate at all, so an in-progress body scroll survives the no-op call instead of being reset to UnityEngine.Vector2.zero.

    Declaration
    public void GoTo_ToTheCurrentStep_DoesNotResetTheBodyScroll()

    GoTo_Ungated_MovesPastTheCurrentStepsError_AndFiresBothHooks()

    Regression coverage for GoTo(TStep, bool)'s ungated shape — the seam an in-body navigation control (a mode card, a "skip to" link) reaches for when it must move even while the step on screen is errored, unlike every footer/breadcrumb move, which stays gated.

    Declaration
    public void GoTo_Ungated_MovesPastTheCurrentStepsError_AndFiresBothHooks()

    HiddenStep_ErrorIsNeitherRunNorConsultedByTheForwardGate()

    Declaration
    public void HiddenStep_ErrorIsNeitherRunNorConsultedByTheForwardGate()

    HiddenStep_IsAbsentFromTheBreadcrumbTitlesAndTheStepCount()

    Declaration
    public void HiddenStep_IsAbsentFromTheBreadcrumbTitlesAndTheStepCount()

    HiddenStep_IsNotSomethingGoToCanLandOn()

    Declaration
    public void HiddenStep_IsNotSomethingGoToCanLandOn()

    OnBeforeDrawStep_RunsBeforeTheCurrentStepsDraw()

    Drives a real repaint through EditorWindow.SendEvent — the technique LeaderboardTestDataTableResizeTests.OpenWindow uses to exercise real OnGUI behavior — because OnBeforeDrawStep's ordering guarantee only exists while the frame actually runs; every other test in this class deliberately avoids that. Uses its own window rather than the shared Serenity.UnityGlobal.Tests.Editor.SerenityStepWizardWindowTests._window so every other test keeps running with no OnGUI pass.

    Declaration
    public void OnBeforeDrawStep_RunsBeforeTheCurrentStepsDraw()

    OnLeave_FiresOnTheStepBeingLeftBeforeTheTargetsOnEnter()

    Hook ordering on the one method every way out of a step funnels through: the footer's Next (ApplyFooterAction), a breadcrumb jump (DrawHeader) and GoTo all call GoToTableIndex, so asserting the order here asserts it for all three.

    Declaration
    public void OnLeave_FiresOnTheStepBeingLeftBeforeTheTargetsOnEnter()

    OnLeave_HidingARowOnItsWayOut_StillLandsOnTheStepAimedAt()

    Declaration
    public void OnLeave_HidingARowOnItsWayOut_StillLandsOnTheStepAimedAt()

    OnLeave_OnAJumpTheGateRefuses_DoesNotFire()

    Declaration
    public void OnLeave_OnAJumpTheGateRefuses_DoesNotFire()

    OnLeave_OnAMoveThatStaysOnTheSameStep_DoesNotFire()

    Declaration
    public void OnLeave_OnAMoveThatStaysOnTheSameStep_DoesNotFire()

    PingAndGoTo_FiresOnEnterOfTheTarget()

    Declaration
    public void PingAndGoTo_FiresOnEnterOfTheTarget()

    PingAndGoTo_Gated_RefusedByAnErroredSourceStep_KeepsTheCursor()

    Declaration
    public void PingAndGoTo_Gated_RefusedByAnErroredSourceStep_KeepsTheCursor()

    PingAndGoTo_Gated_WithNoError_MovesToTheTarget()

    Declaration
    public void PingAndGoTo_Gated_WithNoError_MovesToTheTarget()

    PingAndGoTo_MovesUngatedPastAnErroredStep_WithoutLatchingTerminal()

    Declaration
    public void PingAndGoTo_MovesUngatedPastAnErroredStep_WithoutLatchingTerminal()

    PingCreatedAssetOnly_DoesNotMoveTheCursorNorRunAnyHook()

    The fourth finishing shape: ServiceExtensionCreatorWindow and CreateThemeWindow both ping the asset they just wrote and stay exactly where the reader already is — no GoTo at all, unlike every other finishing shape. Proven the same way GoTo_ToTheCurrentStep_DoesNotResetTheBodyScroll() proves a same-step move never reaches the controller: the scroll survives and no hook fires.

    Declaration
    public void PingCreatedAssetOnly_DoesNotMoveTheCursorNorRunAnyHook()

    PrimaryAction_ShowsOnlyOnTheStepThatDeclaresIt()

    Declaration
    public void PrimaryAction_ShowsOnlyOnTheStepThatDeclaresIt()

    ResetForAnotherRun_ClearsTerminalStateAndRestoresTheGate()

    Declaration
    public void ResetForAnotherRun_ClearsTerminalStateAndRestoresTheGate()

    ResetForAnotherRun_FiresTheLandedOnStepsOnEnter()

    Declaration
    public void ResetForAnotherRun_FiresTheLandedOnStepsOnEnter()

    ResetForAnotherRun_FiresTheLeftStepsOnLeave()

    Declaration
    public void ResetForAnotherRun_FiresTheLeftStepsOnLeave()

    ResetForAnotherRun_OnTheStepAlreadyShowing_StillClearsTerminal()

    The carve-out MoveCursor's alwaysApplyMove exists for: here the reset target (Done) IS the step already showing after FinishWithAsset landed there, so the resolved landing equals the source and the general same-step no-op would skip the controller move entirely — except ResetForAnotherRun must still reach it to clear IsTerminal, restart or not.

    Declaration
    public void ResetForAnotherRun_OnTheStepAlreadyShowing_StillClearsTerminal()

    RunFrame_MutatingAShowingRowsTitle_ReProjectsOnTheNextFrame()

    The projection's other change-detection trigger, alongside the visible-set change TogglingTheHiddenRule_ReProjectsOnTheNextFrameWithoutMovingTheReader() covers: a row that stays showing but renames itself must not leave the breadcrumb repeating a stale title forever — the old comparison only looked at which table indices were showing, so a title-only edit was invisible to it. Drives the non-drawing PrepareFrame preamble for the same reason that test does, and asserts no hook fires either, since a rename is the table re-describing itself, not navigation.

    Declaration
    public void RunFrame_MutatingAShowingRowsTitle_ReProjectsOnTheNextFrame()

    RunFrame_OnAFreshScratchWindow_DoesNotThrowOnItsFirstFrame()

    Regression for the defect where RunFrame cleared the step-error cache before anything had forced the step table to build, so a scratch window's first frame NullReferenceExceptiond on Array.Clear whenever OnBeforeDrawStep did not itself touch the table. Drives the non-drawing PrepareFrame preamble directly rather than through a real repaint — unlike OnBeforeDrawStep_RunsBeforeTheCurrentStepsDraw(), this must not be skippable on a headless run, since a headless run is exactly where this defect was found, and unlike the full drawing RunFrame, PrepareFrame makes no GUILayout call a headless window has no layout context to answer.

    Declaration
    public void RunFrame_OnAFreshScratchWindow_DoesNotThrowOnItsFirstFrame()

    ShowsFooterThisFrame_False_SuppressesTheFooterOnEveryStepRegardlessOfItsOwnShowsFooter()

    Regression coverage for the window-level footer seam CreateEventWindow needs: its two-phase compile handoff has to blank the footer on EVERY step while a pending phase waits on a domain reload, which no single row's static ShowsFooter can express. Drives the composition directly (Serenity.UnityGlobal.Tests.Editor.SerenityStepWizardTestWindow.ShouldDrawFooterForTests(Serenity.UnityGlobal.Tests.Editor.SerenityStepWizardTestStep)) rather than through a real repaint, since ShowsFooterThisFrame is a pure per-call predicate with nothing IMGUI-specific to exercise.

    Declaration
    public void ShowsFooterThisFrame_False_SuppressesTheFooterOnEveryStepRegardlessOfItsOwnShowsFooter()

    ShowsFooterThisFrame_True_LeavesEachStepsOwnShowsFooterInControl()

    Declaration
    public void ShowsFooterThisFrame_True_LeavesEachStepsOwnShowsFooterInControl()

    ShowsFooter_HidesOnlyOnTheStepThatDeclaresIt()

    Declaration
    public void ShowsFooter_HidesOnlyOnTheStepThatDeclaresIt()

    SkipTooltipProvider_Null_FallsBackToTheStaticSkipTooltip()

    Declaration
    public void SkipTooltipProvider_Null_FallsBackToTheStaticSkipTooltip()

    SkipTooltipProvider_WinsOverTheStaticSkipTooltip_AndIsReReadOnEachCall()

    Regression coverage for the seam ServiceExtensionCreatorWindow needs: its skip tooltip names the currently selected kind ("Nothing to configure for {kind}"), which a plain SkipTooltip string set once when the table was built cannot express. The Rig step's static SkipTooltip stays set alongside its provider, so this proves the provider is actually preferred rather than the row simply having nothing else to fall back to.

    Declaration
    public void SkipTooltipProvider_WinsOverTheStaticSkipTooltip_AndIsReReadOnEachCall()

    SkippedStep_NeverBlocksAForwardJumpPastIt()

    Declaration
    public void SkippedStep_NeverBlocksAForwardJumpPastIt()

    SkippedStep_ReportsItsSkipTooltipToTheBreadcrumb()

    Declaration
    public void SkippedStep_ReportsItsSkipTooltipToTheBreadcrumb()

    StepErrorAt_OnAFreshWindowWithNoFrameRunYet_DoesNotThrow()

    Declaration
    public void StepErrorAt_OnAFreshWindowWithNoFrameRunYet_DoesNotThrow()

    StepErrorAt_RunsTheDescriptorsErrorAtMostOncePerRepaint()

    Proves the per-frame Error cache: within one repaint, the breadcrumb consults the Identity step's forward-jump gate once for every later step's button and the footer consults CurrentStepError for the step itself — three readers of the same descriptor row. Without a cache that is WizardStepDescriptor<TStep>.Error invoked three times a repaint; with it, once. Drives a real repaint the same way OnBeforeDrawStep_RunsBeforeTheCurrentStepsDraw() does, because the cache lives inside RunFrame, which only runs from a real OnGUI dispatch.

    Declaration
    public void StepErrorAt_RunsTheDescriptorsErrorAtMostOncePerRepaint()

    TogglingTheHiddenRule_ReProjectsOnTheNextFrameWithoutMovingTheReader()

    The re-projection contract, driven through the non-drawing PrepareFrame preamble because that is where a hidden rule is re-read: hiding the row ABOVE the reader shortens the list and moves every later step's position down by one, and the reader must still be on the step they were reading rather than on whatever inherited its index. Needs no console-error suppression, since PrepareFrame makes no GUILayout call — see RunFrame_OnAFreshScratchWindow_DoesNotThrowOnItsFirstFrame().

    Declaration
    public void TogglingTheHiddenRule_ReProjectsOnTheNextFrameWithoutMovingTheReader()

    UnskippedStep_ReportsNoBreadcrumbTooltip()

    Declaration
    public void UnskippedStep_ReportsNoBreadcrumbTooltip()
    In this article
    © 2026 Serenity. All Rights Reserved