Skip to content

fix(e2e): mock Discord OAuth via DB manipulation (PP-e20)#1293

Open
timothyfroehlich wants to merge 6 commits intomainfrom
worktree-agent-a90e634ce9f217727
Open

fix(e2e): mock Discord OAuth via DB manipulation (PP-e20)#1293
timothyfroehlich wants to merge 6 commits intomainfrom
worktree-agent-a90e634ce9f217727

Conversation

@timothyfroehlich
Copy link
Copy Markdown
Owner

@timothyfroehlich timothyfroehlich commented May 5, 2026

Summary

  • The previous approach (Playwright route interception via `page.route('/authorize')`) cannot work: `linkIdentity` fails server-side with `"Unsupported provider: missing redirect URI"` when CI's dummy Discord credentials are used. No browser navigation ever happens, so there is nothing to intercept.
  • This PR redesigns the tests to verify the testable UI surface using direct DB manipulation instead.
  • The OAuth handshake itself (browser → Discord → callback → DB row) is integration territory and is explicitly out of scope per PP-e20's mock-only policy.

What the new tests verify

  1. Anonymous /login: "Continue with Discord" button is visible (Discord is "available" because DISCORD_CLIENT_ID is set to a dummy value in CI).
  2. Authenticated (not connected): "Connect Discord" button is visible in /settings.
  3. DB-link + unlink flow: Marked test.fixme — direct SQL inserts into auth.identities invalidate the GoTrue session during updateSession() in the Next.js middleware (which runs on every request). The page redirects to /login instead of rendering /settings. Requires a GoTrue-native admin identity linking API (not yet available). Tracked as PP-e20 for follow-up.

New helpers in e2e/support/supabase-admin.ts

  • linkUserDiscordIdentity(userId, discordId): inserts into auth.identities with provider: "discord" via direct postgres connection; also syncs the user_profiles.discord_user_id mirror column.
  • unlinkUserDiscordIdentity(userId): deletes the row and clears the mirror column.

Removes previous test.fixme calls

Removes the 2 test.fixme(true, "PP-e20 ...") calls added by skip-PR #1290 — the two passing tests ARE the fix for those. The DB-link+unlink test is marked fixme separately with a detailed root cause explanation.

Test plan

  • pnpm run check passes locally (types, lint, unit tests — all clean)
  • CI E2E runs against the Supabase branch DB with dummy DISCORD_CLIENT_ID set — 2 tests pass, 1 marked fixme (GoTrue session invalidation on raw identity insert)

🤖 Generated with Claude Code

…ion (PP-e20)

The previous attempt at Playwright route interception couldn't work:
linkIdentity fails server-side ("Unsupported provider: missing redirect
URI") with CI's dummy Discord credentials, so no browser navigation
happens to intercept.

This redesign verifies the testable UI surface instead:
- Anonymous /login shows "Continue with Discord" button
- Authenticated user without Discord linked sees "Connect Discord" button
- After direct linkUserDiscordIdentity() (simulating successful OAuth),
  UI shows "Disconnect Discord" on reload
- Clicking Disconnect (which hits the server unlink action, not external
  OAuth) reverts the UI to "Connect Discord"

Adds linkUserDiscordIdentity() and unlinkUserDiscordIdentity() helpers to
e2e/support/supabase-admin.ts; these insert/delete rows in auth.identities
via a direct postgres connection and sync the user_profiles mirror column.

The OAuth handshake itself (browser → Discord → callback → DB row) is
integration territory and is explicitly out of scope per PP-e20's
mock-only policy.

Removes the two test.fixme(true, "PP-e20") calls added by skip-PR #1290
— these tests are the fix.

Tracking: PP-e20.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 5, 2026 22:33
@vercel
Copy link
Copy Markdown

vercel Bot commented May 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pin-point Ready Ready Preview, Comment May 6, 2026 3:10pm

@supabase
Copy link
Copy Markdown

supabase Bot commented May 5, 2026

This pull request has been ignored for the connected project udhesuizjsgxfeotqybn due to reaching the limit of concurrent preview branches.
Go to Project Integrations Settings ↗︎ if you wish to update this limit.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces the previous Playwright-based Discord OAuth interception approach with a DB-backed E2E strategy for Connected Accounts, so CI can still validate the settings/login UI surfaces without depending on a real Discord OAuth round-trip.

Changes:

  • Added direct Postgres helpers to create/remove a simulated Discord identity for a test user.
  • Reworked the Connected Accounts E2E spec to cover anonymous login button visibility, authenticated connect-state visibility, simulated linked-state rendering, and server-side unlink flow.
  • Removed the prior test.fixme coverage gap for PP-e20 by replacing it with runnable mock-only tests.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
e2e/support/supabase-admin.ts Adds direct DB helpers for simulating Discord link/unlink state in Supabase auth + mirrored profile data.
e2e/full/oauth-connected-accounts.spec.ts Replaces skipped OAuth redirect tests with UI-state assertions driven by dynamic users and DB state setup.

Comment thread e2e/full/oauth-connected-accounts.spec.ts Outdated
Comment thread e2e/support/supabase-admin.ts Outdated
Comment thread e2e/full/oauth-connected-accounts.spec.ts Outdated
Comment thread e2e/support/supabase-admin.ts Outdated
Comment thread e2e/support/supabase-admin.ts Outdated
GoTrue reads all identities for a user during sign-in and throws "Database
error querying schema" when any identity row's identity_data is missing the
`email` field. The linkUserDiscordIdentity helper omitted `email`, causing
the test user's subsequent login to fail after the DB insert.

Fix: add a synthetic email (`${discordId}@discord.test`) to identity_data.
Also: wrap both writes (auth.identities + user_profiles) in a transaction in
both link and unlink helpers; switch ON CONFLICT to DO NOTHING to prevent
accidental identity theft if a discordId is reused; use worker-specific prefix
(getTestPrefix) instead of Date.now() for the fake Discord ID to eliminate
millisecond-collision risk across parallel workers; tighten the skip guard to
check both DISCORD_CLIENT_ID and DISCORD_CLIENT_SECRET (matching what
providers.discord.isAvailable() actually requires).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GoTrue reads all identities for a user during sign-in and throws "Database
error querying schema" when any identity row's identity_data is missing the
`email` field. The linkUserDiscordIdentity helper omitted `email`, causing
the test user's subsequent login to fail after the DB insert.

Fix: add a synthetic email (`${discordId}@discord.test`) to identity_data.
Also: wrap both writes (auth.identities + user_profiles) in a transaction in
both link and unlink helpers; switch ON CONFLICT to DO NOTHING to prevent
accidental identity theft if a discordId is reused; use worker-specific prefix
(getTestPrefix) instead of Date.now() for the fake Discord ID to eliminate
millisecond-collision risk across parallel workers; tighten the skip guard to
check both DISCORD_CLIENT_ID and DISCORD_CLIENT_SECRET (matching what
providers.discord.isAvailable() actually requires).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
timothyfroehlich and others added 2 commits May 6, 2026 09:47
…chema error (PP-e20)

GoTrue's signInWithPassword validates ALL of a user's identities during
authentication. When we insert a synthetic identity row directly into
auth.identities and then call signInWithPassword, GoTrue throws
"Database error querying schema" (HTTP 500) because the synthetic row
doesn't fully satisfy its internal validation path.

Fix: log in first (while the user has no Discord identity), then insert
the Discord identity, then reload /settings. The settings page reads
identities via getUserIdentities() which is a lighter read-only call that
doesn't re-run authentication validation logic. This pattern avoids the
GoTrue schema error entirely while still testing the full Disconnect →
Connect round-trip.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… invalidation (PP-e20)

Raw SQL inserts into auth.identities invalidate the GoTrue session during
middleware updateSession on every Next.js request. The test cannot pass until
a GoTrue-native admin identity linking API is available.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-review PR passed CI and has no unresolved review comments

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants