fix(e2e): provision fixture user before mobile web Playwright (closes #435)#307
Conversation
Add Neon-guarded upsert for E2E_WEB_EMAIL so login matches CI secrets after DB wipes or password drift. Wire e2e-mobile workflow with globalSetup and document fixture secrets plus psql triage in e2e/README.md. Closes #435 Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds credential-gated E2E provisioning for mobile web Playwright tests: a conditional globalSetup upserts a test user into a Neon Postgres when CI secrets and Changes
Sequence Diagram(s)sequenceDiagram
participant CI as CI Job
participant Playwright as Playwright Runner
participant GlobalSetup as global-setup.ts
participant Scripts as provision script
participant DB as Neon Postgres
participant Tests as E2E Tests
CI->>Playwright: start job (env secrets injected)
Playwright->>GlobalSetup: invoke globalSetup (if E2E_WEB_SETUP_USER=true)
GlobalSetup->>Scripts: readE2EWebCredentials() & provisionE2EWebUser()
Scripts->>DB: connect (assert Neon URL) -> upsert user (insert on conflict)
DB-->>Scripts: upsert result
Scripts-->>GlobalSetup: success / failure
GlobalSetup-->>Playwright: continue
Playwright->>Tests: run tests (real auth if provisioned, else mocked APIs)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
@CodeAnt-AI review |
|
CodeAnt AI is running the review. |
|
@cursor review |
|
@graphite-app re-review |
Sequence DiagramThis PR ensures that mobile web Playwright tests automatically upsert a fixture user in the non-production database so the login flow uses credentials aligned with CI secrets, preventing 401 failures when the user row or password hash is out of sync. sequenceDiagram
participant CI
participant Playwright
participant GlobalSetup
participant ProvisionScript
participant Database
CI->>Playwright: Run mobile web tests with e2e web env
Playwright->>GlobalSetup: Invoke global setup when setup flag is true
GlobalSetup->>ProvisionScript: Read web credentials and database url from env
GlobalSetup->>ProvisionScript: Request provision of fixture web user
ProvisionScript->>Database: Upsert user with email and password hash
Database-->>Playwright: Fixture user ready for login tests
Generated by CodeAnt AI |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 4 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit a6dcf7b. Configure here.
|
CodeAnt AI finished running the review. |
- globalSetup: warn and skip if POSTGRES_URL or creds missing (fixes mobile E2E when E2E_WEB_* secrets are not configured yet) - workflow: job-level env with E2E_TEST_USER_* fallbacks for GitHub secrets - provision: trim-aware credential fallback, close Neon pool after upsert, shared assertNeonNonProdPostgresUrl, username e2e_<12 hex> within 3–30 rule, update path checks username collision with other rows - pool: export closePoolDb for scripts Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
|
CodeAnt AI is reviewing your PR. |
Align e2e-policy with e2e/README: when POSTGRES_URL or fixture creds are empty in CI (e.g. fork PRs), global setup skips DB upsert and mock-api tests run. Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
|
CodeAnt AI finished reviewing your PR. |
Replace read-then-insert/update with INSERT ... ON CONFLICT DO UPDATE on users.email so three matrix jobs cannot race on first provision. Keep pre-check when another row owns the derived username (different email). Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
|
CodeAnt AI is running Incremental review |
Sequence DiagramThis PR adds Playwright global setup and supporting scripts to ensure a credentialed fixture user is upserted in the Neon database before mobile web E2E tests, while safely skipping provisioning when the database URL or secrets are missing. sequenceDiagram
participant CI
participant Playwright
participant GlobalSetup
participant Provisioner
participant Database
CI->>Playwright: Run mobile web tests with env variables
Playwright->>GlobalSetup: Invoke global setup
GlobalSetup->>GlobalSetup: Read db url and fixture credentials
alt Missing db url or credentials
GlobalSetup-->>Playwright: Skip fixture user provisioning
else All config present
GlobalSetup->>Provisioner: Provision E2E web user
Provisioner->>Database: Upsert fixture user by email
Database-->>Provisioner: User ensured for login
Provisioner-->>Playwright: Setup complete
end
Generated by CodeAnt AI |
|
CodeAnt AI finished running the review. |
|
CodeAnt AI is running the review. |
Sequence DiagramThis PR adds a Playwright global setup and supporting scripts that upsert a credentialed fixture user in the Neon database before mobile web E2E tests, or safely skip provisioning when database URL or credentials are missing to avoid spurious 401 failures. sequenceDiagram
participant CI as CI e2e mobile job
participant Playwright
participant GlobalSetup
participant Provisioner as E2E user provisioner
participant Database as Neon database
CI->>Playwright: Start mobile web tests
Playwright->>GlobalSetup: Run global setup
GlobalSetup->>GlobalSetup: Read POSTGRES_URL and fixture credentials
alt Config present
GlobalSetup->>Provisioner: Provision E2E user with credentials
Provisioner->>Database: Upsert user by email with password hash
Database-->>Provisioner: User ensured
Provisioner-->>GlobalSetup: Close database pool
else Missing config
GlobalSetup-->>Playwright: Skip DB provisioning and log warning
end
Generated by CodeAnt AI |
| if (globalForPool.__drizzlePool) { | ||
| await globalForPool.__drizzlePool.end(); | ||
| globalForPool.__drizzlePool = undefined; | ||
| globalForPool.__poolDb = undefined; |
There was a problem hiding this comment.
Suggestion: closePoolDb only clears the cached globals after awaiting end(). If end() throws (network/socket shutdown errors do happen), the stale cached pool/db references remain set, so subsequent calls can keep reusing a broken client and fail repeatedly. Clear/reset cached references in a guaranteed cleanup path so state is consistent even when pool shutdown errors. [missing cleanup]
Severity Level: Major ⚠️
- ❌ Playwright globalSetup may reuse a broken Neon pool.
- ⚠️ E2E web user provisioning can repeatedly fail after shutdown error.
- ⚠️ Future scripts using poolDb inherit inconsistent connection state.Steps of Reproduction ✅
1. Run mobile web Playwright E2E with `E2E_WEB_SETUP_USER=true`, which configures
`globalSetup` to `./e2e/global-setup.ts` via `playwright.config.ts:10`.
2. In `e2e/global-setup.ts:15–30`, `globalSetup()` calls `provisionE2EWebUser()` from
`scripts/e2e/provision-e2e-web-user.ts:40` after reading credentials and `POSTGRES_URL`,
which in turn uses `poolDb` (imported from `src/db/pool.ts:43`) to perform queries and
thereby initializes `globalForPool.__drizzlePool` and `globalForPool.__poolDb` in
`getPool()` / `getPoolDb()` (`src/db/pool.ts:15–35`).
3. After the queries complete, the `finally` block in `provisionE2EWebUser()`
(`scripts/e2e/provision-e2e-web-user.ts:65–99`) invokes `closePoolDb()`, which executes
the code at `src/db/pool.ts:51–54`: it awaits `globalForPool.__drizzlePool.end()` on line
52 and only then sets `globalForPool.__drizzlePool` and `globalForPool.__poolDb` to
`undefined` on lines 53–54.
4. If `Pool.end()` rejects (e.g., due to a Neon WebSocket/network error) during this
`await` on `src/db/pool.ts:52`, the function throws before reaching lines 53–54, leaving
`globalForPool.__drizzlePool` / `__poolDb` still set; any subsequent call in the same Node
process to `provisionE2EWebUser()` (via `e2e/global-setup.ts` or
`scripts/e2e/setup-web-user.ts:7–23`) or any other code using `poolDb` will see the
cached, already-ended pool in `getPool()` (`src/db/pool.ts:20–28`), reusing a broken
client instead of creating a fresh `Pool`, causing repeated transaction failures until
process restart. This inconsistent cleanup behavior matches the suggestion: there is no
guaranteed reset of cached globals when shutdown fails.Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** src/db/pool.ts
**Line:** 51:54
**Comment:**
*Missing Cleanup: `closePoolDb` only clears the cached globals after awaiting `end()`. If `end()` throws (network/socket shutdown errors do happen), the stale cached pool/db references remain set, so subsequent calls can keep reusing a broken client and fail repeatedly. Clear/reset cached references in a guaranteed cleanup path so state is consistent even when pool shutdown errors.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix|
CodeAnt AI finished running the review. |
|
CodeAnt AI is running the review. |
Sequence DiagramThis PR wires Playwright global setup and a provisioning script so that mobile web E2E tests upsert a Neon-hosted fixture user using CI secrets before login, or skip database work when configuration is missing while keeping mock-based tests green. sequenceDiagram
participant CI
participant Playwright
participant GlobalSetup
participant NeonDB
participant Backend
CI->>Playwright: Run mobile web E2E job
Playwright->>GlobalSetup: Invoke global setup
GlobalSetup->>GlobalSetup: Read POSTGRES_URL and E2E web credentials
alt DB url and credentials present
GlobalSetup->>NeonDB: Upsert fixture user with configured email and password
NeonDB-->>GlobalSetup: Fixture user ensured
else Missing config
GlobalSetup-->>Playwright: Skip DB provisioning and log warning
end
Playwright->>Backend: Login with fixture user
Backend-->>Playwright: Authenticated session returned
Generated by CodeAnt AI |
|
CodeAnt AI finished running the review. |
|
CodeAnt AI is running the review. |
Sequence DiagramThis PR adds Playwright global setup and a provisioning script that upserts a Neon-backed fixture user before mobile web E2E tests run, or safely skips provisioning when database or credential configuration is missing. sequenceDiagram
participant CI
participant Playwright
participant GlobalSetup
participant Provisioner
participant Database
participant Backend
CI->>Playwright: Run mobile web E2E job
Playwright->>GlobalSetup: Start global setup
GlobalSetup->>GlobalSetup: Read database url and fixture credentials
alt Config present
GlobalSetup->>Provisioner: Provision E2E web user
Provisioner->>Database: Upsert fixture user with current password
else Missing config
GlobalSetup->>GlobalSetup: Log warning and skip provisioning
end
Playwright->>Backend: Execute tests using login flow
Generated by CodeAnt AI |
|
CodeAnt AI finished running the review. |
|
CodeAnt AI is running the review. |
Sequence DiagramThis PR adds a Playwright global setup that, when enabled in CI, ensures a Neon-hosted database contains a fixture user whose email and password match configured secrets, skipping provisioning when credentials or database URL are missing so mock-based tests still run. sequenceDiagram
participant CI Workflow
participant Playwright
participant GlobalSetup
participant Provisioner
participant Database
CI Workflow->>Playwright: Run mobile web E2E with setup enabled
Playwright->>GlobalSetup: Invoke global setup
GlobalSetup->>GlobalSetup: Read DB URL and fixture credentials
alt DB URL or credentials missing
GlobalSetup-->>Playwright: Skip DB provisioning and continue with mock APIs
else All required values present
GlobalSetup->>Provisioner: Provision E2E web user with credentials
Provisioner->>Provisioner: Validate environment and target Neon host
Provisioner->>Database: Upsert fixture user by email with derived username and password hash
Database-->>Provisioner: Confirm user inserted or updated
Provisioner-->>GlobalSetup: Provisioning complete
GlobalSetup-->>Playwright: Proceed to execute tests
end
Generated by CodeAnt AI |
| if (!host.endsWith(".neon.tech") && host !== "neon.tech") { | ||
| throw new Error( | ||
| "Refusing to use POSTGRES_URL: hostname must be a Neon host (*.neon.tech).", | ||
| ); |
There was a problem hiding this comment.
Suggestion: The hostname check contradicts the stated policy by explicitly allowing neon.tech in addition to *.neon.tech. This lets a non-database apex domain pass validation and pushes failure to a later connection step, defeating the guardrail's intent. Require only subdomain hosts (or document and verify apex separately) so invalid endpoints are rejected early. [incorrect condition logic]
Severity Level: Major ⚠️
- ❌ Seed script accepts invalid Neon URL, fails later during connect.
- ⚠️ E2E user provisioning misreports misconfigured POSTGRES_URL until runtime.Steps of Reproduction ✅
1. Open `scripts/seed.ts` and note the `main()` entrypoint at lines 53–54 and its
invocation in the same file at lines 216–219 (via `main().catch(...)`), confirming this
script is run directly as a CLI seed.
2. Set environment variables before running the seed: `NODE_ENV` to a non-production
value, `SEED_CONFIRM=still-point-nonprod` (required at lines 59–62), and `POSTGRES_URL` to
an apex Neon host such as `postgres://user:pass@neon.tech/dbname`.
3. Run `node scripts/seed.ts`; inside `main()` the script reads `POSTGRES_URL` at lines
65–68, then calls `assertNeonHostedPostgresUrl(postgresUrl)` at lines 70–71, which uses
`parsed.hostname.toLowerCase()` at line 18 and the guard at lines 19–22:
- `host` becomes `"neon.tech"`;
- `host.endsWith(".neon.tech")` is `false`;
- `host !== "neon.tech"` is `false`;
so the condition `if (!host.endsWith(".neon.tech") && host !== "neon.tech")` is `false`
and no error is thrown, despite the comment and error message claiming only
`*.neon.tech` subdomains are allowed.
4. The script proceeds to create a Neon `Pool` with `process.env.POSTGRES_URL` in
`src/db/pool.ts` at lines 15–27 (via `poolDb.transaction(...)` in `scripts/seed.ts` lines
77–213). Any failure (e.g., DNS or connection failure when targeting `neon.tech`) now
happens later in the transaction instead of being rejected early by
`assertNeonHostedPostgresUrl`, demonstrating that the hostname check is more permissive
than its documented `*.neon.tech` constraint.Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** scripts/lib/assert-neon-postgres-url.ts
**Line:** 19:22
**Comment:**
*Incorrect Condition Logic: The hostname check contradicts the stated policy by explicitly allowing `neon.tech` in addition to `*.neon.tech`. This lets a non-database apex domain pass validation and pushes failure to a later connection step, defeating the guardrail's intent. Require only subdomain hosts (or document and verify apex separately) so invalid endpoints are rejected early.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix|
CodeAnt AI finished running the review. |
|
CodeAnt AI is running the review. |
Sequence DiagramThis PR adds a Playwright global setup and shared provisioning script that upserts a credentialed fixture user in the Neon database before mobile web E2E tests run, while safely skipping provisioning when database or credential secrets are missing. sequenceDiagram
participant CI as CI workflow
participant PW as Playwright runner
participant GS as Playwright global setup
participant Script as Provision script
participant DB as Neon database
CI->>PW: Start mobile web E2E job with env vars
PW->>GS: Invoke global setup
GS->>GS: Read POSTGRES_URL and fixture credentials
alt DB url and credentials present
GS->>Script: Provision E2E web user with email and password
Script->>DB: Upsert fixture user by email with derived username and password hash
DB-->>Script: User ensured
Script-->>GS: Provisioning complete
GS-->>PW: Continue tests against real backend
else Missing DB url or credentials
GS-->>PW: Log warning and skip provisioning (tests use mocked API)
end
Generated by CodeAnt AI |
|
CodeAnt AI finished running the review. |

User description
Summary
Addresses long-standing 401 on login for credentialed mobile web E2E when the fixture user row is missing from Neon or the stored password hash no longer matches GitHub Actions secrets.
Babysitter follow-up (commit cc7d5c0)
E2E_WEB_SETUP_USER=trueno longer fails whensecrets.E2E_WEB_*/POSTGRES_URLresolve to empty strings.globalSetuplogs a warning and skips DB provisioning so mock-based mobile E2E stays green until secrets exist.envincludesE2E_TEST_USER_EMAIL/E2E_TEST_USER_PASSWORDfallbacks (Bugbot: empty-stringE2E_WEB_*no longer blocksE2E_TEST_USER_*).closePoolDb()after provision; sharedscripts/lib/assert-neon-postgres-url.ts; fixture usernamee2e_+ 12 hex (fits app 3–30 rule); update path checks username collision with another row.Operator / issue #435
Post diagnostic comment on #435 without pasting secrets. Add repo secrets when ready for real DB alignment.
Closes #435.
CodeAnt-AI Description
Set up the mobile web E2E login user before Playwright runs
What Changed
Impact
✅ Fewer mobile web login failures in E2E✅ Reliable Playwright runs after DB wipes or secret rotation✅ Clearer setup for credentialed CI test runs🔄 Retrigger CodeAnt AI Review
Details
💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.