Skip to content

feat: add E2E integration tests with WorkOS emulator#399

Draft
nicknisi wants to merge 16 commits intomainfrom
nicknisi/integration-tests
Draft

feat: add E2E integration tests with WorkOS emulator#399
nicknisi wants to merge 16 commits intomainfrom
nicknisi/integration-tests

Conversation

@nicknisi
Copy link
Copy Markdown
Member

Summary

  • Adds Playwright E2E integration tests that run the example Next.js app against the workos CLI's emulator (workos@beta), proving the full auth lifecycle works end-to-end without a real WorkOS backend
  • Adds a Client Demo page to the Next.js example app (matching the tanstack-start example) with useAuth(), useAccessToken(), org switching, and client-side sign out
  • Adds login_hint support to the example login route for multi-user testing
  • Adds CI job to run E2E tests on every push/PR

Test Coverage (27 tests)

Suite Tests What it covers
auth flows 5 Sign-in, sign-out, protected routes
error handling 4 Corrupt cookies, bad callback params
session mgmt 3 Persistence, isolation, cookie attrs
client hooks 4 useAuth lifecycle, useAccessToken, client-side sign-out
impersonation 3 Banner renders, stop button, stop ends session
token refresh 2 Client-side refresh via UI, session persistence
org switching 3 Client-side switch via UI, badge update, session persistence
multi-user 3 login_hint selection, account details, context isolation

How it works

The e2e/ directory is its own workspace package (isolates @playwright/test from Next.js peer dep conflicts). Tests use createEmulator() from workos/emulate to start a local WorkOS backend with seeded users, orgs, and impersonation data. The emulator's authorize endpoint auto-selects the first seeded user (or a specific user via login_hint), enabling fully automated auth flows with no UI interaction.

Test plan

  • pnpm test — 332 unit tests pass
  • pnpm test:e2e:next — 27 E2E tests pass
  • pnpm run build succeeds
  • CI E2E job passes on this PR

nicknisi added 12 commits March 25, 2026 23:13
Uses the programmatic `createEmulator()` API from the WorkOS CLI to
stand up a local WorkOS backend, then runs the example Next.js app
against it. Tests cover the full auth lifecycle: unauthenticated state,
sign-in via the emulator's auto-auth flow, protected page access,
account details rendering, and sign-out with session clearing.

The e2e/ directory is its own workspace package to isolate
@playwright/test from the examples (Next.js 16 declares it as an
optional peer dep, causing conflicting type resolutions).

Tests are parameterized via E2E_APPS env var so the same suite can
run against examples/next or examples/vinext.
- Move .env.local aside during tests so emulator env vars take
  precedence; restore in globalTeardown
- Use vinext dev mode (vinext start has an RSC entry bug)
- Skip auth-flow tests for vinext — its redirect() shim doesn't
  propagate Set-Cookie headers, breaking the PKCE cookie chain
- Unauthenticated tests (home page, /account protection) pass on both
Error handling tests:
- Corrupt session cookie gracefully degrades to unauthenticated
- Corrupt cookie on protected page doesn't crash
- Callback with missing params returns error page
- Callback with invalid code returns error page

Session management tests:
- Session persists across page navigations
- Session isolation between browser contexts (incognito)
- Session cookie has expected name and httpOnly flag

Client-side hook tests:
- useAuth resolves to unauthenticated state after hydration
- useAuth reflects authenticated state after sign-in
- useAuth updates after sign-out
… E2E tests

New tests:
- Impersonation banner renders with seeded impersonator data
- Stop impersonation button ends session
- Token refresh via /test-refresh route returns updated session
- Session remains valid after refresh
- Org switching via /test-switch-org completes without error
- Session remains valid after org switch
- login_hint selects a specific seeded user
- Different users see different account details
- Sessions isolated between users in separate browser contexts

Example app changes:
- Login route accepts ?login_hint= query param
- Added /test-refresh route (calls refreshSession)
- Added /test-switch-org route (calls switchToOrganization)
- Updated middleware matcher for new test routes

Seed now includes impersonator data on first user, a second user
(other@example.com), and a "Test Organization" for org switching.
The emulator now reads organization_id from the request body during
refresh_token exchange, so switchToOrganization properly sets the
org context on the session.
Add /client page to Next.js example (modeled after tanstack-start)
with useAuth, useAccessToken, and org switching UI. Rewrite
client-hooks and org-switching E2E tests to exercise the actual
client page instead of test-only route handlers.

New client page features:
- Session info display (sessionId, organizationId, role, permissions)
- Impersonator indicator
- Access token status with refresh button
- Organization switching with text input
- Client-side sign out

Updated tests:
- client-hooks tests now use /client page
- org-switching tests include client page UI test
- Restored sign-out workarounds (emulator logout needs full URL for returnTo)
Replace bare-bones client page with full-featured version matching
the tanstack-start example. Adds useAuth/useAccessToken display,
org switching UI, and Client Demo nav link. Updates E2E tests.
The Refresh Token button was silently catching errors and only logging
to console. Now shows success/error callout in the UI so failures are
visible. Updates E2E test to assert the success message appears.
Delete /test-refresh and /test-switch-org route handlers. All token
refresh, org switching, and client hook tests now exercise the real
client page UI. No test-only code in the example app.
Replace link:../../cli/main with workos@beta from npm so the
E2E tests can run in CI without the local CLI checkout.
Runs Playwright E2E tests against the Next.js example app with
the WorkOS emulator on every push/PR. Uploads test results as
artifacts on failure.
@nicknisi nicknisi force-pushed the nicknisi/integration-tests branch from 814b11a to 7b9f365 Compare March 26, 2026 04:15
Playwright requires empty destructure ({}) as first arg in fixtures.
Exclude e2e/ from oxlint rather than fighting the pattern.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant