Skip to content

feat(next): multi-wallet login flow with two-step UI and Synpress E2E#96

Merged
gaboesquivel merged 6 commits intomainfrom
auth-wallet
Feb 17, 2026
Merged

feat(next): multi-wallet login flow with two-step UI and Synpress E2E#96
gaboesquivel merged 6 commits intomainfrom
auth-wallet

Conversation

@gaboesquivel
Copy link
Copy Markdown
Member

@gaboesquivel gaboesquivel commented Feb 15, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Added wallet-based authentication with MetaMask and Solana/Phantom support
    • Consolidated dashboard to home page (root path) with wallet and email linking options
    • New wallet login interface alongside magic link authentication
  • Bug Fixes & Improvements

    • Updated authentication flow to use root path for post-login navigation
    • Improved login page UI with streamlined wallet options
    • Enhanced dashboard with API health status and session information

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 15, 2026

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

Project Deployment Actions Updated (UTC)
basilic-docs Ready Ready Preview, Comment Feb 17, 2026 1:27am
basilic-fastify Ready Ready Preview, Comment Feb 17, 2026 1:27am
basilic-next Ready Ready Preview, Comment Feb 17, 2026 1:27am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 15, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The PR consolidates the dashboard to the root path, integrates wallet authentication flows for MetaMask and Solana using Synpress, refactors the login UI with wallet options, redirects /dashboard to /, and updates all E2E tests and documentation to reflect root-based navigation.

Changes

Cohort / File(s) Summary
Dashboard consolidation
apps/next/app/dashboard/page.tsx, apps/next/next.config.mjs
Removes /dashboard page entirely and adds permanent redirect from /dashboard to / in Next.js config.
Login UI refactoring
apps/next/app/login/page.tsx, apps/next/components/login/login-actions-client.tsx, apps/next/components/login/login-actions.tsx, apps/next/components/login/wallet-options-view.tsx
Introduces new LoginActionsClient wrapper and self-contained LoginActions component with wallet options view, replacing WalletSignInButtons-based UI in login page.
Root page dashboard
apps/next/app/page.tsx, apps/next/components/dashboard/dashboard-wallet-content.tsx
Replaces DashboardContent with DashboardWalletContent on root page; expands dashboard layout with header controls, badge components, and restructured wallet/email linking sections.
Provider and wallet integration
apps/next/components/providers.tsx, apps/next/components/wallet-sign-in-buttons.tsx
Adds Solana wallet adapter to providers, updates auth callback URL to root, exports WalletSignInRow, and adds programmatic MetaMask connection support via injected connector.
Synpress wallet setup
apps/next/e2e/wallet-setup/metamask.setup.ts, apps/next/e2e/wallet-setup/phantom.setup.ts
Introduces wallet setup scripts for automated MetaMask and Phantom provisioning with seed phrases for E2E tests.
E2E wallet auth specs
apps/next/e2e/wallet-metamask-auth.spec.ts, apps/next/e2e/wallet-solana-auth.spec.ts, apps/next/e2e/wallet-auth.spec.ts
Adds new MetaMask and Solana auth E2E tests; updates existing wallet-auth to verify both wallet login and magic link flows, with root-based navigation.
E2E magic-link and wallet-link tests
apps/next/e2e/magic-link-auth.spec.ts, apps/next/e2e/link-wallet.spec.ts, apps/next/e2e/link-email.spec.ts
Updates navigation targets from /dashboard to /, changes error assertions from field-specific to alert-based display, and adjusts post-auth UI expectations.
E2E wallet mock fixtures
apps/next/e2e/fixtures-wallet-mock.ts, apps/next/e2e/fixtures-solana-mock.ts
Adds deterministic wallet and Solana mock fixtures for testing without real wallet interactions; includes mock keypair generation and browser-injected Phantom/Solana APIs.
Test infrastructure config
apps/next/playwright.config.ts, apps/next/scripts/run-e2e-local.mjs, apps/next/scripts/run-e2e.mjs
Adds wallet-metamask and wallet-solana projects to Playwright config; updates run-e2e scripts to default wallet projects and workers when not specified.
ESLint and Biome config
apps/next/eslint.config.js, biome.json
Expands ESLint ignore patterns for Synpress/Playwright caches; updates Biome schema to 2.4.0 and adds new ignore patterns for wallet setup and test artifacts.
Package dependencies
apps/next/package.json, package.json
Adds Synpress, wallet-mock, and tweetnacl devDependencies; updates biome, eslint, and turbo versions; adds pnpm overrides and workspaces config; adds Synpress scripts (synpress:metamask, synpress:phantom, synpress:build).
Documentation updates
apps/docu/content/docs/architecture/authentication.mdx, apps/docu/content/docs/architecture/frontend-stack.mdx, apps/docu/content/docs/testing/e2e-testing.mdx, apps/docu/content/docs/testing/frontend-testing.mdx
Updates SSR request path diagram, documents root-based post-login home, details new MetaMask/Solana wallet specs with mocks, reflects root-based navigation flows, and updates troubleshooting notes.
Ignore and security config
.gitignore, .gitleaks.toml, osv-scanner.toml
Adds Synpress/Cypress cache entries to .gitignore; allowlists wallet-setup files in gitleaks; adds multiple transitive dev-only vulnerability overrides.
Test badge infrastructure
apps/next/components/api-health-badge.tsx, apps/next/e2e/badges.spec.ts
Adds data-testid attribute to API health badge for testing; updates badge test assertions to use data-testid checks instead of text matching.
E2E docs and script
.cursor/rules/frontend/e2e-playwright.mdc, .github/scripts/wait-vercel-deployment.sh
Updates E2E session model documentation with wallet auth exceptions; adds 5-minute pre-deployment wait.
Package manifest and OpenAPI
package.json (root), apps/fastify/openapi/openapi.json
Consolidates pnpm overrides and adds workspaces field; reformats OpenAPI JSON arrays for consistency without semantic changes.
Hook documentation
packages/react/src/hooks/use-magic-link.ts, packages/react/src/components/login-form.spec.tsx
Updates example callbackUrl in documentation and test fixtures from /dashboard to /.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant LoginPage as Login Page
    participant LoginActions as LoginActions
    participant WalletOptions as WalletOptionsView
    participant Connector as Wallet Connector

    User->>LoginPage: Navigate to /login
    LoginPage->>LoginActions: Render with initialError
    LoginActions->>LoginActions: Show initial panel
    User->>LoginActions: Click "Wallet Login"
    LoginActions->>WalletOptions: showWalletOptions = true
    WalletOptions->>WalletOptions: Render wallet options
    User->>WalletOptions: Click "Connect MetaMask"
    WalletOptions->>Connector: useConnect() for injected
    Connector->>Connector: Connect to MetaMask
    User->>Connector: Sign transaction
    Connector->>LoginPage: Redirect with auth token
    LoginPage->>User: Redirect to / (root)
Loading
sequenceDiagram
    actor Test
    participant Playwright as Playwright
    participant Synpress as Synpress
    participant MetaMask as MetaMask
    participant App as Next.js App

    Test->>Playwright: Load metamask.setup.ts
    Playwright->>Synpress: Initialize Synpress helper
    Synpress->>MetaMask: Get extension ID & context
    Synpress->>MetaMask: Import seed phrase
    MetaMask->>Synpress: Wallet initialized
    Test->>App: Navigate to /login
    App->>Test: Render login page
    Test->>App: Click wallet login → Connect MetaMask
    App->>MetaMask: Initiate connection
    MetaMask->>Synpress: Handle connection request
    Test->>MetaMask: Confirm signature
    MetaMask->>App: Return signed message
    App->>Test: Redirect to / with auth
    Test->>Test: Assert URL/UI state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • feat(next): login with wallet #92: Implements wallet-based login, dashboard wallet UI, and introduces Synpress E2E wallet specs and fixtures—directly overlaps with core wallet authentication and testing infrastructure changes.
  • chore: improve e2e tests #86: Modifies Playwright E2E infrastructure, test session model, and authentication flow documentation—shares E2E config and session model updates.
  • chore: update e2e testing strategy #87: Updates E2E testing strategy including Playwright config, run-e2e scripts, and test fixtures—directly related to test infrastructure changes in this PR.

Poem

🐰 The dashboard dances now upon the root,
Wallets wake with MetaMask and Phantom's boot,
From /dashboard gone, all roads lead home,
To / where users freely roam,
With Synpress mocks and fixtures bright,
Our tests shall pass from morn to night! 🎭✨

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main changes: introducing a multi-wallet login flow with a two-step UI component and adding Synpress E2E testing for wallet authentication.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch auth-wallet

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @.gitignore:
- Line 24: Update the .gitignore entry for the Synpress cache to use a trailing
slash by replacing or changing ".cache-synpress" to ".cache-synpress/" and add
Cypress artifact directories to ignore if applicable: "cypress/screenshots/",
"cypress/videos/", and "cypress/downloads/"; ensure you check synpress.json for
any custom Cypress output folders and add those paths as well so test artifacts
aren’t committed.

In @.gitleaks.toml:
- Line 13: The current allowlist entry
'''apps/next/e2e/wallet-setup/.*\.(ts|js|mjs)$''' is too broad and disables all
gitleaks rules for that directory; replace it with a targeted allowlist that
matches only the known, safe test secrets used by Synpress (e.g., explicit
regexes for the test seed phrase and test private key values) or remove the
allowlist entirely and instead add explicit exceptions for specific harmless
constants; update the .gitleaks.toml entry by removing the directory-wide regex
and adding narrowly scoped regex patterns that exactly match the test values you
intend to permit so real secrets remain detectable.

In `@apps/next/components/wallet-sign-in-buttons.tsx`:
- Line 60: The current onConnect handler in wallet-sign-in-buttons.tsx (and the
similar handler in wallet-options-view.tsx) silently no-ops when the injected
connector is undefined; update the UI to avoid a confusing button state by
disabling the "Connect MetaMask" button (e.g., add disabled={!injected}) and/or
show feedback when clicked with no injected wallet (e.g., show a tooltip or call
the existing connect error handler or a toast). Ensure you update the onConnect
callback associated with connect({ connector: injected }) to only call connect
when injected is defined (guard injected before invoking) and add the UI
disabled state so users cannot attempt to connect when no injected connector
exists.
🧹 Nitpick comments (7)
osv-scanner.toml (1)

6-27: Add ignoreUntil dates to these suppressions to ensure periodic reassessment.

These vulnerabilities in transitive dev dependencies (axios, glob, ws, tsup from Synpress E2E tooling) are appropriately ignored for now, but without an expiry date they risk being forgotten indefinitely. Setting ignoreUntil to a future date (e.g., 3–6 months out) ensures they are revisited and removed once upstream patches become available or the dependencies are upgraded.

Example with `ignoreUntil`
[[IgnoredVulns]]
id = "GHSA-43fc-jf86-j433"
reason = "Transitive (axios) from Synpress E2E, dev only"
ignoreUntil = "2026-08-01"

Apply similarly to all 7 entries.

apps/next/components/wallet-sign-in-buttons.tsx (1)

45-61: Significant duplication with wallet-options-view.tsx.

WalletSignInButtons (lines 45–61) and WalletOptionsView (wallet-options-view.tsx lines 10–49) share nearly identical hook setup: useWallet('eip155'), useWallet('solana'), useChainId(), useConnect(), useWalletModal(), and the same injected-connector lookup. Consider extracting this shared wallet-connection logic into a custom hook (e.g., useWalletConnectors) to keep both components DRY.

apps/next/scripts/run-e2e-local.mjs (1)

130-143: Synpress build triggers unnecessarily when running non-wallet projects.

The condition !pwArgs.some(a => a.startsWith('--project=')) means that passing any args without an explicit --project= flag (e.g., --grep "magic-link") will trigger the Synpress build. This adds unnecessary build time when running only non-wallet specs.

Consider tightening the condition, for example by also checking whether any wallet spec file is explicitly targeted:

♻️ Suggested refinement
  const runWalletSpecs =
-    !pwArgs.some(a => a.startsWith('--project=')) ||
-    pwArgs.some(a => a.includes('wallet-metamask') || a.includes('wallet-solana'))
+    pwArgs.some(a => a.includes('wallet-metamask') || a.includes('wallet-solana')) ||
+    !pwArgs.some(a => a.startsWith('--project'))

This reorders the check so the explicit wallet match is evaluated first, but the fundamental behavior is the same — you may want to skip the build entirely when a non-wallet --project is specified (regardless of = vs space separator).

apps/next/components/login/login-actions.tsx (1)

42-70: Both view panels are always mounted — wallet hooks run even on initial view.

Since both panels are rendered simultaneously (hidden via CSS), all wallet-related hooks in WalletOptionsView (useConnect, useWallet, etc.) execute even when the user is on the initial login form. This is fine for a smooth transition UX, but worth noting for awareness — if those hooks trigger network requests or side effects, they'll fire immediately on mount.

If this becomes a concern, lazy-mounting the wallet panel (e.g., {showWalletOptions && <WalletOptionsView ... />}) would defer those hooks, at the cost of losing the CSS transition.

apps/next/e2e/wallet-auth.spec.ts (1)

18-33: Redundant page.goto('/') after waitForURL already confirmed navigation to /.

Line 27 waits for the URL to be /, then Line 29 navigates to / again. This is a no-op but adds unnecessary latency.

♻️ Remove redundant navigation
     await authHelpers.verifyMagicLink(page, token)
     await page.waitForURL(url => url.pathname === '/' || url.pathname === '', { timeout: 5000 })
 
-    await page.goto('/')
     await expect(page.getByRole('heading', { name: /dashboard/i })).toBeVisible()
apps/next/components/dashboard/dashboard-wallet-content.tsx (1)

139-165: UX: No explicit MetaMask connect button in the "Link wallet" section.

When no wallet is connected (Line 140), the UI shows a Solana connect button but only a text hint for MetaMask ("or connect MetaMask for EVM"). Users may not know how to connect MetaMask without an explicit button. If MetaMask connection is handled via auto-injection from wagmi, consider adding a brief tooltip or instruction.

apps/next/e2e/wallet-solana-auth.spec.ts (1)

17-17: Consider a stricter URL assertion to avoid false positives.

The regex /\/(\?.*)?$/ would also match URLs like /login/ or /some-path/. Since you're verifying a redirect to root specifically, consider using the same pattern as in wallet-auth.spec.ts Line 27:

-  await expect(page).toHaveURL(/\/(\?.*)?$/)
+  await page.waitForURL(url => url.pathname === '/' || url.pathname === '', { timeout: 5000 })

This explicitly validates the pathname rather than relying on a regex against the full URL.

Comment thread .gitignore Outdated
Comment thread .gitleaks.toml
Comment thread apps/next/components/wallet-sign-in-buttons.tsx Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.cursor/rules/frontend/e2e-playwright.mdc (1)

13-13: ⚠️ Potential issue | 🟡 Minor

Stale project list — missing the two new wallet projects.

This line still describes only auth and chromium projects. It should also mention wallet-metamask and wallet-solana to match the updated playwright.config.ts.

✏️ Suggested update
-- projects: auth first (`magic-link-auth.spec.ts`), chromium second (all other specs including `wallet-auth.spec.ts`, `link-wallet.spec.ts`, `link-email.spec.ts`)
+- projects: auth first (`magic-link-auth.spec.ts`), wallet-metamask and wallet-solana (Synpress-based real-wallet specs), chromium last (all remaining specs; ignores auth and wallet specs)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/rules/frontend/e2e-playwright.mdc at line 13, Update the stale
projects list line that currently mentions only "auth" and "chromium" to also
include the two new wallet projects ("wallet-metamask" and "wallet-solana") so
the documentation matches the updated playwright.config.ts; locate the line
describing projects (the sentence starting with "projects: auth first...") and
append or insert the wallet-metamask and wallet-solana entries in the same
style/order as the existing projects.
🤖 Fix all issues with AI agents
Verify each finding against the current code and only fix it if needed.


In @.cursor/rules/frontend/e2e-playwright.mdc:
- Line 13: Update the stale projects list line that currently mentions only
"auth" and "chromium" to also include the two new wallet projects
("wallet-metamask" and "wallet-solana") so the documentation matches the updated
playwright.config.ts; locate the line describing projects (the sentence starting
with "projects: auth first...") and append or insert the wallet-metamask and
wallet-solana entries in the same style/order as the existing projects.

In @.github/workflows/next-e2e-test.yml:
- Around line 105-118: Add an id to the cache step (e.g., id: cache-synpress)
and guard the "Build Synpress wallet cache" step so it only runs when the cache
was missed; update its if condition to include &&
steps.cache-synpress.outputs.cache-hit != 'true' while keeping the existing
deployment and filter guards. Reference the step named "Cache Synpress wallet"
to add the id and the step named "Build Synpress wallet cache" to change the if
condition.
- Line 118: The CI step currently appends "|| true" to the xvfb-run
--auto-servernum pnpm --filter `@repo/next` synpress:phantom command which hides
Phantom setup failures; remove the "|| true" and instead handle failures
explicitly by capturing the command exit code (e.g., run the command, check $?
or use shell conditional), and if it fails either fail the job or echo a clear
warning message with the exit code and context (so the failure is visible in CI
logs) before deciding to continue; update the step that runs "xvfb-run
--auto-servernum pnpm --filter `@repo/next` synpress:phantom" accordingly.

In `@apps/docu/content/docs/testing/e2e-testing.mdx`:
- Around line 150-163: Replace the ambiguous parenthetical "(seed: standard test
phrase)" with an explicit reference to the Synpress/BIP-39 test mnemonic so
readers know it’s not a project secret; update the sentence near the wallet
setup filenames (e2e/wallet-setup/metamask.setup.ts,
e2e/wallet-setup/phantom.setup.ts) to say something like "(seed: the Synpress
default BIP-39 test mnemonic, e.g. the well-known 'test test test test test test
test test test test test junk')" so it clearly identifies the public test
phrase.

In `@apps/next/e2e/badges.spec.ts`:
- Around line 36-46: The test "should show both badges side by side on login
page" mixes locator styles: replace the inconsistent use of
page.locator('text=Signed Out') or page.getByText('Signed Out') so both
assertions use the same API; pick one (e.g., change page.locator('text=Signed
Out') to page.getByText('Signed Out') or vice versa) so the assertions in that
test consistently reference the same locator method.

In `@apps/next/scripts/run-e2e-local.mjs`:
- Line 140: The DISPLAY check is inconsistent: `const synpressNeedsXvfb =
process.platform === 'linux' && !env.DISPLAY` uses the merged `env` object while
later code checks `process.env.DISPLAY`, causing divergence if `.env.test`
defines DISPLAY; make the checks consistent by using the same source (preferably
`env.DISPLAY`) everywhere—update the later DISPLAY checks (the Playwright/xvfb
decision code that currently reads `process.env.DISPLAY`) to read `env.DISPLAY`
so both `synpressNeedsXvfb` and the Playwright run use the same environment
values.
- Around line 142-158: The used pattern of conditionally prefixing commands with
xvfb-run is duplicated across metamaskCmd/metamaskArgs, phantomCmd/phantomArgs
and the Playwright run invocation; create a small helper (e.g., wrapWithXvfb or
buildXvfbCommand) that takes the base command and args plus the boolean
synpressNeedsXvfb and returns the proper cmd and args tuple, then replace the
metamaskCmd/metamaskArgs, phantomCmd/phantomArgs and the Playwright spawnSync
call to use that helper (ensure spawnSync is still called with cwd, env, stdio
as before).
- Around line 128-138: pwArgs is being mutated with .push(), making flow hard to
follow; instead compute the final args immutably: keep the initial pwArgs
creation in the pwArgs variable (from userArgs/hasWorkers) and then derive a new
finalPwArgs (used later) by conditionally concatenating the extra project flags
when (!hasProjectArg && skipWalletE2E) is true. Reference pwArgs, hasProjectArg,
skipWalletE2E (and runWalletSpecs if helpful) and replace the in-place
pwArgs.push(...) with an immutable assignment that produces finalPwArgs without
mutating pwArgs.

In `@apps/next/scripts/run-e2e.mjs`:
- Around line 42-43: runWalletSpecs currently defaults to true when no --project
flag is passed (via the rest array), causing xvfb and --workers=1 to run
unnecessarily; change the logic so runWalletSpecs is true only if an explicit
indicator is present or wallet spec files exist: check for an explicit flag like
'--wallet' in rest or detect wallet tests by scanning the filesystem for wallet
spec patterns (e.g., using a glob for "*wallet*.spec.*") and set runWalletSpecs
based on that detection, leaving it false when neither an explicit flag nor
matching files are found; update any code that relies on runWalletSpecs (the
variable named runWalletSpecs and the subsequent xvfb/--workers handling) to use
this new condition.
🧹 Nitpick comments (7)
🤖 Fix all nitpicks with AI agents
Verify each finding against the current code and only fix it if needed.


In @.github/workflows/next-e2e-test.yml:
- Around line 105-118: Add an id to the cache step (e.g., id: cache-synpress)
and guard the "Build Synpress wallet cache" step so it only runs when the cache
was missed; update its if condition to include &&
steps.cache-synpress.outputs.cache-hit != 'true' while keeping the existing
deployment and filter guards. Reference the step named "Cache Synpress wallet"
to add the id and the step named "Build Synpress wallet cache" to change the if
condition.
- Line 118: The CI step currently appends "|| true" to the xvfb-run
--auto-servernum pnpm --filter `@repo/next` synpress:phantom command which hides
Phantom setup failures; remove the "|| true" and instead handle failures
explicitly by capturing the command exit code (e.g., run the command, check $?
or use shell conditional), and if it fails either fail the job or echo a clear
warning message with the exit code and context (so the failure is visible in CI
logs) before deciding to continue; update the step that runs "xvfb-run
--auto-servernum pnpm --filter `@repo/next` synpress:phantom" accordingly.

In `@apps/docu/content/docs/testing/e2e-testing.mdx`:
- Around line 150-163: Replace the ambiguous parenthetical "(seed: standard test
phrase)" with an explicit reference to the Synpress/BIP-39 test mnemonic so
readers know it’s not a project secret; update the sentence near the wallet
setup filenames (e2e/wallet-setup/metamask.setup.ts,
e2e/wallet-setup/phantom.setup.ts) to say something like "(seed: the Synpress
default BIP-39 test mnemonic, e.g. the well-known 'test test test test test test
test test test test test junk')" so it clearly identifies the public test
phrase.

In `@apps/next/e2e/badges.spec.ts`:
- Around line 36-46: The test "should show both badges side by side on login
page" mixes locator styles: replace the inconsistent use of
page.locator('text=Signed Out') or page.getByText('Signed Out') so both
assertions use the same API; pick one (e.g., change page.locator('text=Signed
Out') to page.getByText('Signed Out') or vice versa) so the assertions in that
test consistently reference the same locator method.

In `@apps/next/scripts/run-e2e-local.mjs`:
- Around line 142-158: The used pattern of conditionally prefixing commands with
xvfb-run is duplicated across metamaskCmd/metamaskArgs, phantomCmd/phantomArgs
and the Playwright run invocation; create a small helper (e.g., wrapWithXvfb or
buildXvfbCommand) that takes the base command and args plus the boolean
synpressNeedsXvfb and returns the proper cmd and args tuple, then replace the
metamaskCmd/metamaskArgs, phantomCmd/phantomArgs and the Playwright spawnSync
call to use that helper (ensure spawnSync is still called with cwd, env, stdio
as before).
- Around line 128-138: pwArgs is being mutated with .push(), making flow hard to
follow; instead compute the final args immutably: keep the initial pwArgs
creation in the pwArgs variable (from userArgs/hasWorkers) and then derive a new
finalPwArgs (used later) by conditionally concatenating the extra project flags
when (!hasProjectArg && skipWalletE2E) is true. Reference pwArgs, hasProjectArg,
skipWalletE2E (and runWalletSpecs if helpful) and replace the in-place
pwArgs.push(...) with an immutable assignment that produces finalPwArgs without
mutating pwArgs.

In `@apps/next/scripts/run-e2e.mjs`:
- Around line 42-43: runWalletSpecs currently defaults to true when no --project
flag is passed (via the rest array), causing xvfb and --workers=1 to run
unnecessarily; change the logic so runWalletSpecs is true only if an explicit
indicator is present or wallet spec files exist: check for an explicit flag like
'--wallet' in rest or detect wallet tests by scanning the filesystem for wallet
spec patterns (e.g., using a glob for "*wallet*.spec.*") and set runWalletSpecs
based on that detection, leaving it false when neither an explicit flag nor
matching files are found; update any code that relies on runWalletSpecs (the
variable named runWalletSpecs and the subsequent xvfb/--workers handling) to use
this new condition.
apps/next/e2e/badges.spec.ts (1)

36-46: Nit: inconsistent locator style for "Signed Out" within the same test group.

Line 36 uses page.locator('text=Signed Out') while line 46 uses page.getByText('Signed Out'). Both work, but picking one style consistently improves readability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/e2e/badges.spec.ts` around lines 36 - 46, The test "should show
both badges side by side on login page" mixes locator styles: replace the
inconsistent use of page.locator('text=Signed Out') or page.getByText('Signed
Out') so both assertions use the same API; pick one (e.g., change
page.locator('text=Signed Out') to page.getByText('Signed Out') or vice versa)
so the assertions in that test consistently reference the same locator method.
.github/workflows/next-e2e-test.yml (2)

105-118: Skip the wallet build when the cache is already warm.

The cache step has no id, so the build step (Line 117-118) runs unconditionally — even on a cache hit. Add an id and gate the build on a cache miss to save CI minutes.

♻️ Proposed fix
       - name: Cache Synpress wallet
         if: steps.filter.outputs.next == 'true' && steps.wait-app.outputs.deployment_url_app != '' && steps.wait-api.outputs.deployment_url_api != ''
+        id: synpress-cache
         uses: actions/cache@v4
         with:
           path: apps/next/.cache-synpress
           key: synpress-${{ runner.os }}-${{ hashFiles('apps/next/e2e/wallet-setup/**') }}
           restore-keys: |
             synpress-${{ runner.os }}-

       - name: Build Synpress wallet cache
-        if: steps.filter.outputs.next == 'true' && steps.wait-app.outputs.deployment_url_app != '' && steps.wait-api.outputs.deployment_url_api != ''
+        if: steps.filter.outputs.next == 'true' && steps.wait-app.outputs.deployment_url_app != '' && steps.wait-api.outputs.deployment_url_api != '' && steps.synpress-cache.outputs.cache-hit != 'true'
         run: |
           xvfb-run --auto-servernum pnpm --filter `@repo/next` synpress:metamask
           xvfb-run --auto-servernum pnpm --filter `@repo/next` synpress:phantom || true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/next-e2e-test.yml around lines 105 - 118, Add an id to the
cache step (e.g., id: cache-synpress) and guard the "Build Synpress wallet
cache" step so it only runs when the cache was missed; update its if condition
to include && steps.cache-synpress.outputs.cache-hit != 'true' while keeping the
existing deployment and filter guards. Reference the step named "Cache Synpress
wallet" to add the id and the step named "Build Synpress wallet cache" to change
the if condition.

118-118: || true silently swallows Phantom setup failures.

If Phantom wallet support is experimental, consider at least logging a warning so failures are visible in CI output rather than silently ignored.

-          xvfb-run --auto-servernum pnpm --filter `@repo/next` synpress:phantom || true
+          xvfb-run --auto-servernum pnpm --filter `@repo/next` synpress:phantom || echo "::warning::Phantom wallet cache build failed — skipping"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/next-e2e-test.yml at line 118, The CI step currently
appends "|| true" to the xvfb-run --auto-servernum pnpm --filter `@repo/next`
synpress:phantom command which hides Phantom setup failures; remove the "||
true" and instead handle failures explicitly by capturing the command exit code
(e.g., run the command, check $? or use shell conditional), and if it fails
either fail the job or echo a clear warning message with the exit code and
context (so the failure is visible in CI logs) before deciding to continue;
update the step that runs "xvfb-run --auto-servernum pnpm --filter `@repo/next`
synpress:phantom" accordingly.
apps/docu/content/docs/testing/e2e-testing.mdx (1)

150-163: Minor: clarify "standard test phrase" reference.

Line 161 mentions (seed: standard test phrase) which is ambiguous. Consider specifying that this refers to the Synpress default test mnemonic (e.g., "the well-known test test test... BIP-39 mnemonic") so readers don't confuse it with a project-specific secret.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/docu/content/docs/testing/e2e-testing.mdx` around lines 150 - 163,
Replace the ambiguous parenthetical "(seed: standard test phrase)" with an
explicit reference to the Synpress/BIP-39 test mnemonic so readers know it’s not
a project secret; update the sentence near the wallet setup filenames
(e2e/wallet-setup/metamask.setup.ts, e2e/wallet-setup/phantom.setup.ts) to say
something like "(seed: the Synpress default BIP-39 test mnemonic, e.g. the
well-known 'test test test test test test test test test test test junk')" so it
clearly identifies the public test phrase.
apps/next/scripts/run-e2e-local.mjs (2)

142-158: Extract the xvfb-wrapping pattern into a helper to reduce duplication.

The pattern of conditionally prepending xvfb-run --auto-servernum -- appears three times (MetaMask build, Phantom build, Playwright run). A small helper would reduce duplication and make it easier to adjust the xvfb flags in one place.

Example helper
+function wrapXvfb(cmd, args, needsXvfb) {
+  return needsXvfb
+    ? ['xvfb-run', ['--auto-servernum', '--', cmd, ...args]]
+    : [cmd, args]
+}
+
   // then usage:
-  const metamaskCmd = synpressNeedsXvfb ? 'xvfb-run' : 'pnpm'
-  const metamaskArgs = synpressNeedsXvfb
-    ? ['--auto-servernum', '--', 'pnpm', 'synpress:metamask']
-    : ['synpress:metamask']
+  const [metamaskCmd, metamaskArgs] = wrapXvfb('pnpm', ['synpress:metamask'], synpressNeedsXvfb)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/scripts/run-e2e-local.mjs` around lines 142 - 158, The used pattern
of conditionally prefixing commands with xvfb-run is duplicated across
metamaskCmd/metamaskArgs, phantomCmd/phantomArgs and the Playwright run
invocation; create a small helper (e.g., wrapWithXvfb or buildXvfbCommand) that
takes the base command and args plus the boolean synpressNeedsXvfb and returns
the proper cmd and args tuple, then replace the metamaskCmd/metamaskArgs,
phantomCmd/phantomArgs and the Playwright spawnSync call to use that helper
(ensure spawnSync is still called with cwd, env, stdio as before).

128-138: Mutating pwArgs in-place on Line 138 makes the data flow harder to follow.

pwArgs is built on Line 130, then conditionally mutated via .push() on Line 138, then read again on Lines 172-177 to produce finalPwArgs. Consider building the final args immutably to make the control flow clearer.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/scripts/run-e2e-local.mjs` around lines 128 - 138, pwArgs is being
mutated with .push(), making flow hard to follow; instead compute the final args
immutably: keep the initial pwArgs creation in the pwArgs variable (from
userArgs/hasWorkers) and then derive a new finalPwArgs (used later) by
conditionally concatenating the extra project flags when (!hasProjectArg &&
skipWalletE2E) is true. Reference pwArgs, hasProjectArg, skipWalletE2E (and
runWalletSpecs if helpful) and replace the in-place pwArgs.push(...) with an
immutable assignment that produces finalPwArgs without mutating pwArgs.
apps/next/scripts/run-e2e.mjs (1)

42-43: runWalletSpecs defaults to true when no --project flag is passed — verify this is intentional.

When a user runs the script without any --project= argument, runWalletSpecs evaluates to true (first disjunct). This means the xvfb wrapper and --workers=1 default kick in even for plain pnpm run-e2e.mjs invocations that may not involve wallet tests at all. If only the Playwright config's testMatch determines which projects actually run, this is fine—but the xvfb overhead and single-worker default may slow down non-wallet runs unnecessarily.

Consider gating on the presence of wallet spec files or an explicit flag rather than defaulting to true.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/scripts/run-e2e.mjs` around lines 42 - 43, runWalletSpecs currently
defaults to true when no --project flag is passed (via the rest array), causing
xvfb and --workers=1 to run unnecessarily; change the logic so runWalletSpecs is
true only if an explicit indicator is present or wallet spec files exist: check
for an explicit flag like '--wallet' in rest or detect wallet tests by scanning
the filesystem for wallet spec patterns (e.g., using a glob for
"*wallet*.spec.*") and set runWalletSpecs based on that detection, leaving it
false when neither an explicit flag nor matching files are found; update any
code that relies on runWalletSpecs (the variable named runWalletSpecs and the
subsequent xvfb/--workers handling) to use this new condition.

Comment thread apps/next/scripts/run-e2e-local.mjs Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/docu/content/docs/testing/e2e-testing.mdx (1)

88-100: ⚠️ Potential issue | 🟡 Minor

Section header and intro at line 90 don't account for the new wallet-project specs.

Line 90 states: "Wallet-related specs run in the chromium project." However, wallet-metamask-auth.spec.ts (line 99) and wallet-solana-auth.spec.ts (line 100) run in their own dedicated wallet-metamask and wallet-solana projects respectively, not in chromium. The current wording is misleading — only wallet-auth.spec.ts, link-wallet.spec.ts, and link-email.spec.ts run in chromium.

Consider updating the intro paragraph to clarify the project assignment, e.g.:

Proposed fix
-Wallet-related specs run in the **chromium** project (after the auth project). They use `authHelpers.sendMagicLink` and `authHelpers.verifyMagicLink` for per-test setup and do **not** use the `authenticatedPage` fixture. No browser extensions required.
+Wallet UI specs (`wallet-auth`, `link-wallet`, `link-email`) run in the **chromium** project (after the auth project). They use `authHelpers.sendMagicLink` and `authHelpers.verifyMagicLink` for per-test setup and do **not** use the `authenticatedPage` fixture. Full wallet auth specs (`wallet-metamask-auth`, `wallet-solana-auth`) run in their own dedicated projects (**wallet-metamask**, **wallet-solana**) using injected mock providers. No browser extensions required.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/docu/content/docs/testing/e2e-testing.mdx` around lines 88 - 100, Update
the intro paragraph to accurately state which specs run in which Playwright
projects: note that wallet-auth.spec.ts, link-wallet.spec.ts, and
link-email.spec.ts run in the chromium project, while
wallet-metamask-auth.spec.ts runs in the wallet-metamask project and
wallet-solana-auth.spec.ts runs in the wallet-solana project; revise the
sentence that currently reads "Wallet-related specs run in the **chromium**
project" to mention the three chromium specs explicitly and call out the
separate wallet-metamask and wallet-solana projects for the EVM and Solana flows
(also keep the note about using
authHelpers.sendMagicLink/authHelpers.verifyMagicLink and not using the
authenticatedPage fixture).
🤖 Fix all issues with AI agents
Verify each finding against the current code and only fix it if needed.


In @.cursor/rules/frontend/e2e-playwright.mdc:
- Line 13: The term "wallet specs" is ambiguous; update the references in the
doc that group the chromium project specs (wallet-auth.spec.ts,
link-wallet.spec.ts, link-email.spec.ts) and the separate wallet project specs
(wallet-metamask-auth.spec.ts, wallet-solana-auth.spec.ts) to use distinct
labels (e.g., "wallet UI specs" for the chromium magic-link tests and "wallet
auth specs" for the wallet-metamask/wallet-solana mock-auth tests) and add a
one-line clarifying note explaining the difference; ensure you change every
occurrence (the group around
wallet-auth.spec.ts/link-wallet.spec.ts/link-email.spec.ts and the mentions near
wallet-metamask-auth.spec.ts and wallet-solana-auth.spec.ts) and keep the
examples and project references (chromium vs wallet projects) consistent with
the new labels.

In @.github/scripts/wait-vercel-deployment.sh:
- Around line 54-57: Remove the unconditional 5-minute sleep and ensure START is
set before any wait so the timeout includes all elapsed time: delete the
echo/sleep lines or make the initial delay configurable (e.g., NEW_ARG or
INITIAL_DELAY) and default to 0, then set START=$(date +%s) before entering the
polling loop and compute TIMEOUT_SEC=$((TIMEOUT_MIN * 60)) as before; update any
references to the initial sleep to use the new variable (or remove them) so the
polling loop alone controls waits and the total duration is correctly bounded by
TIMEOUT_SEC.

In `@apps/docu/content/docs/testing/e2e-testing.mdx`:
- Around line 88-100: Update the intro paragraph to accurately state which specs
run in which Playwright projects: note that wallet-auth.spec.ts,
link-wallet.spec.ts, and link-email.spec.ts run in the chromium project, while
wallet-metamask-auth.spec.ts runs in the wallet-metamask project and
wallet-solana-auth.spec.ts runs in the wallet-solana project; revise the
sentence that currently reads "Wallet-related specs run in the **chromium**
project" to mention the three chromium specs explicitly and call out the
separate wallet-metamask and wallet-solana projects for the EVM and Solana flows
(also keep the note about using
authHelpers.sendMagicLink/authHelpers.verifyMagicLink and not using the
authenticatedPage fixture).

In `@apps/next/e2e/fixtures-solana-mock.ts`:
- Around line 24-54: The mock's event methods (mock.on, mock.off, mock.emit,
removeListener) are no-ops while connect() calls mock.emit('connect',
publicKey), so listeners never fire; implement a minimal event emitter in the
fixture: store handlers in a Map keyed by event name when
mock.on/removeListener/off are called, remove handlers appropriately, and invoke
those handlers with the provided args from mock.emit (ensure connect() triggers
the stored 'connect' handlers); update signaled symbols: mock.on, mock.off,
mock.removeListener, mock.emit, and connect to use this handler storage so tests
relying on window.solana.on('connect', ...) work.

In `@apps/next/e2e/wallet-metamask-auth.spec.ts`:
- Around line 12-15: Replace the direct DOM invocation evaluate(el =>
el.click()) with Playwright's native click() on the Playwright locators (e.g.,
use connectBtn.click() and signInBtn.click()) so actionability checks and
auto-waiting are preserved; if flakiness was the reason for using evaluate, add
an explicit wait for the mock wallet readiness (e.g., waitForSelector or
waitForFunction) before calling connectBtn.click() to ensure the wallet
injection timing is handled and avoid bypassing Playwright's checks.

In `@apps/next/package.json`:
- Around line 37-39: The synpress wallet setup scripts ("synpress:metamask",
"synpress:phantom", "synpress:build") and the setup files
(e2e/wallet-setup/metamask.setup.ts, phantom.setup.ts) are orphaned because
playwright.config.ts and the wallet tests still use mock fixtures
(fixtures-wallet-mock, fixtures-solana-mock); either integrate these setup files
into the test config or remove them and update package.json/docs. To fix: decide
which approach to keep; if keeping synpress, add references to the setup files
in playwright.config.ts (e.g., add projects or globalSetup entries that point to
e2e/wallet-setup/metamask.setup.ts and phantom.setup.ts and switch tests to use
those projects instead of fixtures-wallet-mock/fixtures-solana-mock), update
test invocations to call the corresponding npm scripts, and document usage in
the README; if removing, delete the two setup files and remove the three scripts
from package.json and any README mentions so there are no unused artifacts.

In `@apps/next/scripts/run-e2e-local.mjs`:
- Around line 128-146: The project default flags are appended after userArgs in
this script (see userArgs, pwArgs, finalPwArgs) which differs from run-e2e.mjs;
change the assembly so the project defaults are inserted before the user's
remaining args (i.e., build finalPwArgs as [...workers/projectArgs, ...userArgs]
like run-e2e.mjs) to make argument ordering consistent across scripts while
preserving the existing hasProjectArg and hasWorkers checks.

In `@package.json`:
- Around line 56-77: The top-level "overrides" object must be moved under the
existing "pnpm" object so pnpm v10 will apply them; move the entire overrides
block (the keys for eslint, `@eslint/js`, tmp, js-yaml, diff, bigint-buffer, tar,
`@isaacs/brace-expansion`, esbuild, path-to-regexp, undici, next, lodash,
lodash-es) into a new "overrides" property nested inside the existing "pnpm"
object (which already contains "onlyBuiltDependencies"), remove the top-level
"overrides" entry, and ensure there are no duplicate keys so pnpm.overrides is
the single source of truth.
- Line 46: Replace the "vercel": "latest" dependency with a pinned semantic
version to ensure reproducible builds; locate the "vercel" entry in package.json
and change its version string from "latest" to a specific release (for example
"29.10.0" or another vetted semver), or use a caret/tilde range if you intend
controlled updates (e.g., "^29.10.0"), and update lockfile by running your
package manager (pnpm install) to commit the deterministic version.
🧹 Nitpick comments (7)
🤖 Fix all nitpicks with AI agents
Verify each finding against the current code and only fix it if needed.


In @.cursor/rules/frontend/e2e-playwright.mdc:
- Line 13: The term "wallet specs" is ambiguous; update the references in the
doc that group the chromium project specs (wallet-auth.spec.ts,
link-wallet.spec.ts, link-email.spec.ts) and the separate wallet project specs
(wallet-metamask-auth.spec.ts, wallet-solana-auth.spec.ts) to use distinct
labels (e.g., "wallet UI specs" for the chromium magic-link tests and "wallet
auth specs" for the wallet-metamask/wallet-solana mock-auth tests) and add a
one-line clarifying note explaining the difference; ensure you change every
occurrence (the group around
wallet-auth.spec.ts/link-wallet.spec.ts/link-email.spec.ts and the mentions near
wallet-metamask-auth.spec.ts and wallet-solana-auth.spec.ts) and keep the
examples and project references (chromium vs wallet projects) consistent with
the new labels.

In @.github/scripts/wait-vercel-deployment.sh:
- Around line 54-57: Remove the unconditional 5-minute sleep and ensure START is
set before any wait so the timeout includes all elapsed time: delete the
echo/sleep lines or make the initial delay configurable (e.g., NEW_ARG or
INITIAL_DELAY) and default to 0, then set START=$(date +%s) before entering the
polling loop and compute TIMEOUT_SEC=$((TIMEOUT_MIN * 60)) as before; update any
references to the initial sleep to use the new variable (or remove them) so the
polling loop alone controls waits and the total duration is correctly bounded by
TIMEOUT_SEC.

In `@apps/next/e2e/fixtures-solana-mock.ts`:
- Around line 24-54: The mock's event methods (mock.on, mock.off, mock.emit,
removeListener) are no-ops while connect() calls mock.emit('connect',
publicKey), so listeners never fire; implement a minimal event emitter in the
fixture: store handlers in a Map keyed by event name when
mock.on/removeListener/off are called, remove handlers appropriately, and invoke
those handlers with the provided args from mock.emit (ensure connect() triggers
the stored 'connect' handlers); update signaled symbols: mock.on, mock.off,
mock.removeListener, mock.emit, and connect to use this handler storage so tests
relying on window.solana.on('connect', ...) work.

In `@apps/next/e2e/wallet-metamask-auth.spec.ts`:
- Around line 12-15: Replace the direct DOM invocation evaluate(el =>
el.click()) with Playwright's native click() on the Playwright locators (e.g.,
use connectBtn.click() and signInBtn.click()) so actionability checks and
auto-waiting are preserved; if flakiness was the reason for using evaluate, add
an explicit wait for the mock wallet readiness (e.g., waitForSelector or
waitForFunction) before calling connectBtn.click() to ensure the wallet
injection timing is handled and avoid bypassing Playwright's checks.

In `@apps/next/package.json`:
- Around line 37-39: The synpress wallet setup scripts ("synpress:metamask",
"synpress:phantom", "synpress:build") and the setup files
(e2e/wallet-setup/metamask.setup.ts, phantom.setup.ts) are orphaned because
playwright.config.ts and the wallet tests still use mock fixtures
(fixtures-wallet-mock, fixtures-solana-mock); either integrate these setup files
into the test config or remove them and update package.json/docs. To fix: decide
which approach to keep; if keeping synpress, add references to the setup files
in playwright.config.ts (e.g., add projects or globalSetup entries that point to
e2e/wallet-setup/metamask.setup.ts and phantom.setup.ts and switch tests to use
those projects instead of fixtures-wallet-mock/fixtures-solana-mock), update
test invocations to call the corresponding npm scripts, and document usage in
the README; if removing, delete the two setup files and remove the three scripts
from package.json and any README mentions so there are no unused artifacts.

In `@apps/next/scripts/run-e2e-local.mjs`:
- Around line 128-146: The project default flags are appended after userArgs in
this script (see userArgs, pwArgs, finalPwArgs) which differs from run-e2e.mjs;
change the assembly so the project defaults are inserted before the user's
remaining args (i.e., build finalPwArgs as [...workers/projectArgs, ...userArgs]
like run-e2e.mjs) to make argument ordering consistent across scripts while
preserving the existing hasProjectArg and hasWorkers checks.

In `@package.json`:
- Line 46: Replace the "vercel": "latest" dependency with a pinned semantic
version to ensure reproducible builds; locate the "vercel" entry in package.json
and change its version string from "latest" to a specific release (for example
"29.10.0" or another vetted semver), or use a caret/tilde range if you intend
controlled updates (e.g., "^29.10.0"), and update lockfile by running your
package manager (pnpm install) to commit the deterministic version.
.github/scripts/wait-vercel-deployment.sh (1)

54-57: Unconditional 5-minute sleep wastes CI time and isn't counted toward the timeout.

Two concerns:

  1. Wasted time: The existing polling loop already handles "no deployment yet" gracefully. If Vercel happens to be ready in 2 minutes, you still wait 5. This adds ~5 min to every CI run unconditionally.
  2. Hidden total duration: START is set after the sleep (line 56), so the 5-min delay is invisible to the 18-min timeout. Worst case is 23 minutes of wall-clock time, which may surprise maintainers and could hit CI job-level timeouts.

Consider either making the initial delay configurable (e.g., a 4th argument) or simply removing it and relying on the poll loop, perhaps with a longer initial poll interval.

♻️ Option: make the initial delay configurable with a sensible default
 PROJECT_NAME="${1:?project name required}"
 TIMEOUT_MIN="${2:-18}"
 [[ -n "${3:-}" ]] && OUTPUT_KEY="deployment_url_$3" || OUTPUT_KEY="deployment_url"
-POLL_SEC=45
+INITIAL_DELAY="${4:-0}"
+POLL_SEC=45
 API_BASE="https://api.vercel.com"
 echo "::group::Waiting for Vercel deployment (${PROJECT_NAME} @ ${GITHUB_SHA})"
-echo "Waiting 5min for Vercel to start build..."
-sleep 300
+if [[ "$INITIAL_DELAY" -gt 0 ]]; then
+  echo "Waiting ${INITIAL_DELAY}s for Vercel to start build..."
+  sleep "$INITIAL_DELAY"
+fi
 START=$(date +%s)
 TIMEOUT_SEC=$((TIMEOUT_MIN * 60))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/scripts/wait-vercel-deployment.sh around lines 54 - 57, Remove the
unconditional 5-minute sleep and ensure START is set before any wait so the
timeout includes all elapsed time: delete the echo/sleep lines or make the
initial delay configurable (e.g., NEW_ARG or INITIAL_DELAY) and default to 0,
then set START=$(date +%s) before entering the polling loop and compute
TIMEOUT_SEC=$((TIMEOUT_MIN * 60)) as before; update any references to the
initial sleep to use the new variable (or remove them) so the polling loop alone
controls waits and the total duration is correctly bounded by TIMEOUT_SEC.
apps/next/e2e/wallet-metamask-auth.spec.ts (1)

12-15: evaluate(el => el.click()) bypasses Playwright's actionability checks.

Lines 12 and 15 use evaluate to click instead of Playwright's native .click(). This skips auto-waiting for the element to be visible, enabled, and stable — which can mask real UI bugs (e.g., overlapping elements, disabled state not clearing). The Solana test (wallet-solana-auth.spec.ts) uses native .click() for equivalent steps.

If this was done to work around flakiness with the mock wallet injection timing, consider adding an explicit wait instead.

Suggested change
-  await connectBtn.evaluate((el: HTMLElement) => el.click())
+  await connectBtn.click()
   const signInBtn = page.getByRole('button', { name: /sign in with ethereum/i })
   await expect(signInBtn).toBeVisible({ timeout: 15_000 })
-  await signInBtn.evaluate((el: HTMLElement) => el.click())
+  await signInBtn.click()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/e2e/wallet-metamask-auth.spec.ts` around lines 12 - 15, Replace the
direct DOM invocation evaluate(el => el.click()) with Playwright's native
click() on the Playwright locators (e.g., use connectBtn.click() and
signInBtn.click()) so actionability checks and auto-waiting are preserved; if
flakiness was the reason for using evaluate, add an explicit wait for the mock
wallet readiness (e.g., waitForSelector or waitForFunction) before calling
connectBtn.click() to ensure the wallet injection timing is handled and avoid
bypassing Playwright's checks.
package.json (1)

46-46: Pin vercel to a specific version for reproducible builds.

Using "latest" means every pnpm install can pull a different version, which can cause CI flakiness and makes builds non-reproducible.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` at line 46, Replace the "vercel": "latest" dependency with a
pinned semantic version to ensure reproducible builds; locate the "vercel" entry
in package.json and change its version string from "latest" to a specific
release (for example "29.10.0" or another vetted semver), or use a caret/tilde
range if you intend controlled updates (e.g., "^29.10.0"), and update lockfile
by running your package manager (pnpm install) to commit the deterministic
version.
apps/next/e2e/fixtures-solana-mock.ts (1)

24-54: Event emitter methods are no-ops — verify the app doesn't rely on on('connect') events.

mock.on, mock.off, and mock.emit are all no-ops, but connect() calls mock.emit('connect', publicKey). If the application code registers listeners via window.solana.on('connect', handler), those handlers will never fire. This is fine if the app only polls isConnected or awaits the connect() promise, but could cause issues if it relies on event-driven connection detection.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/e2e/fixtures-solana-mock.ts` around lines 24 - 54, The mock's event
methods (mock.on, mock.off, mock.emit, removeListener) are no-ops while
connect() calls mock.emit('connect', publicKey), so listeners never fire;
implement a minimal event emitter in the fixture: store handlers in a Map keyed
by event name when mock.on/removeListener/off are called, remove handlers
appropriately, and invoke those handlers with the provided args from mock.emit
(ensure connect() triggers the stored 'connect' handlers); update signaled
symbols: mock.on, mock.off, mock.removeListener, mock.emit, and connect to use
this handler storage so tests relying on window.solana.on('connect', ...) work.
apps/next/scripts/run-e2e-local.mjs (1)

128-146: Argument construction is correct, but project defaults are appended in a different position than run-e2e.mjs.

In run-e2e.mjs (line 46), project args are placed before the user's remaining args:

[...workers, ...projectArgs, ...rest]

Here, project defaults are appended after userArgs (line 132–140). Playwright doesn't care about the ordering of --project flags, so this is functionally equivalent — but the inconsistency between the two scripts could confuse a future maintainer. Consider aligning the argument assembly order for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/scripts/run-e2e-local.mjs` around lines 128 - 146, The project
default flags are appended after userArgs in this script (see userArgs, pwArgs,
finalPwArgs) which differs from run-e2e.mjs; change the assembly so the project
defaults are inserted before the user's remaining args (i.e., build finalPwArgs
as [...workers/projectArgs, ...userArgs] like run-e2e.mjs) to make argument
ordering consistent across scripts while preserving the existing hasProjectArg
and hasWorkers checks.
.cursor/rules/frontend/e2e-playwright.mdc (1)

13-13: The term "wallet specs" is overloaded — consider disambiguating.

Line 13 groups wallet-auth.spec.ts, link-wallet.spec.ts, link-email.spec.ts under the chromium project and calls them out alongside "wallet specs." Lines 19 and 33 also use the label "wallet specs" for these chromium-project specs that authenticate via magic link. Meanwhile, Lines 27–28 introduce wallet-metamask-auth.spec.ts and wallet-solana-auth.spec.ts as separate wallet-project specs with actual wallet mock auth.

Both groups involve "wallets" but have fundamentally different auth mechanisms. A reader unfamiliar with the codebase could confuse them. Consider using distinct labels, e.g., "wallet UI specs" (chromium) vs. "wallet auth specs" (wallet-metamask/wallet-solana), or adding a brief clarifying note.

Also applies to: 19-19, 26-29

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/rules/frontend/e2e-playwright.mdc at line 13, The term "wallet
specs" is ambiguous; update the references in the doc that group the chromium
project specs (wallet-auth.spec.ts, link-wallet.spec.ts, link-email.spec.ts) and
the separate wallet project specs (wallet-metamask-auth.spec.ts,
wallet-solana-auth.spec.ts) to use distinct labels (e.g., "wallet UI specs" for
the chromium magic-link tests and "wallet auth specs" for the
wallet-metamask/wallet-solana mock-auth tests) and add a one-line clarifying
note explaining the difference; ensure you change every occurrence (the group
around wallet-auth.spec.ts/link-wallet.spec.ts/link-email.spec.ts and the
mentions near wallet-metamask-auth.spec.ts and wallet-solana-auth.spec.ts) and
keep the examples and project references (chromium vs wallet projects)
consistent with the new labels.
apps/next/package.json (1)

37-39: Synpress setup files and scripts are defined but not integrated into the test suite.

The synpress:metamask, synpress:phantom, and synpress:build scripts exist in package.json, and the corresponding setup files (e2e/wallet-setup/metamask.setup.ts and e2e/wallet-setup/phantom.setup.ts) are fully implemented with synpress code. However, the wallet auth tests run with mock fixtures instead (fixtures-wallet-mock and fixtures-solana-mock), and the setup files are not referenced in playwright.config.ts.

Either document the purpose of these files and when they should be used, or remove them if they're no longer needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/package.json` around lines 37 - 39, The synpress wallet setup
scripts ("synpress:metamask", "synpress:phantom", "synpress:build") and the
setup files (e2e/wallet-setup/metamask.setup.ts, phantom.setup.ts) are orphaned
because playwright.config.ts and the wallet tests still use mock fixtures
(fixtures-wallet-mock, fixtures-solana-mock); either integrate these setup files
into the test config or remove them and update package.json/docs. To fix: decide
which approach to keep; if keeping synpress, add references to the setup files
in playwright.config.ts (e.g., add projects or globalSetup entries that point to
e2e/wallet-setup/metamask.setup.ts and phantom.setup.ts and switch tests to use
those projects instead of fixtures-wallet-mock/fixtures-solana-mock), update
test invocations to call the corresponding npm scripts, and document usage in
the README; if removing, delete the two setup files and remove the three scripts
from package.json and any README mentions so there are no unused artifacts.

Comment thread package.json
- Add pnpm-workspace overrides for axios, glob, ws (Synpress), esbuild, lodash, lodash-es
- Override vercel>@vercel/blob to 2.2.0 for patched undici in blob path
- Override path-to-regexp to 6.3.0
- Remove undici override (breaks jsdom used by @repo/react tests)
- Set audit-level=high (moderate undici vulns in @vercel/node until upstream fix)
- Restore pnpm audit step in security workflow
- Add osv-scanner ignores for undici (jsdom incompatible) and path-to-regexp
- Update docs: README, scripts/README, security-check.mjs
This was referenced Mar 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant