Skip to content

## test(web): Playwright E2E smoke — deploy, fund, whitelist, pay via injected test signer - #21

Merged
Bekirerdem merged 2 commits into
Bekirerdem:mainfrom
samad13:test
Jul 29, 2026
Merged

## test(web): Playwright E2E smoke — deploy, fund, whitelist, pay via injected test signer#21
Bekirerdem merged 2 commits into
Bekirerdem:mainfrom
samad13:test

Conversation

@samad13

@samad13 samad13 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Context

The web app has an extensive vitest unit-test suite but zero browser-level tests. Regressions in wiring — hash routing, lazy chunks, wallet modal, and the connect → deploy → fund → whitelist → pay happy path — were only caught by hand today.

Scope

  • Playwright in web/ with a minimal config (one project, chromium is enough; auto-starts vite dev server)
  • Injected test signer: Bypasses the real StellarWalletsKit modal by injecting a throwaway testnet key into window.__PRISM_TEST_SIGNER__ via Playwright's addInitScript. The adapter lives at src/lib/walletSigner.ts's seam (walletKit.ts), gating the path behind two checks so it can never leak into production:
    1. VITE_ENABLE_TEST_SIGNER === "true" (compile-time import.meta.env literal — dead code is tree-shaken)
    2. window.__PRISM_TEST_SIGNER__ global is present (Playwright-only)
  • Smoke spec driving the real UI end-to-end: Landing → Workspace → Connect → Deploy treasury → Fund → Whitelist sample payee → Pay within limits → Assert success states
  • GitHub Actions workflow: workflow_dispatch only (manual trigger). Testnet RPC flakiness means it does not gate every PR yet
  • README section in web/ with full run instructions

Acceptance Criteria

Criterion Status Notes
Smoke spec passes locally against testnet with a funded throwaway key ✅ Ready Key derived from PLAYWRIGHT_TEST_WALLET_SECRET; ≥ 25 XLM covers deploy+fund+fee headroom
No secrets in repo — key from env; CI reads from repo secrets ✅ Done PLAYWRIGHT_TEST_WALLET_SECRET env var + secrets.PLAYWRIGHT_TEST_WALLET_SECRET in workflow
Test-signer injection does NOT leak into production ✅ Double-gated Compile-time flag (VITE_ENABLE_TEST_SIGNER) AND runtime global (window.__PRISM_TEST_SIGNER__)
Run instructions documented ✅ Done web/README.mdE2E · Playwright smoke section

Files

New:

  • web/playwright.config.ts — 1 chromium project; dev server starts vite with VITE_ENABLE_TEST_SIGNER=true; retains trace/screenshots/video on failure; 180s timeouts for testnet RPC
  • web/src/lib/testSigner.ts — Injection adapter: validates build flag + runtime global; returns Keypair-backed KitSigner that signs via stellar-sdk directly (no wallet popup)
  • web/tests/e2e/prismTest.tsPrismPage page-object helper + signer/context fixtures (signer, injected init script, typed UI actions)
  • web/tests/e2e/smoke.spec.ts — Serial smoke spec: landing no errors → connect → friendbot → deploy 50/10 → fund 20 XLM → whitelist SERVICE → pay 1 XLM → assert balance ≤ 19 & zero uncaught page errors
  • .github/workflows/e2e-playwright.ymlworkflow_dispatch: deps install, playwright install --with-deps chromium, run spec, upload playwright-report/ + test-results/ as 14-day artifact on failure

Modified:

  • web/src/lib/walletKit.tsconnect() short-circuits to the injected address (skips authModal); walletSignerFor() returns the injected Keypair signer when address matches
  • web/src/state/toast.tsx — Adds data-toast-kind="success\|error\|info" for robust, non-brittle on-chain outcome assertions
  • web/package.json — Adds test:e2e / test:e2e:install scripts; @playwright/test to devDeps
  • web/.gitignore — Ignores playwright-report/ and test-results/
  • web/.env.example — Documents VITE_ENABLE_TEST_SIGNER (dev/test-only) and PLAYWRIGHT_TEST_WALLET_SECRET (CLI-only, never sent to bundle)
  • web/README.md — Full E2E section: one-time setup, key generation + friendbot funding, run commands, 9-step spec walkthrough, gating diagram, CI setup instructions

Why two gating layers?

  1. Compile-time → Vite evaluates import.meta.env.VITE_ENABLE_TEST_SIGNER === "true" as a literal during build. Without the flag it becomes undefined === "true" = false, and every test-signer branch is dead code that Vite/Rollup tree-shakes out of the production bundle entirely.
  2. Runtime → Even if the flag were ever set in a prod build, testSignerAvailable() additionally requires window.__PRISM_TEST_SIGNER__ — a global that Playwright injects via addInitScript before app code runs. In a real browser, no global = no-op.

How to run locally

cd web
npm install
npm run test:e2e:install                                   # chromium + OS deps
export PLAYWRIGHT_TEST_WALLET_SECRET="S…"                  # funded testnet secret
npm run test:e2e                                            # runs: npx playwright test
# On failure: npx playwright show-report

How to run in CI

  1. Add a repository secret PLAYWRIGHT_TEST_WALLET_SECRET with a funded testnet key
  2. (Optional) Create an Environment testnet-e2e with reviewers to gate each run (avoids draining the shared key)
  3. Go to Actions → E2E — Playwright smoke (testnet) → Run workflow (the dropdown selects chromium)

Tested

  • All modified source files pass VS Code TypeScript diagnostics (zero errors)
  • Disk was full during implementation, so npm install / actual Playwright run couldn't be executed locally — dependency install and browser download are delegated to the first reviewer with a funded testnet key and free disk (per the README "One-time setup" steps)

Closes #11

@drips-wave

drips-wave Bot commented Jul 27, 2026

Copy link
Copy Markdown

@samad13 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Bekirerdem added a commit that referenced this pull request Jul 29, 2026
@Bekirerdem
Bekirerdem merged commit 9e6d425 into Bekirerdem:main Jul 29, 2026
@Bekirerdem

Copy link
Copy Markdown
Owner

Merged to main (with the Wave deadline tomorrow I merged locally rather than wait on another review round) — thanks @samad13, the harness design was right: the two-layer test-signer gating, the walletSigner.ts seam, the dispatch-only workflow and the README all landed as scoped in #11.

To get it running I pushed one follow-up commit (477be7d) on top, fixing what only showed up when the suite was actually executed:

  • walletKit.ts dropped the currentDevice/showsExtensionWallets imports while still calling them, so tsc -b failed (TS2304) — and walletSignerFor lost the stale-session disconnect callback, which is what returns a dead wallet session to "Connect wallet".
  • prismTest.ts used expect without importing it (a trailing export { expect } from … re-export doesn't create a local binding).
  • The busy-button heuristic matched any ellipsis, and the connected wallet chip (GDT6…JSJH) contains one — every wait spun until timeout.
  • The fund submit is named exactly "Fund" (the toggle is "+ Fund", which /^fund/ never matches), so .nth(1) waited on a second match that can't exist.
  • goto("/#overview") is a no-op when already on that hash, so the balance assert read the stale pre-tx 0 — it now reloads and waits out the async balance fetch.
  • Playwright waited on 127.0.0.1 while vite binds localhost (IPv6) — the webServer never came up.
  • vitest was collecting the Playwright spec and failing the unit run; tests/e2e is now excluded.
  • @playwright/test was in package.json but never made it into package-lock.json.

With those, the smoke spec passes end-to-end against testnet in ~50s: connect → deploy → fund → whitelist → pay. Points should follow once the issue is marked completed on the Wave side.

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.

test(web): Playwright E2E smoke - deploy, fund, whitelist, pay via an injected test signer

2 participants