1- import { act , renderHook } from '@testing-library/react' ;
1+ import { renderHook } from '@testing-library/react' ;
22import { beforeEach , describe , expect , it , vi } from 'vitest' ;
33
44// The umbrella hook composes several `@clerk/shared/react` hooks. We mock the
55// whole module so the test drives exactly what the source query and the
66// underlying test-runs query report, and can assert how the umbrella gates the
77// test-runs query's `enabled` and folds its loading into the global gate.
88
9+ // A connection shaped enough for the umbrella's gating: the derived
10+ // "configured" predicate reads `samlConnection.idpSsoUrl` + `idpEntityId`, and
11+ // the active path reads `active`.
12+ type MockConnection = {
13+ id : string ;
14+ active ?: boolean ;
15+ samlConnection ?: { idpSsoUrl ?: string ; idpEntityId ?: string } | null ;
16+ } ;
17+
18+ const configuredConnection = ( id : string ) : MockConnection => ( {
19+ id,
20+ samlConnection : { idpSsoUrl : 'https://idp.example.com/sso' , idpEntityId : 'https://idp.example.com/entity' } ,
21+ } ) ;
22+
23+ const unconfiguredConnection = ( id : string ) : MockConnection => ( { id, samlConnection : null } ) ;
24+
925// Mutable state the connection-source mock reads from, so a test can flip from
1026// "no connection at load" to "connection created mid-flow" between renders.
1127const connectionsState = vi . hoisted ( ( ) => ( {
12- data : [ ] as Array < { id : string } > ,
28+ data : [ ] as MockConnection [ ] ,
1329 isLoading : false ,
1430} ) ) ;
1531
@@ -63,21 +79,30 @@ beforeEach(() => {
6379const lastTwoCalls = ( ) => testRunsState . calls . slice ( - 2 ) ;
6480
6581describe ( 'useOrganizationEnterpriseConnection — test-runs gating' , ( ) => {
66- it ( '(a) existing connection at load → test-runs active and contribute to the global isLoading' , ( ) => {
67- connectionsState . data = [ { id : 'ent_1' } ] ;
82+ it ( '(a) existing configured connection at load → test-runs active and contribute to the global isLoading' , ( ) => {
83+ connectionsState . data = [ configuredConnection ( 'ent_1' ) ] ;
6884 testRunsState . isLoading = true ;
6985
7086 const { result } = renderHook ( ( ) => useOrganizationEnterpriseConnection ( ) ) ;
7187
72- // Both underlying queries (probe + list) are enabled from the first render.
88+ // A configured connection existed at load → both underlying queries (probe +
89+ // list) are enabled from the first render.
7390 expect ( lastTwoCalls ( ) ) . toEqual ( [ { enabled : true } , { enabled : true } ] ) ;
74- // A connection existed at load, so the cold test-runs load gates the full
75- // skeleton.
91+ // …so the cold test-runs load gates the full skeleton (hadInitialConnection).
7692 expect ( result . current . isLoading ) . toBe ( true ) ;
7793 expect ( result . current . testRuns . isLoading ) . toBe ( true ) ;
7894 } ) ;
7995
80- it ( '(b) no connection at load → test-runs inactive after a mid-flow create, and never gate the global skeleton' , ( ) => {
96+ it ( '(a2) active (but unconfigured) connection at load → test-runs active via the isActive path' , ( ) => {
97+ connectionsState . data = [ { id : 'ent_active' , active : true , samlConnection : null } ] ;
98+
99+ const { result } = renderHook ( ( ) => useOrganizationEnterpriseConnection ( ) ) ;
100+
101+ expect ( lastTwoCalls ( ) ) . toEqual ( [ { enabled : true } , { enabled : true } ] ) ;
102+ expect ( result . current . isLoading ) . toBe ( false ) ;
103+ } ) ;
104+
105+ it ( '(b) fresh start: no connection → dormant; connection created but NOT yet configured → still dormant, never gating the global skeleton' , ( ) => {
81106 connectionsState . data = [ ] ;
82107 testRunsState . isLoading = true ;
83108
@@ -87,40 +112,41 @@ describe('useOrganizationEnterpriseConnection — test-runs gating', () => {
87112 expect ( lastTwoCalls ( ) ) . toEqual ( [ { enabled : false } , { enabled : false } ] ) ;
88113 expect ( result . current . isLoading ) . toBe ( false ) ;
89114
90- // A connection appears mid-flow (the create on the fresh-start path).
91- connectionsState . data = [ { id : 'ent_new' } ] ;
115+ // A connection appears mid-flow but is not yet configured (the create on the
116+ // fresh-start path, before the configure step fills in the SAML fields).
117+ connectionsState . data = [ unconfiguredConnection ( 'ent_new' ) ] ;
92118 rerender ( ) ;
93119
94- // The query stays dormant — creating the connection must NOT fire it…
120+ // The query stays dormant — creating an unconfigured connection must NOT
121+ // fire it…
95122 expect ( lastTwoCalls ( ) ) . toEqual ( [ { enabled : false } , { enabled : false } ] ) ;
96123 // …and the global gate never folds in test-runs on this path, even though
97124 // the underlying flag would say loading were it enabled.
98125 expect ( result . current . isLoading ) . toBe ( false ) ;
99126 } ) ;
100127
101- it ( '(c) after Test-step activation → test-runs active, with loading at the table level (isFetching), not the global skeleton' , ( ) => {
128+ it ( '(c) fresh start: once the connection is configured → test-runs active, with loading at the table level (isFetching), not the global skeleton' , ( ) => {
102129 connectionsState . data = [ ] ;
103130
104131 const { result, rerender } = renderHook ( ( ) => useOrganizationEnterpriseConnection ( ) ) ;
105132
106- // Connection created mid-flow; still dormant until the Test step activates .
107- connectionsState . data = [ { id : 'ent_new' } ] ;
133+ // Connection created mid-flow but unconfigured → still dormant .
134+ connectionsState . data = [ unconfiguredConnection ( 'ent_new' ) ] ;
108135 rerender ( ) ;
109136 expect ( lastTwoCalls ( ) ) . toEqual ( [ { enabled : false } , { enabled : false } ] ) ;
110137
111- // The Test step calls `activate()` on entry . A background list fetch is now
138+ // The configure step fills in the SAML fields . A background list fetch is now
112139 // in flight (table-level), but it is not a cold load.
113140 testRunsState . isFetching = true ;
114- act ( ( ) => {
115- result . current . testRuns . activate ( ) ;
116- } ) ;
141+ connectionsState . data = [ configuredConnection ( 'ent_new' ) ] ;
142+ rerender ( ) ;
117143
118- // Now active → both queries fire.
144+ // Now configured → both queries fire.
119145 expect ( lastTwoCalls ( ) ) . toEqual ( [ { enabled : true } , { enabled : true } ] ) ;
120146 // Loading is table-level only…
121147 expect ( result . current . testRuns . isFetching ) . toBe ( true ) ;
122148 // …and the global skeleton stays down: no connection at initial load, so
123- // test-runs never gate it.
149+ // test-runs never gate it (no flash on configure → test) .
124150 expect ( result . current . isLoading ) . toBe ( false ) ;
125151 } ) ;
126152
0 commit comments