Conversation
Add end-to-end test infrastructure for the personal-wp package, mirroring the existing playground-website Playwright setup. - Playwright config targeting port 5401 dev server - Test fixtures with iframe-aware WordPress locator - PersonalWPPage helper for common interactions - 16 tests across smoke, blueprints, and UI specs - e2e:playwright NX target in project.json Made-with: Cursor
There was a problem hiding this comment.
Pull request overview
Adds Playwright E2E test infrastructure and coverage for the personal-wp package, aligned with the existing playground-website approach.
Changes:
- Adds an Nx
e2e:playwrighttarget for running Playwright tests forplayground-personal-wp - Introduces Playwright config, fixtures, and a
PersonalWPPagehelper for nested-iframe interactions - Adds 3 spec files covering smoke, blueprint, and UI behaviors (16 tests total)
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/playground/personal-wp/project.json | Adds Nx target for running Playwright E2E tests |
| packages/playground/personal-wp/playwright/playwright.config.ts | New Playwright config including webServer startup and browser projects |
| packages/playground/personal-wp/playwright/playground-fixtures.ts | New fixtures extending Playwright test with wordpress and website helpers |
| packages/playground/personal-wp/playwright/personal-wp-page.ts | New page-object helper for navigation + Personal WP UI interactions |
| packages/playground/personal-wp/playwright/e2e/ui.spec.ts | Adds UI interaction assertions (address bar, panels, overlay, navigation) |
| packages/playground/personal-wp/playwright/e2e/smoke.spec.ts | Adds boot + auto-login + basic shell/iframe smoke checks |
| packages/playground/personal-wp/playwright/e2e/blueprints.spec.ts | Adds blueprint hash/query-based execution tests (base64/JSON/data URL/wp-cli) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
packages/playground/personal-wp/playwright/playground-fixtures.ts
Outdated
Show resolved
Hide resolved
packages/playground/personal-wp/playwright/e2e/blueprints.spec.ts
Outdated
Show resolved
Hide resolved
Add a dedicated CI workflow job to run the personal-wp Playwright e2e tests on every PR, matching the pattern of existing e2e jobs. Made-with: Cursor
The playwright install runs as the regular user, so the test must also run without sudo to find the cached browser binaries. Port 5401 does not require root privileges. Made-with: Cursor
- smoke: check for 'Howdy' text instead of #wpadminbar visibility
(admin bar element exists but is CSS-hidden before JS initializes)
- ui: use getByRole('heading', { name: 'Backup' }) to avoid strict
mode violation from 6 elements matching getByText('Backup')
- blueprints: remove blueprint-url data URL test that fails on fresh
CI browsers (no existing OPFS site for the query param path)
- Use type-only re-export for Page in playground-fixtures
- Use proper Playwright type for goto options parameter
- Scope address bar selector to the toolbar header
- Use toBeVisible() instead of not.toBeEmpty() in waitForNestedIframes
Made-with: Cursor
…n checks
'Start over' and 'Recovery' also match multiple elements (heading +
paragraph). Use getByRole('heading') consistently for all menu sections.
Made-with: Cursor
Smoke tests: - Rename to reflect actual first-visit flow (default my-wordpress blueprint lands on welcome page, not dashboard) - Check #wpwrap visibility for boot confirmation - Check #wpadminbar attachment (not visibility) for login verification - Add explicit welcome page URL assertion via address bar Browser coverage: - Add webkit (Desktop Safari) project to match core playground-website - CI now runs a matrix of chromium/firefox/webkit instead of chromium-only Made-with: Cursor
…er timeout Firefox and WebKit use Asyncify (not JSPI), where the WordPress body inside the iframe may be CSS-hidden during boot. toBeVisible() fails in this state while not.toBeEmpty() (used by core playground-website) succeeds. Additionally, personal-wp boots are heavier (OPFS site creation + default blueprint fetches a plugin from GitHub), so the timeout is increased to 180s to accommodate slower Asyncify mode. Made-with: Cursor
Firefox and WebKit fail because the WASM PHP runtime needs SharedArrayBuffer, which requires cross-origin isolation headers (COEP/COOP). These are provided by the service worker after it claims the page, but on a fresh Vite dev server load the service worker isn't active yet and the runtime never boots. The core playground-website E2E tests already cover Firefox/WebKit via a built app served with proper headers. Personal-wp E2E tests focus on the UI layer and run on Chromium (with JSPI) only. Made-with: Cursor
… ones Blueprint execution (base64, JSON, writeFile, login, wp-cli) is thoroughly covered by the core playground-website E2E tests. The welcome page test already proves blueprints work through personal-wp. Similarly, WordPress boot, auto-login, and viewport rendering are implicitly tested by core. Remaining 8 tests focus on what personal-wp uniquely adds: - Default my-wordpress blueprint flow (welcome page landing) - Personal-wp toolbar - Address bar, Site Tools panel, menu overlay, page title, navigation Made-with: Cursor
personal-wp forks resolve-blueprint-from-url.ts and boot-site-client.ts from core. Add a smoke test that exercises this forked parsing → boot chain, while avoiding re-testing shared step execution from @wp-playground/blueprints. Made-with: Cursor
There was a problem hiding this comment.
Pull request overview
Adds Playwright E2E coverage for the personal-wp package, focusing on the fork-specific boot/parsing path and personal-wp UI behaviors.
Changes:
- Adds Playwright config + fixtures + page object helper for personal-wp E2E.
- Introduces 2 E2E spec files (smoke + UI) totaling 9 tests.
- Wires execution via Nx target and a dedicated CI job.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/playground/personal-wp/project.json | Adds an Nx target to run the personal-wp Playwright E2E suite. |
| packages/playground/personal-wp/playwright/playwright.config.ts | Introduces Playwright configuration, Chromium-only project, and dev-server startup via webServer. |
| packages/playground/personal-wp/playwright/playground-fixtures.ts | Defines Playwright fixtures for nested WP iframe access and a PersonalWP page helper. |
| packages/playground/personal-wp/playwright/personal-wp-page.ts | Adds a Page Object helper for navigation/iframe readiness and toolbar/UI interactions. |
| packages/playground/personal-wp/playwright/e2e/ui.spec.ts | Adds UI-focused E2E checks (Site Tools, menu overlay, title, address bar navigation). |
| packages/playground/personal-wp/playwright/e2e/smoke.spec.ts | Adds smoke tests validating default landing, welcome flow, and URL-hash blueprint path. |
| .github/workflows/ci.yml | Adds a dedicated CI job to install Chromium and run the personal-wp E2E suite. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const baseURL = | ||
| process.env.PLAYWRIGHT_TEST_BASE_URL || | ||
| 'http://127.0.0.1:5401/website-server/'; |
There was a problem hiding this comment.
This mirrors the existing playground-website Playwright config (port 5400 vs 5401). In practice, PLAYWRIGHT_TEST_BASE_URL is only used when a server is already running, and reuseExistingServer: !process.env.CI (true locally) means Playwright skips starting/polling the hardcoded URL entirely. If this were worth changing, it should be addressed across both configs together.
| webServer: { | ||
| command: 'npx nx run playground-personal-wp:dev', | ||
| url: 'http://127.0.0.1:5401/website-server/', | ||
| reuseExistingServer: !process.env.CI, | ||
| }, |
There was a problem hiding this comment.
Duplicate of the above — same pattern inherited from the existing playground-website config.
| await expect( | ||
| page | ||
| .frameLocator( | ||
| '#playground-viewport:visible,.playground-viewport:visible' | ||
| ) | ||
| .frameLocator('#wp') | ||
| .locator('body') | ||
| ).not.toBeEmpty(); |
There was a problem hiding this comment.
This is intentionally a loose minimum-viability gate — it confirms the nested iframe chain loaded and PHP rendered something. Each test then makes its own specific assertions (toHaveText, toHaveValue, toBeVisible) which serve as the actual readiness guarantees. A tighter gate like #wpadminbar would actually be more fragile (e.g. it is not present on the welcome page). Combined with generous timeouts (60s expect, 300s test) and 3 retries, flakiness from this gate is unlikely. We can revisit if flakiness is actually observed.
| - name: Install Playwright Browser | ||
| run: npx playwright install chromium --with-deps | ||
| - name: Run personal-wp Playwright e2e tests | ||
| run: CI=true npx playwright test --config=packages/playground/personal-wp/playwright/playwright.config.ts --project=chromium |
There was a problem hiding this comment.
This follows the same pattern used by the existing playground-website E2E CI job (direct npx playwright test commands, not Nx targets). Consistent with the rest of the repo CI setup.
| retries: 3, | ||
| workers: 3, |
There was a problem hiding this comment.
The existing playground-website config uses the identical values (retries: 3, workers: 3) without CI conditioning — this is an intentional project-wide convention. If worth revisiting, it should be done across both configs consistently, not just here.
This isn't directly related to the PR. Why are these files copied? If they are useful, let's export them. |
packages/playground/personal-wp/playwright/playground-fixtures.ts
Outdated
Show resolved
Hide resolved
The wordpress FrameLocator was defined in three places — the fixture, the page object's wordpress() method, and waitForNestedIframes(). Now wordpress() is the single source of truth and both callers delegate to it. Made-with: Cursor
…orNestedIframes() Both methods always operate on this.page — the parameter was never called with a non-default value. Made-with: Cursor
|
@bgrgicak I guess because this package is like a forked version of playground instance. So, it copies over some stuff like that. So, not a usual requirement from consumer's side. Resolving blueprint can definitely be exported, we needed it in wpcom stuff too. Others, perhaps not so much. |
Verify clicking "you can reset this WordPress" reveals the "Delete everything" button and clicking "you can troubleshoot" reveals the "Install Health Check & Troubleshoot" link. Made-with: Cursor
I agree it's a rare use case, but if it's simple for us it will make these advanced use cases easier to implement. |
Summary
Adds Playwright E2E tests for the
personal-wppackage, focused on code paths and UI that are unique to personal-wp.personal-wp forks several core modules —
resolve-blueprint-from-url.ts,boot-site-client.ts, androuter.ts— rather than importing fromplayground-website. Blueprint step execution is shared via@wp-playground/blueprints, so we don't re-test individual step types (writeFile, wp-cli, etc.) that core already covers extensively. Instead, these tests verify personal-wp's own parsing → boot chain and its unique UI.9 tests across 2 spec files:
Implementation details
playwright.config.ts— targets port 5401 (personal-wp dev server), Chromium-only (Firefox/WebKit can't boot via Vite dev server due to missing COEP/COOP headers before service worker claims the page)playground-fixtures.ts— extends Playwrighttestwithwordpress(iframe chain) andwebsite(PersonalWPPage helper) fixturespersonal-wp-page.ts— page helper withgoto()that waits for nested iframes, plus site tools, menu overlay, and address bar methodstest-e2e-personal-wpjob on ChromiumTest plan
npx playwright test --config=packages/playground/personal-wp/playwright/playwright.config.ts --project=chromiumMade with Cursor