Testing Your Auth
Mocking guards, seeding test users, writing E2E flows.
Auth is annoying to test because it touches everything. Three patterns make it manageable.
1. Override NestAuthAuthGuard for unit tests
In a NestJS unit test, you usually don't want to wire up the entire auth stack just to test a controller. Override the guard with a stub:
Now every test treats requests as if they came from u_test. Tweak the stub per describe block to test role-gated paths.
2. Use MEMORY session store + a real NestAuthModule for integration tests
For end-to-end tests that do exercise the full auth flow:
You get a real auth stack on a throwaway SQLite — sign up, log in, hit /auth/me, assert.
3. Seed a test user with deterministic credentials
Wrap this in a fixture helper so every test gets a fresh logged-in user.
Testing MFA flows
For MFA-protected endpoints, the simplest path is to disable MFA in the test config. If you need to exercise MFA itself, capture the code from the event:
Same pattern works for EmailVerificationRequestedEvent, PasswordResetRequestedEvent, and PasswordlessCodeRequestedEvent.
Testing OAuth flows
Don't hit the real provider in tests. Stub validate on the relevant BaseAuthProvider subclass:
Now client.login({ providerName: 'google', credentials: { token: 'fake' } }) "works" deterministically.
Testing role / permission gating
Combination of patterns 1 and 2 — for unit tests, override the guard to inject roles. For integration tests, seed the user with the relevant userAccess and let the real guard run.
CI hygiene
- Run tests against
MEMORYsessions and SQLite in-memory — no external services. - Use
JWT_SECRET=test-secretin CI so signed tokens are deterministic across runs. - Don't commit fixtures with real-looking secrets, even fake ones — secret scanners will trigger.