From 277f293cef738ed91c06d43dfe8bc002e89126c0 Mon Sep 17 00:00:00 2001 From: Tyler Dixon Date: Thu, 6 Aug 2026 11:07:39 -0700 Subject: [PATCH 1/2] feat(auth)!: remove the deprecated AuthCheck and ClaimsCheck components Both were deprecated in #368 (2021-05-14), which shipped useSigninCheck as their replacement in the same commit and migrated docs/use.md and the example app off them. Nothing in the repo has pointed at them since. That is four years and three months of deprecation. They only functioned with suspense enabled. In non-suspense mode they logged a warning and rendered anyway, so a suspense-mode user got no runtime signal at all, which is an argument for a clear upgrade-guide entry rather than for keeping them. Removing them is a runtime break for a plain JS importer, not just a type error, so it rides the major. Also removes the exported AuthCheckProps and ClaimsCheckProps. ClaimCheckErrors stays: it sits between them in the file but belongs to the SigninCheckResult shape that useSigninCheck returns. src/auth.tsx drops its `React` and `useSuspenseEnabledFromConfigAndContext` imports, which are used only by the removed code and would fail the build under noUnusedLocals. The file keeps its .tsx extension despite no longer containing JSX; renaming emits the same auth.js and only costs blame history. Tests: the four AuthCheck tests go. Two others used the AuthCheck wrapper without being about AuthCheck, so they get a useSigninCheck-based gate that renders the same testids. One of those was vacuous and is now real. `beforeEach` signs out, so the old gate rendered its fallback, UserDetails never mounted, and its two expectations never executed. It now signs in first and awaits the gated testid. Mutation-verified: removing the sign-in fails it. Group 3 of #754. Groups 1 and 2 are unaffected, so #754 stays open. --- docs/reference/README.md | 4 - docs/reference/functions/AuthCheck.md | 29 ------ docs/reference/functions/ClaimsCheck.md | 29 ------ docs/reference/functions/preloadUser.md | 2 +- docs/reference/functions/useIdTokenResult.md | 2 +- docs/reference/functions/useSigninCheck.md | 2 +- docs/reference/functions/useUser.md | 2 +- docs/reference/interfaces/AuthCheckProps.md | 33 ------- docs/reference/interfaces/ClaimCheckErrors.md | 2 +- docs/reference/interfaces/ClaimsCheckProps.md | 45 --------- docs/reference/interfaces/ClaimsValidator.md | 4 +- .../interfaces/SignInCheckOptionsBasic.md | 4 +- .../SignInCheckOptionsClaimsObject.md | 6 +- .../SignInCheckOptionsClaimsValidator.md | 6 +- .../type-aliases/SigninCheckResult.md | 2 +- docs/upgrade-guide.md | 26 +++++ src/auth.tsx | 89 ------------------ test/auth.test.tsx | 94 ++++++------------- 18 files changed, 73 insertions(+), 308 deletions(-) delete mode 100644 docs/reference/functions/AuthCheck.md delete mode 100644 docs/reference/functions/ClaimsCheck.md delete mode 100644 docs/reference/interfaces/AuthCheckProps.md delete mode 100644 docs/reference/interfaces/ClaimsCheckProps.md diff --git a/docs/reference/README.md b/docs/reference/README.md index 52c83109..037e6551 100644 --- a/docs/reference/README.md +++ b/docs/reference/README.md @@ -10,9 +10,7 @@ ## Interfaces -- [AuthCheckProps](interfaces/AuthCheckProps.md) - [ClaimCheckErrors](interfaces/ClaimCheckErrors.md) -- [ClaimsCheckProps](interfaces/ClaimsCheckProps.md) - [ClaimsValidator](interfaces/ClaimsValidator.md) - [FirebaseAppProviderProps](interfaces/FirebaseAppProviderProps.md) - [ObservableStatus](interfaces/ObservableStatus.md) @@ -61,11 +59,9 @@ ## Functions -- [~~AuthCheck~~](functions/AuthCheck.md) - [checkIdField](functions/checkIdField.md) - [checkinitialData](functions/checkinitialData.md) - [checkOptions](functions/checkOptions.md) -- [~~ClaimsCheck~~](functions/ClaimsCheck.md) - [FirebaseAppProvider](functions/FirebaseAppProvider.md) - [preloadFirestoreDoc](functions/preloadFirestoreDoc.md) - [preloadObservable](functions/preloadObservable.md) diff --git a/docs/reference/functions/AuthCheck.md b/docs/reference/functions/AuthCheck.md deleted file mode 100644 index dfb0e3ea..00000000 --- a/docs/reference/functions/AuthCheck.md +++ /dev/null @@ -1,29 +0,0 @@ -[**ReactFire reference docs**](../README.md) - -*** - -[ReactFire reference docs](../README.md) / AuthCheck - -# ~~Function: AuthCheck()~~ - -> **AuthCheck**(`__namedParameters`): `ReactElement` - -Defined in: [src/auth.tsx:259](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L259) - -## Parameters - -### \_\_namedParameters - -[`AuthCheckProps`](../interfaces/AuthCheckProps.md) - -## Returns - -`ReactElement` - -## Deprecated - -Use `useSigninCheck` instead - -Conditionally render children based on signed-in status and [custom claims](https://firebase.google.com/docs/auth/admin/custom-claims). - -Meant for Concurrent mode only (``). [More detail](https://github.com/FirebaseExtended/reactfire/issues/325#issuecomment-827654376). diff --git a/docs/reference/functions/ClaimsCheck.md b/docs/reference/functions/ClaimsCheck.md deleted file mode 100644 index fa5ca95e..00000000 --- a/docs/reference/functions/ClaimsCheck.md +++ /dev/null @@ -1,29 +0,0 @@ -[**ReactFire reference docs**](../README.md) - -*** - -[ReactFire reference docs](../README.md) / ClaimsCheck - -# ~~Function: ClaimsCheck()~~ - -> **ClaimsCheck**(`__namedParameters`): `Element` - -Defined in: [src/auth.tsx:215](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L215) - -## Parameters - -### \_\_namedParameters - -[`ClaimsCheckProps`](../interfaces/ClaimsCheckProps.md) - -## Returns - -`Element` - -## Deprecated - -Use `useSigninCheck` instead - -Conditionally render children based on [custom claims](https://firebase.google.com/docs/auth/admin/custom-claims). - -Meant for Concurrent mode only (``). [More detail](https://github.com/FirebaseExtended/reactfire/issues/325#issuecomment-827654376). diff --git a/docs/reference/functions/preloadUser.md b/docs/reference/functions/preloadUser.md index 65e598af..b2270e2e 100644 --- a/docs/reference/functions/preloadUser.md +++ b/docs/reference/functions/preloadUser.md @@ -8,7 +8,7 @@ > **preloadUser**(`authResolver`): `Promise`\<`User` \| `null` \| `undefined`\> -Defined in: [src/auth.tsx:11](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L11) +Defined in: [src/auth.tsx:9](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L9) ## Parameters diff --git a/docs/reference/functions/useIdTokenResult.md b/docs/reference/functions/useIdTokenResult.md index 7293fc74..ea7dfa82 100644 --- a/docs/reference/functions/useIdTokenResult.md +++ b/docs/reference/functions/useIdTokenResult.md @@ -8,7 +8,7 @@ > **useIdTokenResult**(`user`, `forceRefresh?`, `options?`): [`ObservableStatus`](../interfaces/ObservableStatus.md)\<`IdTokenResult`\> -Defined in: [src/auth.tsx:41](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L41) +Defined in: [src/auth.tsx:39](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L39) ## Parameters diff --git a/docs/reference/functions/useSigninCheck.md b/docs/reference/functions/useSigninCheck.md index 895405bc..968efaad 100644 --- a/docs/reference/functions/useSigninCheck.md +++ b/docs/reference/functions/useSigninCheck.md @@ -8,7 +8,7 @@ > **useSigninCheck**(`options?`): [`ObservableStatus`](../interfaces/ObservableStatus.md)\<[`SigninCheckResult`](../type-aliases/SigninCheckResult.md)\> -Defined in: [src/auth.tsx:136](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L136) +Defined in: [src/auth.tsx:121](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L121) Subscribe to the signed-in status of a user. diff --git a/docs/reference/functions/useUser.md b/docs/reference/functions/useUser.md index 0f7277e6..f5d566ad 100644 --- a/docs/reference/functions/useUser.md +++ b/docs/reference/functions/useUser.md @@ -8,7 +8,7 @@ > **useUser**\<`T`\>(`options?`): [`ObservableStatus`](../interfaces/ObservableStatus.md)\<`User` \| `null`\> -Defined in: [src/auth.tsx:22](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L22) +Defined in: [src/auth.tsx:20](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L20) Subscribe to Firebase auth state changes, including token refresh diff --git a/docs/reference/interfaces/AuthCheckProps.md b/docs/reference/interfaces/AuthCheckProps.md deleted file mode 100644 index c5edcb62..00000000 --- a/docs/reference/interfaces/AuthCheckProps.md +++ /dev/null @@ -1,33 +0,0 @@ -[**ReactFire reference docs**](../README.md) - -*** - -[ReactFire reference docs](../README.md) / AuthCheckProps - -# Interface: AuthCheckProps - -Defined in: [src/auth.tsx:54](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L54) - -## Properties - -### children - -> **children**: `ReactNode` - -Defined in: [src/auth.tsx:56](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L56) - -*** - -### fallback - -> **fallback**: `ReactNode` - -Defined in: [src/auth.tsx:55](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L55) - -*** - -### requiredClaims? - -> `optional` **requiredClaims?**: `Object` - -Defined in: [src/auth.tsx:57](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L57) diff --git a/docs/reference/interfaces/ClaimCheckErrors.md b/docs/reference/interfaces/ClaimCheckErrors.md index ce0afa98..179a4209 100644 --- a/docs/reference/interfaces/ClaimCheckErrors.md +++ b/docs/reference/interfaces/ClaimCheckErrors.md @@ -6,7 +6,7 @@ # Interface: ClaimCheckErrors -Defined in: [src/auth.tsx:67](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L67) +Defined in: [src/auth.tsx:52](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L52) ## Indexable diff --git a/docs/reference/interfaces/ClaimsCheckProps.md b/docs/reference/interfaces/ClaimsCheckProps.md deleted file mode 100644 index 34375923..00000000 --- a/docs/reference/interfaces/ClaimsCheckProps.md +++ /dev/null @@ -1,45 +0,0 @@ -[**ReactFire reference docs**](../README.md) - -*** - -[ReactFire reference docs](../README.md) / ClaimsCheckProps - -# Interface: ClaimsCheckProps - -Defined in: [src/auth.tsx:60](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L60) - -## Properties - -### children - -> **children**: `ReactNode` - -Defined in: [src/auth.tsx:63](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L63) - -*** - -### fallback - -> **fallback**: `ReactNode` - -Defined in: [src/auth.tsx:62](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L62) - -*** - -### requiredClaims - -> **requiredClaims**: `object` - -Defined in: [src/auth.tsx:64](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L64) - -#### Index Signature - -\[`key`: `string`\]: `any` - -*** - -### user - -> **user**: `User` - -Defined in: [src/auth.tsx:61](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L61) diff --git a/docs/reference/interfaces/ClaimsValidator.md b/docs/reference/interfaces/ClaimsValidator.md index 436ddd45..f6173e26 100644 --- a/docs/reference/interfaces/ClaimsValidator.md +++ b/docs/reference/interfaces/ClaimsValidator.md @@ -6,11 +6,11 @@ # Interface: ClaimsValidator() -Defined in: [src/auth.tsx:93](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L93) +Defined in: [src/auth.tsx:78](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L78) > **ClaimsValidator**(`claims`): `object` -Defined in: [src/auth.tsx:94](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L94) +Defined in: [src/auth.tsx:79](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L79) ## Parameters diff --git a/docs/reference/interfaces/SignInCheckOptionsBasic.md b/docs/reference/interfaces/SignInCheckOptionsBasic.md index 66967bf8..6fb7a5b2 100644 --- a/docs/reference/interfaces/SignInCheckOptionsBasic.md +++ b/docs/reference/interfaces/SignInCheckOptionsBasic.md @@ -6,7 +6,7 @@ # Interface: SignInCheckOptionsBasic -Defined in: [src/auth.tsx:85](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L85) +Defined in: [src/auth.tsx:70](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L70) ## Extends @@ -23,7 +23,7 @@ Defined in: [src/auth.tsx:85](https://github.com/FirebaseExtended/reactfire/blob > `optional` **forceRefresh?**: `boolean` -Defined in: [src/auth.tsx:86](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L86) +Defined in: [src/auth.tsx:71](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L71) *** diff --git a/docs/reference/interfaces/SignInCheckOptionsClaimsObject.md b/docs/reference/interfaces/SignInCheckOptionsClaimsObject.md index 09a1eae0..4c619eb2 100644 --- a/docs/reference/interfaces/SignInCheckOptionsClaimsObject.md +++ b/docs/reference/interfaces/SignInCheckOptionsClaimsObject.md @@ -6,7 +6,7 @@ # Interface: SignInCheckOptionsClaimsObject -Defined in: [src/auth.tsx:89](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L89) +Defined in: [src/auth.tsx:74](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L74) ## Extends @@ -18,7 +18,7 @@ Defined in: [src/auth.tsx:89](https://github.com/FirebaseExtended/reactfire/blob > `optional` **forceRefresh?**: `boolean` -Defined in: [src/auth.tsx:86](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L86) +Defined in: [src/auth.tsx:71](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L71) #### Inherited from @@ -54,7 +54,7 @@ Defined in: [src/index.ts:26](https://github.com/FirebaseExtended/reactfire/blob > **requiredClaims**: `ParsedToken` -Defined in: [src/auth.tsx:90](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L90) +Defined in: [src/auth.tsx:75](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L75) *** diff --git a/docs/reference/interfaces/SignInCheckOptionsClaimsValidator.md b/docs/reference/interfaces/SignInCheckOptionsClaimsValidator.md index 5ba7f609..32902460 100644 --- a/docs/reference/interfaces/SignInCheckOptionsClaimsValidator.md +++ b/docs/reference/interfaces/SignInCheckOptionsClaimsValidator.md @@ -6,7 +6,7 @@ # Interface: SignInCheckOptionsClaimsValidator -Defined in: [src/auth.tsx:100](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L100) +Defined in: [src/auth.tsx:85](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L85) ## Extends @@ -18,7 +18,7 @@ Defined in: [src/auth.tsx:100](https://github.com/FirebaseExtended/reactfire/blo > `optional` **forceRefresh?**: `boolean` -Defined in: [src/auth.tsx:86](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L86) +Defined in: [src/auth.tsx:71](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L71) #### Inherited from @@ -82,4 +82,4 @@ Defined in: [src/index.ts:31](https://github.com/FirebaseExtended/reactfire/blob > **validateCustomClaims**: [`ClaimsValidator`](ClaimsValidator.md) -Defined in: [src/auth.tsx:101](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L101) +Defined in: [src/auth.tsx:86](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L86) diff --git a/docs/reference/type-aliases/SigninCheckResult.md b/docs/reference/type-aliases/SigninCheckResult.md index f6f71bd1..aee05de0 100644 --- a/docs/reference/type-aliases/SigninCheckResult.md +++ b/docs/reference/type-aliases/SigninCheckResult.md @@ -8,4 +8,4 @@ > **SigninCheckResult** = \{ `errors`: \{ \}; `hasRequiredClaims`: `false`; `signedIn`: `false`; `user`: `null`; \} \| \{ `errors`: [`ClaimCheckErrors`](../interfaces/ClaimCheckErrors.md); `hasRequiredClaims`: `boolean`; `signedIn`: `true`; `user`: `User`; \} -Defined in: [src/auth.tsx:71](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L71) +Defined in: [src/auth.tsx:56](https://github.com/FirebaseExtended/reactfire/blob/main/src/auth.tsx#L56) diff --git a/docs/upgrade-guide.md b/docs/upgrade-guide.md index ba953351..7bd26774 100644 --- a/docs/upgrade-guide.md +++ b/docs/upgrade-guide.md @@ -2,6 +2,32 @@ ReactFire v5 contains breaking changes. This section lists them as they land; add an entry here in any PR that changes public behavior. +## `AuthCheck` and `ClaimsCheck` removed + +Both components were deprecated in v4 (May 2021) in favor of the `useSigninCheck` hook, which shipped in the same release. They have been removed in v5. + +They only ever worked with ``, and in non-suspense mode they logged a deprecation warning and rendered anyway. If you used them without suspense, you have been seeing that warning. + +**If you use either component**, replace it with `useSigninCheck`: + +```tsx +// Before +} requiredClaims={{ admin: true }}> + + + +// After +const { status, data: signInCheckResult } = useSigninCheck({ requiredClaims: { admin: true } }); + +if (status === 'loading') return ; + +return signInCheckResult.signedIn && signInCheckResult.hasRequiredClaims ? : ; +``` + +`useSigninCheck` also gives you the failed-claim details through `signInCheckResult.errors`, which the components never exposed, and it works in both suspense and non-suspense mode. + +The exported `AuthCheckProps` and `ClaimsCheckProps` types are gone with them. **`ClaimCheckErrors` remains**, since it is part of the `useSigninCheck` result shape. + ## Error handling behavior change Previously, errors from any reactfire hook were thrown unconditionally, making `status: 'error'` unreachable in practice. In v5, error handling depends on the mode: diff --git a/src/auth.tsx b/src/auth.tsx index 6e74d6c5..ebd71688 100644 --- a/src/auth.tsx +++ b/src/auth.tsx @@ -1,9 +1,7 @@ -import * as React from 'react'; import { user } from 'rxfire/auth'; import { preloadObservable, ReactFireOptions, useAuth, useObservable, ObservableStatus, ReactFireError } from './index.js'; import { from, of, defer } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; -import { useSuspenseEnabledFromConfigAndContext } from './firebaseApp.js'; import type { Auth, User, IdTokenResult } from 'firebase/auth'; type Claims = IdTokenResult['claims']; @@ -51,19 +49,6 @@ export function useIdTokenResult(user: User, forceRefresh = false, options?: Rea return useObservable(observableId, observable$, options); } -export interface AuthCheckProps { - fallback: React.ReactNode; - children: React.ReactNode; - requiredClaims?: Object; -} - -export interface ClaimsCheckProps { - user: User; - fallback: React.ReactNode; - children: React.ReactNode; - requiredClaims: { [key: string]: any }; -} - export interface ClaimCheckErrors { [key: string]: any[]; } @@ -204,77 +189,3 @@ function getClaimsObjectValidator(requiredClaims: Claims): ClaimsValidator { }; }; } - -/** - * @deprecated Use `useSigninCheck` instead - * - * Conditionally render children based on [custom claims](https://firebase.google.com/docs/auth/admin/custom-claims). - * - * Meant for Concurrent mode only (``). [More detail](https://github.com/FirebaseExtended/reactfire/issues/325#issuecomment-827654376). - */ -export function ClaimsCheck({ user, fallback, children, requiredClaims }: ClaimsCheckProps) { - const { data, status, error } = useIdTokenResult(user, false); - - if (status === 'loading') { - throw new Error('ClaimsCheck must be run in Suspense mode'); - } else if (status === 'error') { - throw error - } - - const { claims } = data; - const missingClaims: { [key: string]: { expected: string; actual: string | undefined } } = {}; - - const suspenseMode = useSuspenseEnabledFromConfigAndContext(); - if (!suspenseMode) { - console.warn( - 'ClaimsCheck is deprecated and only works when ReactFire is in experimental Suspense Mode. Use useSigninCheck or set suspense={true} in FirebaseAppProvider if you want to use this component.' - ); - } - - if (requiredClaims) { - Object.keys(requiredClaims).forEach((claim) => { - if (requiredClaims[claim] !== claims[claim]) { - missingClaims[claim] = { - expected: requiredClaims[claim], - actual: claims[claim]?.toString(), - }; - } - }); - } - - if (Object.keys(missingClaims).length === 0) { - return <>{children}; - } else { - return <>{fallback}; - } -} - -/** - * @deprecated Use `useSigninCheck` instead - * - * Conditionally render children based on signed-in status and [custom claims](https://firebase.google.com/docs/auth/admin/custom-claims). - * - * Meant for Concurrent mode only (``). [More detail](https://github.com/FirebaseExtended/reactfire/issues/325#issuecomment-827654376). - */ -export function AuthCheck({ fallback, children, requiredClaims }: AuthCheckProps): React.ReactElement { - const { data: user } = useUser(); - - const suspenseMode = useSuspenseEnabledFromConfigAndContext(); - if (!suspenseMode) { - console.warn( - 'AuthCheck is deprecated and only works when ReactFire is in experimental Suspense Mode. Use useSigninCheck or set suspense={true} in FirebaseAppProvider if you want to use this component.' - ); - } - - if (user) { - return requiredClaims ? ( - - {children} - - ) : ( - <>{children} - ); - } else { - return <>{fallback}; - } -} diff --git a/test/auth.test.tsx b/test/auth.test.tsx index 647ef683..6cbfedb7 100644 --- a/test/auth.test.tsx +++ b/test/auth.test.tsx @@ -5,7 +5,6 @@ import { NEVER } from 'rxjs'; import { preloadObservable } from '../src/useObservable'; import { FirebaseAppProvider, - AuthCheck, AuthProvider, useUser, useSigninCheck, @@ -29,11 +28,24 @@ describe('Authentication', () => { ); - const AuthCheckWrapper = (props?: { children?: any }) => ( + // Stands in for the removed : renders children when signed in and a fallback + // when not. Kept in suspense mode behind a Suspense boundary so the tests that used + // AuthCheckWrapper still exercise the same path. + const SigninGate = ({ children }: { children?: any }) => { + const { data: signinResult } = useSigninCheck(); + + if (signinResult?.signedIn !== true) { + return

not signed in

; + } + + return <>{children ??

signed in

}; + }; + + const SigninGateWrapper = (props?: { children?: any }) => ( - not signed in}>{props?.children ||

signed in

}
+ {props?.children}
@@ -85,56 +97,6 @@ describe('Authentication', () => { cleanup(); }); - describe('AuthCheck', () => { - it('can find firebase Auth from Context', async () => { - const { getByTestId } = render(); - - await waitFor(() => expect(getByTestId('signed-out')).toBeInTheDocument()); - }); - - it('renders the fallback if a user is not signed in', async () => { - const { getByTestId } = render(); - - await waitFor(() => expect(getByTestId('signed-out')).toBeInTheDocument()); - - await act(async () => { - await signIn(); - }); - - await waitFor(() => expect(getByTestId('signed-in')).toBeInTheDocument()); - }); - - it('renders children if a user is logged in', async () => { - await act(async () => { - await signIn(); - }); - - const { getByTestId } = render(); - - await waitFor(() => expect(getByTestId('signed-in')).toBeInTheDocument()); - }); - - it('can switch between logged in and logged out', async () => { - const { getByTestId } = render(); - - await waitFor(() => expect(getByTestId('signed-out')).toBeInTheDocument()); - - await act(async () => { - await signIn(); - }); - - await waitFor(() => expect(getByTestId('signed-in')).toBeInTheDocument()); - - await act(async () => { - await signOut(getAuth(app)); - }); - - await waitFor(() => expect(getByTestId('signed-out')).toBeInTheDocument()); - }); - - test.todo('checks requiredClaims'); - }); - describe('useSigninCheck()', () => { it('accurately reflects signed-in state', async () => { const { result } = renderHook(() => useSigninCheck(), { wrapper: Provider }); @@ -282,24 +244,30 @@ describe('Authentication', () => { }); describe('useUser', () => { - it('always returns a user if inside an component', async () => { - // Since this is wrapped in an AuthCheck component and we never sign in, this should never get rendered + it('returns a user inside a signed-in gate', async () => { + // The version of this test was vacuous: `beforeEach` signs out, so the + // gate rendered its fallback, UserDetails never mounted, and neither expectation ran. + // Signing in first and awaiting the gated testid is what makes it real. + await act(async () => { + await signIn(); + }); + const UserDetails = () => { const { data: user } = useUser(); expect(user).not.toBeNull(); expect(user).toBeDefined(); - return

Hello

; + return

Hello

; }; - render( - <> - - - - + const { findByTestId } = render( + + + ); + + await findByTestId('in'); }); it('returns the same value as getAuth(app).currentUser', async () => { @@ -366,7 +334,7 @@ describe('Authentication', () => { // a component that conditionally renders its child based on props const ConditionalRenderer = ({ renderChildren }: { renderChildren: boolean }) => { if (renderChildren) { - return ; + return ; } else { return Filler; } From 652440ad349f5bf7cdd57b64269d38c7098cf2b6 Mon Sep 17 00:00:00 2001 From: Tyler Dixon Date: Thu, 6 Aug 2026 11:24:35 -0700 Subject: [PATCH 2/2] test(auth): unnest the afterAll that never restored console.info `console.info` is mocked in `beforeAll` to silence the Auth Emulator warning. The restore lived in an `afterAll` nested inside another `afterAll`, so the inner hook was only registered while teardown was already running, and never ran. The mock leaked past the suite. Pre-existing and unrelated to the AuthCheck removal, folded in because it is two lines in a file this branch already edits. The `@ts-expect-error` above it is still required, which the test typecheck confirms. --- test/auth.test.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/auth.test.tsx b/test/auth.test.tsx index 6cbfedb7..94c3e233 100644 --- a/test/auth.test.tsx +++ b/test/auth.test.tsx @@ -74,10 +74,8 @@ describe('Authentication', () => { }); afterAll(() => { - afterAll(() => { - // @ts-expect-error console.info is mocked in beforeAll - console.info.mockRestore(); - }); + // @ts-expect-error console.info is mocked in beforeAll + console.info.mockRestore(); }); test('double check - emulator is running', async () => {