From 9437edf560dcbba3e0c9ba52c78b0168ac25be22 Mon Sep 17 00:00:00 2001 From: thephez Date: Wed, 13 May 2026 11:27:00 -0400 Subject: [PATCH 1/9] test(dashnote): add Playwright e2e smoke suite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scaffolds dashnote's first Playwright suite: config with chromium-desktop+ chromium-mobile projects, shared fixtures with a pre-connected page and mobile-aware navButton helper, and a smoke spec covering boot/connect, tab navigation, theme toggle, login-modal open/close/validation, mobile hamburger drawer, and the dashnote-lite.html static page. No mnemonic required — read-only flows only. Runs against real testnet, same posture as dashmint-lab. Co-Authored-By: Claude Opus 4.7 (1M context) --- example-apps/dashnote/CLAUDE.md | 3 + example-apps/dashnote/package.json | 2 + example-apps/dashnote/playwright.config.ts | 49 ++++++ example-apps/dashnote/test/e2e/fixtures.ts | 109 +++++++++++++ example-apps/dashnote/test/e2e/smoke.spec.ts | 153 +++++++++++++++++++ 5 files changed, 316 insertions(+) create mode 100644 example-apps/dashnote/playwright.config.ts create mode 100644 example-apps/dashnote/test/e2e/fixtures.ts create mode 100644 example-apps/dashnote/test/e2e/smoke.spec.ts diff --git a/example-apps/dashnote/CLAUDE.md b/example-apps/dashnote/CLAUDE.md index d081179..3a033b7 100644 --- a/example-apps/dashnote/CLAUDE.md +++ b/example-apps/dashnote/CLAUDE.md @@ -12,6 +12,8 @@ React + TypeScript + Vite app for personal notes on Dash Platform testnet. Notes - `npm run build` — typecheck (`tsc -b`) then bundle - `npm run lint` — ESLint - `npm run test` — Vitest suite in [test/](test/) +- `npm run test:e2e` — Playwright suite in [test/e2e/](test/e2e/) (auto-boots Vite on :5181) +- `npm run test:e2e:ui` — Playwright with the interactive UI runner - `npm run format` / `format:check` — Prettier - `npm run preview` — serve production build locally @@ -26,6 +28,7 @@ React + TypeScript + Vite app for personal notes on Dash Platform testnet. Notes - **[src/dash/types.ts](src/dash/types.ts)** — shared SDK types (`DashSdk`, `DashKeyManager`, query result shapes) used across every dash helper. - **[public/dashnote-lite.html](public/dashnote-lite.html)** — single-file zero-build companion. Read-only Recent notes (with optional owner filter) + Get-by-ID only, loads `@dashevo/evo-sdk` from `esm.sh`, and ships alongside the React app at `<...>/dashnote/dashnote-lite.html` (Vite copies `public/*` into `dist/`). Intentionally self-contained as a learning reference — don't import app code into it. - **[test/](test/)** — Vitest + Testing Library. All test files live in this flat directory and are named after the subject under test (e.g. `NotesWorkspace.test.tsx`, `SessionContext.test.tsx`, `notesCache.test.ts`) — they are **not** co-located next to source files, and the directory is **not** mirrored against `src/`. Default Vitest env is `node`; component tests opt into DOM with a `// @vitest-environment jsdom` pragma at the top of the file. +- **[test/e2e/](test/e2e/)** — Playwright specs plus shared `fixtures.ts`. Driven by [playwright.config.ts](playwright.config.ts), which loads `PLATFORM_MNEMONIC` from `../../.env` (repo root, with optional `dashnote/.env` override) and auto-starts `npx vite` on port 5181. The suite runs against real testnet — no SDK mocks. Two projects (`chromium-desktop` using `Desktop Chrome` and `chromium-mobile` using `Pixel 7`) so every spec exercises both layouts; viewport-only flows are guarded inline with `test.skip(testInfo.project.name !== "chromium-mobile", …)` rather than living in a dedicated file. Auth-gated specs sit in `test.describe.configure({ mode: "serial" })` and `test.skip` cleanly when `PLATFORM_MNEMONIC` is unset (via the `HAS_MNEMONIC` flag from `fixtures.ts`). ## Note contract diff --git a/example-apps/dashnote/package.json b/example-apps/dashnote/package.json index 9d84e4d..812a34f 100644 --- a/example-apps/dashnote/package.json +++ b/example-apps/dashnote/package.json @@ -13,6 +13,8 @@ "lint": "eslint .", "test": "vitest run", "test:coverage": "vitest run --coverage", + "test:e2e": "playwright test", + "test:e2e:ui": "playwright test --ui", "preview": "vite preview" }, "dependencies": { diff --git a/example-apps/dashnote/playwright.config.ts b/example-apps/dashnote/playwright.config.ts new file mode 100644 index 0000000..1bdc2ed --- /dev/null +++ b/example-apps/dashnote/playwright.config.ts @@ -0,0 +1,49 @@ +import { defineConfig, devices } from "@playwright/test"; +import { config as loadEnv } from "dotenv"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const here = dirname(fileURLToPath(import.meta.url)); + +// Load repo-root .env first (where PLATFORM_MNEMONIC lives for the tutorials), +// then let a local dashnote/.env override it if present. +loadEnv({ path: resolve(here, "../../.env") }); +loadEnv({ path: resolve(here, ".env"), override: true }); + +const PORT = 5181; + +export default defineConfig({ + testDir: "./test/e2e", + testMatch: "**/*.spec.ts", + fullyParallel: false, + forbidOnly: !!process.env.CI, + retries: 1, + workers: 1, + timeout: 30_000, + expect: { timeout: 15_000 }, + reporter: process.env.CI ? "list" : [["list"], ["html", { open: "never" }]], + + use: { + baseURL: `http://localhost:${PORT}`, + trace: "retain-on-failure", + permissions: ["clipboard-read", "clipboard-write"], + }, + + projects: [ + { + name: "chromium-desktop", + use: { ...devices["Desktop Chrome"] }, + }, + { + name: "chromium-mobile", + use: { ...devices["Pixel 7"] }, + }, + ], + + webServer: { + command: `npx vite --port ${PORT} --strictPort`, + url: `http://localhost:${PORT}`, + reuseExistingServer: !process.env.CI, + timeout: 120_000, + }, +}); diff --git a/example-apps/dashnote/test/e2e/fixtures.ts b/example-apps/dashnote/test/e2e/fixtures.ts new file mode 100644 index 0000000..e6e1f44 --- /dev/null +++ b/example-apps/dashnote/test/e2e/fixtures.ts @@ -0,0 +1,109 @@ +/** + * Shared Playwright fixtures for dashnote E2E tests. + * + * Runs against real Dash Platform testnet — no SDK mocks. The base `page` + * fixture navigates to `/` and waits until the IdentityCard reports a live + * SDK connection (`Connected`, `Authenticated`, or `Browsing (read-only)`) + * so spec bodies always have a usable SDK. + * + * The sidebar is rendered as `