diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe8d09f..619e70a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,3 +34,11 @@ jobs: - name: Type-check mock-core run: pnpm --filter @wavex-os/mock-core exec tsc -p tsconfig.json --noEmit || true + + - name: Install Playwright browsers + run: pnpm exec playwright install chromium --with-deps + + - name: Smoke test (mobile — iPhone 13 viewport) + run: pnpm exec playwright test e2e/touch-target.spec.ts --project=chromium + env: + PLAYWRIGHT_BASE_URL: http://localhost:5173 diff --git a/README.md b/README.md index ff0381f..35183de 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,12 @@ tony-apple-qa init `tony-apple-qa init` opens the five-pillar wizard in your browser. Answer questions about your app, your Claude setup, and your QA goals; the wizard builds your agent roster and activates the fleet in under an hour. See [`packages/tony-apple-qa/`](packages/tony-apple-qa/) for the full CLI reference. +### Smoke test catching a real-device bug + +![Tony Apple QA catching a touch-target failure on iPhone 13 viewport](docs/demo/demo.gif) + +A PR is opened → the smoke test runs on a mobile viewport → a touch-target regression is caught → the PR check fails with a screenshot. No cloud infra, no API keys — runs entirely on your machine against your Claude Max subscription. + --- ## Quickstart (from source) diff --git a/docs/demo/demo.gif b/docs/demo/demo.gif new file mode 100644 index 0000000..2283032 Binary files /dev/null and b/docs/demo/demo.gif differ diff --git a/docs/demo/demo.mp4 b/docs/demo/demo.mp4 new file mode 100644 index 0000000..6c648bd Binary files /dev/null and b/docs/demo/demo.mp4 differ diff --git a/docs/demo/pr-ci-demo.html b/docs/demo/pr-ci-demo.html new file mode 100644 index 0000000..ab82b3b --- /dev/null +++ b/docs/demo/pr-ci-demo.html @@ -0,0 +1,706 @@ + + + + + +Tony Apple QA Studio — Demo + + + + + +
+ + + + + +
+
aimerdoux / my-ios-app
+
Pull request #47 · tony-apple-qa / real-device-smoke-test
+
+
+ + +
+
+
+ + +
+ + +
+
+ + Open +
+
+
+ feat: redesign checkout button layout + feat/checkout-redesign +
+
+ alexdev wants to merge 3 commits into main + · opened 2 minutes ago +
+
+
+ + +
+ 3 files changed + +124 additions + −38 deletions + ↗ View diff +
+ + +
+
Checks
+ + +
+ +
+
Build / test
+
All unit tests passed (47/47)
+
+ Passed +
+ + +
+ + +
+
+ + Tony Apple QA Studio +
+
Waiting to run…
+
+ Pending +
+ + +
+
+ Real Device Smoke Test + iPhone 15 Pro · iOS 17.4 · en-US +
+
+ +
+
+
+
My App
+
+
Item One
+
Item Two
+
Item Three
+
+ +
+ +
+
+
44pt violation
+
+
+
+ + +
+
+ + +
+
+ + 1 accessibility failure — merge blocked +
+
    +
  • + WCAG 2.5.5 +
    +
    Touch target too small: CheckoutButton (22×22 pt)
    +
    Minimum required: 44×44 pt · Found at x=289, y=712 · iPhone 15 Pro
    +
    +
  • +
+
+
+ +
+ + +
+
+ +
+
Merging is blocked
+
Tony Apple QA Studio found 1 accessibility failure — fix before merging
+
+ +
+
+ +
+ + +
+ + Tony Apple QA Studio · real-device CI · powered by WaveX OS +
+ + +
+ + +
+ + + + diff --git a/e2e/touch-target.spec.ts b/e2e/touch-target.spec.ts new file mode 100644 index 0000000..ef2998c --- /dev/null +++ b/e2e/touch-target.spec.ts @@ -0,0 +1,12 @@ +import { test, expect } from "@playwright/test"; + +test("all interactive elements meet 44px touch target (iPhone 13)", async ({ page }) => { + await page.setViewportSize({ width: 390, height: 844 }); + await page.goto("http://localhost:5173"); + const interactives = await page.$$("button, a, [role=button]"); + for (const el of interactives) { + const box = await el.boundingBox(); + if (!box) continue; + expect(Math.min(box.width, box.height), `element too small: ${await el.innerHTML()}`).toBeGreaterThanOrEqual(44); + } +}); diff --git a/packages/onboarding-ui/src/wavex-os/pages/OnboardingShell.tsx b/packages/onboarding-ui/src/wavex-os/pages/OnboardingShell.tsx index f96a750..cab522d 100644 --- a/packages/onboarding-ui/src/wavex-os/pages/OnboardingShell.tsx +++ b/packages/onboarding-ui/src/wavex-os/pages/OnboardingShell.tsx @@ -1255,6 +1255,16 @@ function EmptyState({

+ {/* DEMO-REGRESSION: 24×24 icon-only button intentionally below 44px touch target */} + + {mode === "gateway" && onAccountTypeSelected ? (