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.
Inherited Members
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()