@@ -2,7 +2,7 @@ import { describe, it, expect, jest, beforeEach } from '@jest/globals';
22import React from 'react' ;
33import { act , render , renderHook } from '@testing-library/react-native' ;
44import { Text } from 'react-native' ;
5- import { AppState } from 'react-native' ;
5+ import { AppState , AppStateStatus } from 'react-native' ;
66import { StytchB2BProvider } from '../providers' ;
77import {
88 useStytchB2B ,
@@ -13,8 +13,11 @@ import {
1313import {
1414 ApiB2bSessionV1MemberSession ,
1515 ApiOrganizationV1Member ,
16+ ApiOrganizationV1Organization ,
1617 B2BAuthenticationState ,
1718 StytchB2B ,
19+ B2BSessionsAuthenticateParameters ,
20+ B2BSessionsAuthenticateResponse ,
1821} from '../../lib/b2b-headless.mjs' ;
1922
2023// ---------------------------------------------------------------------------
@@ -28,8 +31,12 @@ type AnyState =
2831type ObserverCallback = ( state : AnyState ) => void | Promise < void > ;
2932
3033interface MockStytchB2BClient {
31- authenticationStateObserver : jest . Mock ;
32- session : { authenticate : jest . Mock } ;
34+ authenticationStateObserver : jest . Mock < ( params : ObserverCallback ) => AnyState > ;
35+ session : {
36+ authenticate : jest . Mock <
37+ ( params : B2BSessionsAuthenticateParameters ) => Promise < B2BSessionsAuthenticateResponse >
38+ > ;
39+ } ;
3340}
3441
3542/**
@@ -52,7 +59,9 @@ function makeStytchMock() {
5259 return { stop } ;
5360 } ) ,
5461 session : {
55- authenticate : jest . fn ( ) . mockResolvedValue ( { } ) ,
62+ authenticate : jest
63+ . fn < ( ) => Promise < B2BSessionsAuthenticateResponse > > ( )
64+ . mockResolvedValue ( { } as B2BSessionsAuthenticateResponse ) ,
5665 } ,
5766 } ;
5867
@@ -70,24 +79,27 @@ function makeStytchMock() {
7079 } ;
7180}
7281
82+ const mockMember = { } as unknown as ApiOrganizationV1Member ;
83+ const mockMemberSession = { } as unknown as ApiB2bSessionV1MemberSession ;
84+ const mockOrganization = { } as unknown as ApiOrganizationV1Organization ;
7385function makeAuthenticatedState (
74- member : ApiOrganizationV1Member = new ApiOrganizationV1Member ( ) ,
75- memberSession : ApiB2bSessionV1MemberSession = new ApiB2bSessionV1MemberSession ( ) ,
86+ member : ApiOrganizationV1Member = mockMember ,
87+ memberSession : ApiB2bSessionV1MemberSession = mockMemberSession ,
7688) {
77- return Object . assign ( new B2BAuthenticationState . Authenticated ( ) , { member , memberSession } ) ;
89+ return new B2BAuthenticationState . Authenticated ( member , memberSession , mockOrganization , '' , '' ) ;
7890}
7991
8092// ---------------------------------------------------------------------------
8193// AppState spy — lets tests trigger app-active events
8294// ---------------------------------------------------------------------------
8395
84- let capturedAppStateHandler : ( ( status : string ) => void ) | null = null ;
96+ let capturedAppStateHandler : ( ( status : AppStateStatus ) => void ) | null = null ;
8597const appStateRemove = jest . fn ( ) ;
8698
8799beforeEach ( ( ) => {
88100 capturedAppStateHandler = null ;
89101 appStateRemove . mockClear ( ) ;
90- jest . spyOn ( AppState , 'addEventListener' ) . mockImplementation ( ( event : string , handler : ( status : string ) => void ) => {
102+ jest . spyOn ( AppState , 'addEventListener' ) . mockImplementation ( ( event , handler ) => {
91103 if ( event === 'change' ) capturedAppStateHandler = handler ;
92104 return { remove : appStateRemove } as ReturnType < typeof AppState . addEventListener > ;
93105 } ) ;
@@ -100,46 +112,64 @@ beforeEach(() => {
100112describe ( 'StytchB2BProvider' , ( ) => {
101113 it ( 'subscribes to authenticationStateObserver on mount' , ( ) => {
102114 const { mockClient } = makeStytchMock ( ) ;
103- render ( < StytchB2BProvider stytch = { mockClient } > < Text /> </ StytchB2BProvider > ) ;
115+ render (
116+ < StytchB2BProvider stytch = { mockClient } >
117+ < Text />
118+ </ StytchB2BProvider > ,
119+ ) ;
104120 expect ( mockClient . authenticationStateObserver ) . toHaveBeenCalled ( ) ;
105121 } ) ;
106122
107123 it ( 'stops the observer subscription on unmount' , ( ) => {
108124 const { mockClient, observerStops } = makeStytchMock ( ) ;
109- const { unmount } = render ( < StytchB2BProvider stytch = { mockClient } > < Text /> </ StytchB2BProvider > ) ;
125+ const { unmount } = render (
126+ < StytchB2BProvider stytch = { mockClient } >
127+ < Text />
128+ </ StytchB2BProvider > ,
129+ ) ;
110130 unmount ( ) ;
111- expect ( observerStops . every ( stop => stop . mock . calls . length > 0 ) ) . toBe ( true ) ;
131+ expect ( observerStops . every ( ( stop ) => stop . mock . calls . length > 0 ) ) . toBe ( true ) ;
112132 } ) ;
113133
114134 it ( 'removes the AppState listener on unmount' , ( ) => {
115135 const { mockClient } = makeStytchMock ( ) ;
116- const { unmount } = render ( < StytchB2BProvider stytch = { mockClient } > < Text /> </ StytchB2BProvider > ) ;
136+ const { unmount } = render (
137+ < StytchB2BProvider stytch = { mockClient } >
138+ < Text />
139+ </ StytchB2BProvider > ,
140+ ) ;
117141 unmount ( ) ;
118142 expect ( appStateRemove ) . toHaveBeenCalled ( ) ;
119143 } ) ;
120144
121145 it ( 'populates member and memberSession context when Authenticated state fires' , async ( ) => {
122146 const { mockClient, emitState } = makeStytchMock ( ) ;
123- const mockMember = new ApiOrganizationV1Member ( ) ;
124- const mockSession = new ApiB2bSessionV1MemberSession ( ) ;
125147
126148 const { result } = renderHook (
127149 ( ) => ( { member : useStytchMember ( ) , memberSession : useStytchMemberSession ( ) } ) ,
128- { wrapper : ( { children } ) => < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider > } ,
150+ {
151+ wrapper : ( { children } ) => (
152+ < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider >
153+ ) ,
154+ } ,
129155 ) ;
130156
131- await emitState ( makeAuthenticatedState ( mockMember , mockSession ) ) ;
157+ await emitState ( makeAuthenticatedState ( mockMember , mockMemberSession ) ) ;
132158
133159 expect ( result . current . member ) . toBe ( mockMember ) ;
134- expect ( result . current . memberSession ) . toBe ( mockSession ) ;
160+ expect ( result . current . memberSession ) . toBe ( mockMemberSession ) ;
135161 } ) ;
136162
137163 it ( 'clears member and memberSession context when Unauthenticated state fires' , async ( ) => {
138164 const { mockClient, emitState } = makeStytchMock ( ) ;
139165
140166 const { result } = renderHook (
141167 ( ) => ( { member : useStytchMember ( ) , memberSession : useStytchMemberSession ( ) } ) ,
142- { wrapper : ( { children } ) => < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider > } ,
168+ {
169+ wrapper : ( { children } ) => (
170+ < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider >
171+ ) ,
172+ } ,
143173 ) ;
144174
145175 await emitState ( makeAuthenticatedState ( ) ) ;
@@ -154,10 +184,11 @@ describe('StytchB2BProvider', () => {
154184 const { mockClient, emitState } = makeStytchMock ( ) ;
155185 const authenticatedState = makeAuthenticatedState ( ) ;
156186
157- const { result } = renderHook (
158- ( ) => useStytchB2BAuthenticationState ( ) ,
159- { wrapper : ( { children } ) => < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider > } ,
160- ) ;
187+ const { result } = renderHook ( ( ) => useStytchB2BAuthenticationState ( ) , {
188+ wrapper : ( { children } ) => (
189+ < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider >
190+ ) ,
191+ } ) ;
161192
162193 expect ( result . current ) . toBeInstanceOf ( B2BAuthenticationState . Loading ) ;
163194 await emitState ( authenticatedState ) ;
@@ -167,7 +198,11 @@ describe('StytchB2BProvider', () => {
167198 it ( 'calls session.authenticate when app becomes active and session is Authenticated' , async ( ) => {
168199 const { mockClient, emitState } = makeStytchMock ( ) ;
169200
170- render ( < StytchB2BProvider stytch = { mockClient } > < Text /> </ StytchB2BProvider > ) ;
201+ render (
202+ < StytchB2BProvider stytch = { mockClient } >
203+ < Text />
204+ </ StytchB2BProvider > ,
205+ ) ;
171206
172207 await act ( async ( ) => {
173208 capturedAppStateHandler ! ( 'active' ) ;
@@ -182,7 +217,11 @@ describe('StytchB2BProvider', () => {
182217 const { mockClient, emitState } = makeStytchMock ( ) ;
183218 mockClient . session . authenticate . mockRejectedValueOnce ( new Error ( 'network error' ) ) ;
184219
185- render ( < StytchB2BProvider stytch = { mockClient } > < Text /> </ StytchB2BProvider > ) ;
220+ render (
221+ < StytchB2BProvider stytch = { mockClient } >
222+ < Text />
223+ </ StytchB2BProvider > ,
224+ ) ;
186225
187226 await act ( async ( ) => {
188227 capturedAppStateHandler ! ( 'active' ) ;
@@ -195,7 +234,11 @@ describe('StytchB2BProvider', () => {
195234 it ( 'does not call session.authenticate when app becomes active but state is not Authenticated' , async ( ) => {
196235 const { mockClient, emitState } = makeStytchMock ( ) ;
197236
198- render ( < StytchB2BProvider stytch = { mockClient } > < Text /> </ StytchB2BProvider > ) ;
237+ render (
238+ < StytchB2BProvider stytch = { mockClient } >
239+ < Text />
240+ </ StytchB2BProvider > ,
241+ ) ;
199242
200243 await act ( async ( ) => {
201244 capturedAppStateHandler ! ( 'active' ) ;
@@ -219,7 +262,9 @@ describe('withStytchB2B', () => {
219262 it ( 'makes the stytch client available via useStytchB2B inside the provider' , ( ) => {
220263 const { mockClient } = makeStytchMock ( ) ;
221264 const { result } = renderHook ( ( ) => useStytchB2B ( ) , {
222- wrapper : ( { children } ) => < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider > ,
265+ wrapper : ( { children } ) => (
266+ < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider >
267+ ) ,
223268 } ) ;
224269 expect ( result . current ) . toBe ( mockClient ) ;
225270 } ) ;
@@ -229,16 +274,19 @@ describe('withStytchMember', () => {
229274 it ( 'returns undefined when no member is in context' , ( ) => {
230275 const { mockClient } = makeStytchMock ( ) ;
231276 const { result } = renderHook ( ( ) => useStytchMember ( ) , {
232- wrapper : ( { children } ) => < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider > ,
277+ wrapper : ( { children } ) => (
278+ < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider >
279+ ) ,
233280 } ) ;
234281 expect ( result . current ) . toBeUndefined ( ) ;
235282 } ) ;
236283
237284 it ( 'reflects the member once Authenticated state fires' , async ( ) => {
238285 const { mockClient, emitState } = makeStytchMock ( ) ;
239- const mockMember = new ApiOrganizationV1Member ( ) ;
240286 const { result } = renderHook ( ( ) => useStytchMember ( ) , {
241- wrapper : ( { children } ) => < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider > ,
287+ wrapper : ( { children } ) => (
288+ < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider >
289+ ) ,
242290 } ) ;
243291 await emitState ( makeAuthenticatedState ( mockMember ) ) ;
244292 expect ( result . current ) . toBe ( mockMember ) ;
@@ -249,7 +297,9 @@ describe('withStytchMemberSession', () => {
249297 it ( 'returns undefined when no session is in context' , ( ) => {
250298 const { mockClient } = makeStytchMock ( ) ;
251299 const { result } = renderHook ( ( ) => useStytchMemberSession ( ) , {
252- wrapper : ( { children } ) => < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider > ,
300+ wrapper : ( { children } ) => (
301+ < StytchB2BProvider stytch = { mockClient } > { children } </ StytchB2BProvider >
302+ ) ,
253303 } ) ;
254304 expect ( result . current ) . toBeUndefined ( ) ;
255305 } ) ;
0 commit comments