TWD Tip: Stub Auth0 Hooks and Mock React Modules
Source: Dev.to
Background
Authentication is one of the trickiest features to test in modern apps.
Tools like Auth0 help a lot, especially with React, providing hooks such as useAuth0 to manage authentication.
Testing these hooks can be challenging:
- Cypress requires special configuration for cross‑domain testing.
- Vitest needs data mocking, but tests still only return a simple pass/fail in the terminal.
- Real users must be created and validated.
Testing While Developing (TWD) encourages testing behavior, not infrastructure. You don’t need to test the auth provider itself—just simulate the authentication behavior your app depends on.
Stubbing the Auth0 Hook
For React apps using Auth0 with PKCE flow, we rely on the useAuth0 hook rather than simple requests. The following pattern gives us full control over authentication in tests.
Wrapper Module
// src/hooks/useAuth.ts
import { useAuth0 } from "@auth0/auth0-react";
const useAuth = () => useAuth0();
export default { useAuth };
Why export an object?
ESModules are immutable by default. Named exports (export const useAuth = …) cannot be mocked at runtime, but an object property can. Exporting as a mutable object lets us stub it with Sinon.
Example TWD Test
import { beforeEach, describe, it, afterEach } from 'twd-js/runner';
import { twd, screenDom, userEvent, expect } from 'twd-js';
import authSession from '../hooks/useAuth';
import Sinon from 'sinon';
import userMock from './userMock.json';
import type { Auth0ContextInterface } from '@auth0/auth0-react';
describe('App tests', () => {
beforeEach(() => {
Sinon.resetHistory();
Sinon.restore();
twd.clearRequestMockRules();
});
afterEach(() => {
twd.clearRequestMockRules();
});
it('should render home page for authenticated user', async () => {
Sinon.stub(authSession, 'useAuth').returns({
isAuthenticated: true,
isLoading: false,
user: userMock,
getAccessTokenSilently: Sinon.stub().resolves('fake-token'),
loginWithRedirect: Sinon.stub().resolves(),
logout: Sinon.stub().resolves(),
} as unknown as Auth0ContextInterface);
await twd.visit('/');
const welcomeText = await screenDom.findByRole('heading', {
name: 'Authenticated area',
level: 1,
});
twd.should(welcomeText, 'be.visible');
const infoText = await screenDom.findByText(
'You are signed in with Auth0. Manage your profile and jot down quick notes below.'
);
twd.should(infoText, 'be.visible');
});
});
What This Stubbing Achieves
- Control authentication state (
isAuthenticated,isLoading). - Provide mock user data (
userMock). - Stub token retrieval (
getAccessTokenSilently). - Mock login/logout flows (
loginWithRedirect,logout).
Testing Scenarios
With the stub in place, you can easily test:
- User logged in vs. logged out.
- Users with different roles or profile data.
- Authentication errors (e.g., token fetch failure).
Further Resources
- Full example React app with this flow: twd-auth0-pkce
- Auth flow with backend sessions example: twd-auth0
- Official TWD documentation: twd.dev
Extending the Approach
This pattern isn’t limited to Auth0. Any module that needs to be controlled in TWD browser tests can be exported as a mutable object and stubbed with Sinon, giving you full control over external dependencies while keeping tests focused on application behavior.