|
1 | 1 | import { cleanup, render, waitFor, renderHook, act } from '@testing-library/react'; |
2 | 2 | import '@testing-library/jest-dom/extend-expect'; |
3 | 3 | import * as React from 'react'; |
| 4 | +import { NEVER } from 'rxjs'; |
| 5 | +import { preloadObservable } from '../src/useObservable'; |
4 | 6 | import { |
5 | 7 | FirebaseAppProvider, |
6 | 8 | AuthCheck, |
@@ -326,39 +328,37 @@ describe('Authentication', () => { |
326 | 328 | expect(result.current.data).toEqual(getAuth(app).currentUser); |
327 | 329 | }); |
328 | 330 |
|
329 | | - it('synchronously returns a user when mounted as a child of a useSigninCheck guard', async () => { |
| 331 | + it('synchronously returns the current user without waiting for the observable', async () => { |
330 | 332 | await act(async () => { |
331 | 333 | await signIn(); |
332 | 334 | }); |
333 | 335 |
|
334 | | - // Capture the very first render of the child — before any re-renders |
| 336 | + // Replace the auth:user observable with NEVER so it never emits. |
| 337 | + // Without the fix (no initialData seeding), status is 'loading' on first render. |
| 338 | + // With the fix (initialData = auth.currentUser), status is 'success' synchronously. |
| 339 | + const cache = (globalThis as any)._reactFirePreloadedObservables as Map<string, any>; |
| 340 | + const authUserKey = `auth:user:${getAuth(app).name}`; |
| 341 | + cache?.delete(authUserKey); |
| 342 | + preloadObservable(NEVER, authUserKey); |
| 343 | + |
335 | 344 | let capturedFirstRender: { user: any; status: string } | undefined; |
336 | 345 |
|
337 | | - const UserChild = () => { |
| 346 | + const UserComponent = () => { |
338 | 347 | const { data: user, status } = useUser(); |
339 | 348 | if (capturedFirstRender === undefined) { |
340 | 349 | capturedFirstRender = { user, status }; |
341 | 350 | } |
342 | | - return <span data-testid="child-user">{user?.email ?? 'no user'}</span>; |
343 | | - }; |
344 | | - |
345 | | - const Guard = () => { |
346 | | - const { data: signinResult, status } = useSigninCheck(); |
347 | | - if (status !== 'success' || !signinResult?.signedIn) { |
348 | | - return <span data-testid="guard-loading">loading</span>; |
349 | | - } |
350 | | - return <UserChild />; |
| 351 | + return <span data-testid="user-output">{String(status)}</span>; |
351 | 352 | }; |
352 | 353 |
|
353 | | - const { findByTestId } = render(<Guard />, { wrapper: Provider }); |
354 | | - |
355 | | - await findByTestId('child-user'); |
| 354 | + try { |
| 355 | + render(<UserComponent />, { wrapper: Provider }); |
356 | 356 |
|
357 | | - // On main (without the fix), useUser mounts with a fresh SuspenseSubject |
358 | | - // (different observableId from useSigninCheck) and returns status:'loading', data:undefined. |
359 | | - // With the fix, currentUser seeds initialData so the first render is already success. |
360 | | - expect(capturedFirstRender!.status).toBe('success'); |
361 | | - expect(capturedFirstRender!.user).toEqual(getAuth(app).currentUser); |
| 357 | + expect(capturedFirstRender!.status).toBe('success'); |
| 358 | + expect(capturedFirstRender!.user).toEqual(getAuth(app).currentUser); |
| 359 | + } finally { |
| 360 | + cache?.delete(authUserKey); |
| 361 | + } |
362 | 362 | }); |
363 | 363 |
|
364 | 364 | it('does not show a logged-out user after navigating away', async () => { |
|
0 commit comments