Files
civitai__civitai/tests
Zachary Lowden 0cc030120f fix(auth): preview-only legacy-session fallback so preview smoke can authenticate (#2786)
* fix(auth): preview-only legacy-session fallback so preview smoke can authenticate

The first-party OAuth cutover (#2712 + follow-ups) moved user resolution off the
app DB onto getSessionUserById, which reads the shared session cache then the
centralized hub (auth.civitai.com) — both backed by the PRODUCTION identity store.

PR previews run against the dev DB clone, where the ci-smoke-* smoke users are
seeded (datapacket-talos seed-smoke-test-users CronJob) but the hub has no row for
them. So getLegacySession decoded the minted legacy cookie fine, extracted the
userId, then getSessionUserById returned null (hub 404) → null session → the _app
route guard 307'd every authenticated request to /login → auth.civitai.com → back
→ ERR_TOO_MANY_REDIRECTS. Result: ALL ~53 authenticated preview smoke tests failed
(observed on pr-2781..2784 previews; #2773's smoke was green before the cutover).
Production is unaffected — real users resolve via the hub normally.

Fix: in getLegacySession, when getSessionUserById misses AND IS_PREVIEW, fall back
to the rich `user` embedded in the minted legacy cookie — exactly what the
pre-cutover gate did (read token.user straight from the cookie, no DB hit). Gated
on IS_PREVIEW so production NEVER trusts the embedded user (it must resolve via the
hub); zero production blast radius. Updated the preview-auth.setup.ts header to
document the new mechanism.

This restores pre-cutover preview behaviour as a stopgap; a longer-term option is
to teach the hub/session-client a preview identity source, but that's the migration
owner's call.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(preview): repoint anonymous SSR-inject landing /login -> /preview-restricted

The anonymous SSR-injection smoke tests (preview-bootstrap, preview-ssr-inject)
used ANON_LANDING='/login' — pre-cutover the in-app /login PAGE rendered through
_app, so __NEXT_DATA__ carried the SSR-injected browsingSettingsAddons /
announcements / getLiveNow. The first-party-OAuth cutover (remove in-app login UI)
made /login a server-side redirect to the hub: it no longer renders, so the anon
landing seeded nothing → the tests failed (and, with AUTH_JWT_ISSUER unset on the
preview, looped).

/preview-restricted is the preview gate's OTHER allow-listed exception
(resolveAuthGuard: `path !== '/preview-restricted'`) and is a plain page (no custom
getServerSideProps) that renders via _app for anyone — anonymous included. Repoint
ANON_LANDING there so the same _app SSR-inject path is exercised, keeping the
coverage instead of dropping it.

(Companion to PR #2786's preview-only legacy-session fallback for the AUTHENTICATED
loop, and the datapacket-talos preview ConfigMap getting AUTH_JWT_ISSUER so /login
forwards to the hub instead of degrading to / on regular previews.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 19:36:57 -05:00
..

Video: https://discord.com/channels/955572167662260295/1062092338698145812/1338591521401733192

# Playwright Testing

### Goal
E2E testing for the main app.
Catch potential issues when changing code, or evaluate edge cases.

### Anti-Goal
For this to be a frustrating pain-in-the-ass time vampire.
It's better to have 1 decent test than try to do 10 perfect ones and give up because it's too time consuming.

### What to Do

- Write tests for common user flows (fill a form, click a button, get a result)
- Handle what-if scenarios (errors, browsers, etc)
- A good rule of thumb is: if it's been reported as a bug, we should have a test in place for it (and things like it)

### What Not to Do

- Write "1==1" tests (dopamine hit, but pointless)
- Mandate coverage percentages (leads to annoyance and features not being done)

---

### How

Testing is intended to work on local development (docker) for consistency with users/data and easy tear down.

1) Run local services (`make init` or devcontainers)
2) Create a file in the `tests/` directory, or use an existing one. Doesn't really matter. Open to directory structure, so something like `tests/generator/gen-queue.spec.ts` would be reasonable.
3) Start writing tests.
    (a) can be done by hand if you know what you're looking to do
    (b) easier approach: `npm run test:gen -- --load-storage tests/auth/{user}.json --viewport-size 1920,1080 http://localhost:3000/{url}`
        - This allows you to create tests by interacting with the page and picking locators
    (c) we'll need better locators, especially for icons. add `data-testid=` to the places you need them (they'll be stripped from production)
    (d) use the various authed users to test different scenarios (mod, full access, muted, etc)
    (e) feel free to mock responses from any of the APIs, but in general it's best to only do this for external services
4) Run with either `npm run test` or `npm run test:ui` to do it interactively with screenshots
5) If you need to reset the db after each test, you can either:
    (a) clean up the mutations as part of the test (delete an object you just made)
    (b) `make boostrap-db` to reset the whole database back to normal
6) We'll eventually set up the github action to run this before a deploy

### Test Failures

There are 4 types of test failures:

1) A bad test (always fail)
    - these might have bad selectors or inaccurate logic
    - **solution**: fix them
2) A flaky test (sometimes fail)
    - frustrating tests which seem to pass most of the time, but not always
        - this is usually a result of race conditions, mismatched timing, or not properly awaiting events like animations
    - **solution**: narrow down which part of the test fails, and catch the flaky issue
3) Intended code change
    - we might have changed the verbiage on a button, which makes certain locators no longer work
        - this is fine, although locators should try to be as agnostic as possible
    - alternatively, we might have simply changed the business logic
    - **solution**: in either case, simply update the test itself
4) Unintended code change
    - you've changed something in the app, and a test breaks due to the introduction of a bug
        - this is the major reason we have tests
    - **solution**: leave the tests alone, they're doing their job. fix the code.