Test While Developing (TWD): An in-browser testing approach that validates full user workflows in real time. This project demonstrates a production-grade Auth0 PKCE flow (Frontend-only Auth) and how to easily test it without complex E2E setups.
The application uses Auth0 React SDK to authenticate users directly in the browser using the PKCE flow.
useAuthHook: A centralized hook wrappinguseAuth0for easy mocking.- State Management: React state handles data, while auth state is managed by the SDK.
- API Client: Attaches the Access Token to requests via
Authorization: Bearerheader.
The backend is a simple API that validates JWTs.
- Middleware:
express-oauth2-jwt-bearerverifies tokens against Auth0 JWKS. - Database: Drizzle ORM + LibSQL.
- Stateless: No sessions or cookies required.
This project demonstrates how to Test While Developing (TWD) with complex authentication flows.
Instead of struggling with slow E2E login scripts, we simply mock the auth hook directly in the browser using Sinon.
Check out src/twd-test/app.twd.test.ts to see:
- Mocking the Auth Hook:
import authSession from '../hooks/useAuth'; // ... Sinon.stub(authSession, 'useAuth').returns({ isAuthenticated: true, user: mockUser, getAccessTokenSilently: Sinon.stub().resolves('fake-token'), // ... });
- Simulating User States: Easily test "Loading", "Unauthenticated", or "Authenticated" states by changing the mock return value.
- API Mocking: Combined with
twd.mockRequest, you simulate the entire backend interaction.
Benefit: You get instant verification of your UI's protected areas without ever hitting the real Auth0 login page during tests.
TWD is a radical new approach to testing web apps. Instead of running tests in Node.js with JSDOM or spinning up full E2E suites, TWD runs tests directly in the browser alongside your app.
- Real browser environment: No JSDOM quirks, no synthetic Node.js environment. Tests run where the app actually runs.
- Request mocking without complexity:
twd.mockRequest()instead of MSW handlers. - Testing Library built-in:
screenDom.getByRole()for semantic queries. - Instant feedback: Refresh = tests run. No test bundling, no startup overhead.
import { twd, userEvent, screenDom } from "twd-js";
import { describe, it, beforeEach } from "twd-js/runner";
import { mockAuthenticatedUser } from "./authUtils";
describe("Notes App", () => {
beforeEach(() => {
twd.clearRequestMockRules();
mockAuthenticatedUser({ id: "1", name: "John", email: "john@test.com" });
});
it("should create and display a new note", async () => {
// Mock the API response BEFORE the action
twd.mockRequest("createNote", {
method: "POST",
url: "/api/notes",
response: { id: 1, title: "Test", content: "My note", createdAt: Date.now() },
});
// Fill the form using Testing Library semantics
const titleInput = screenDom.getByLabelText("Title");
const submitBtn = screenDom.getByRole("button", { name: "Add note" });
await userEvent.type(titleInput, "Test");
await userEvent.click(submitBtn);
// Wait for the mocked request
await twd.waitForRequest("createNote");
// Assert the note appears in the DOM
const note = screenDom.getByText("Test");
note.should("be.visible");
});
});What's being tested: React Router action → useFetcher submission → API call → loader revalidation → DOM update. All real, all in the browser.
GET /
↓
PrivateRoute checks `useAuth().isAuthenticated`
↓
If false, Redirect to /login
/login renders
↓
User clicks "Log In" Button
↓
Auth0 SDK redirects to Auth0 Universal Login
Redirect back to app with code
↓
Auth0 SDK exchanges code for Tokens (Access + ID Token)
↓
App re-renders, `isAuthenticated` becomes true
App component mounts
↓
Calls `getAccessTokenSilently()` to get token string
↓
Calls API with `Authorization: Bearer <token>`
↓
Backend validates token signature & audience
↓
Data returned
cd backend-service
npm install
npm run db:push # Create SQLite tables
npm run dev # Starts on :3000Set up .env:
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_CLIENT_ID=xxxx
AUTH0_CLIENT_SECRET=xxxx
AUTH0_AUDIENCE=https://api.myapp.com <-- NEW: API Identifiernpm install
npm run devSet up .env:
VITE_AUTH0_DOMAIN=your-tenant.auth0.com
VITE_AUTH0_CLIENT_ID=xxxx
VITE_AUTH0_AUDIENCE=https://api.myapp.comIn the browser (http://localhost:5173):
- Open DevTools console
- TWD tests run in the sidebar. Note how the Auth0 login is completely bypassed by our mocks!
cd backend-service
npm testBy exploring this project, you'll understand:
- OAuth2 Security: Why tokens stay server-side, how HttpOnly cookies work.
- React Router Data APIs: Loaders for data-before-render, actions for mutations, error boundaries.
- BFF Pattern: Why a backend layer protects your frontend from auth complexity.
- Testing Workflows: How TWD tests validate full user journeys faster than traditional E2E.
- Type Safety: Using TypeScript + Axios helpers to catch API bugs at compile time.
- backend-service/routes/notes.ts – User-scoped API with JWT validation (
checkJwt). - src/hooks/useAuth.ts – The Auth wrapper hook used for easy mocking.
- src/pages/App/App.tsx – Authenticated view fetching data with tokens.
- src/twd-test/app.twd.test.ts – THE SHOWCASE: How to mock
useAuthto test authenticated flows.
- Auth0 Docs
- React Router v7 Loaders/Actions
- Drizzle ORM
- TWD (Test While Developing) – The custom test runner powering this project