Skip to content

Commit 5a0988f

Browse files
committed
test(mfa): drop transition coverage and inline the walked-state guard
The transition suite mostly guarded the path generator against itself, at snapshot granularity that multiplies with every context field, so it goes away together with its private transitionCoverage module. The cheap guard that every settleable state occurs in a UI-walked path stays, moved next to the walk it covers, because everyStateReachable checks the unfiltered graph and testConfig only proves an assertion exists, not that it ever runs.
1 parent bba73b6 commit 5a0988f

4 files changed

Lines changed: 17 additions & 99 deletions

File tree

tests/unit/components/MultifactorAuthentication/machine/graphTraversal/coverageStaysComplete.test.ts

Lines changed: 0 additions & 33 deletions
This file was deleted.

tests/unit/components/MultifactorAuthentication/machine/graphTraversal/viewMatchesMachine.test.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import SCREENS from '@src/SCREENS';
1717
// navigator, drives each machine event as a real gesture, and asserts the UI markers of the reached
1818
// state at every step of every generated path. A state or event added to the machine appears in the
1919
// walked paths automatically, and the type checks and guard suites then demand the hand-written
20-
// pieces it needs, such as an executor or a UI assertion. The machine-only suites
21-
// live in `everyStateReachable.test.ts` and the coverage guards in `coverageStaysComplete.test.ts`.
20+
// pieces it needs, such as an executor or a UI assertion. The machine-only suites live in
21+
// `everyStateReachable.test.ts`, and the guard suites below check that the walk and `testConfig` stay complete.
2222

2323
// This mock forces a wide layout so the navigator renders the backdrop used as the mounted marker.
2424
jest.mock('@hooks/useResponsiveLayout');
@@ -141,6 +141,18 @@ describe('the real MFA modal matches the machine at every step of every generate
141141
}
142142
});
143143

144+
// Every settleable leaf must occur in a path that the walk above drives. `everyStateReachable.test.ts`
145+
// checks the unfiltered graph, so only this guard catches a state whose every route needs a step the
146+
// walk cannot drive, such as a delayed transition. Paths removed as prefixes of longer paths do not
147+
// reduce state coverage because `path.test` asserts every step.
148+
describe('every settleable MFA state is reached by the UI walk', () => {
149+
const walkedStateValues = walkedPaths.flatMap((path) => path.steps.map((step) => step.state.value));
150+
151+
it.each(getSettleableLeafStates(mfaMachine.root))('$description is reached through the real UI', ({description}) => {
152+
expect(walkedStateValues.some((reached) => matchesState(description, reached))).toBe(true);
153+
});
154+
});
155+
144156
// TestModel runs only the state assertions whose keys match the reached state, so if no key matches a
145157
// state, the test passes without checking it. These guards fail in that case.
146158
//

tests/utils/mfa/flowPaths.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type {SnapshotFrom} from 'xstate';
22
import {matchesState} from 'xstate';
3-
import type {StatePath} from 'xstate/graph';
43
import {getShortestPaths, TestModel} from 'xstate/graph';
54
import mfaMachine from '@components/MultifactorAuthentication/machine/mfaMachine';
65
import type {MfaEvent} from '@components/MultifactorAuthentication/machine/types';
@@ -65,7 +64,6 @@ function hasMfaEventFixtures(type: string): type is MfaEvent['type'] {
6564
const DELAYED_EVENT_PREFIX = 'xstate.after';
6665

6766
type MfaSnapshot = SnapshotFrom<typeof mfaMachine>;
68-
type MfaStatePath = StatePath<MfaSnapshot, MfaEvent>;
6967

7068
/**
7169
* A path is UI-drivable when the walk can produce every step. A delayed transition would need real
@@ -119,8 +117,8 @@ function getDrivingJourneyPaths() {
119117
* Returns the generated coverage paths plus the explicit driving journeys. The journeys are needed
120118
* because a shortest path can be empty, such as the path to the initial `closed` state, so the
121119
* generated paths alone would never drive the teardown. Paths with a delayed step are filtered out
122-
* because the walk cannot drive a timer, and the reachability guards catch a state that loses every
123-
* drivable route.
120+
* because the walk cannot drive a timer, and the walk-coverage guard in `viewMatchesMachine.test.tsx`
121+
* catches a state that loses every drivable route.
124122
*
125123
* `path.test` skips a step whose event has no executor, which keeps framework steps such as
126124
* `xstate.init` harmless while the executor table still forces an executor for every application event.
@@ -132,5 +130,4 @@ function getWalkedPaths() {
132130
}
133131

134132
export default getWalkedPaths;
135-
export {DELAYED_EVENT_PREFIX, getDrivingJourneyPaths, getMfaShortestPaths, getTraversalEvents};
136-
export type {MfaStatePath};
133+
export {getDrivingJourneyPaths, getMfaShortestPaths};

tests/utils/mfa/transitionCoverage.ts

Lines changed: 0 additions & 58 deletions
This file was deleted.

0 commit comments

Comments
 (0)