mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-07-17 17:21:48 +00:00
527 lines
26 KiB
Markdown
527 lines
26 KiB
Markdown
# Playwright E2E Testing Design Document
|
|
|
|
## 1. Business & Functional Problem Statement
|
|
|
|
Topola Viewer currently relies on a Cypress end-to-end (E2E) test suite to
|
|
verify critical user flows, such as interactive chart rendering, search
|
|
capabilities, and experimental WebMCP integrations. However, the existing setup
|
|
is brittle and hard to maintain because it depends on live, external internet
|
|
connections to fetch remote GEDCOM trees, uses loosely-typed JavaScript spec
|
|
files, and suffers from complex process orchestration. Additionally, Cypress's
|
|
historical architectural limitations make testing cross-origin iframe structures
|
|
in embedded mode slow and difficult to simulate locally. Migrating this testing
|
|
suite to Playwright in TypeScript will establish a fast, fully type-safe,
|
|
hermetic, and self-contained validation pipeline, ensuring absolute quality
|
|
control and deployment confidence.
|
|
|
|
## 2. The Technical Plan
|
|
|
|
The technical solution relies on transitioning our testing engine from Cypress
|
|
to Playwright, utilizing a self-contained, local-first execution model. Instead
|
|
of relying on external servers or separate terminal scripts to boot up our
|
|
application, Playwright will orchestrate the entire lifecycle from start to
|
|
finish.
|
|
|
|
Here is a block diagram of how the major components fit together during a test
|
|
run:
|
|
|
|
```mermaid
|
|
graph TD
|
|
subgraph "Orchestration & Testing (Playwright)"
|
|
Runner["Playwright Test Runner"]
|
|
BrowserContext["Virtual Browser Engine"]
|
|
NetworkRouter["Built-in Network Router"]
|
|
end
|
|
|
|
subgraph "Local Application"
|
|
SilentServer["Local Web Server<br/>(Vite booted silently)"]
|
|
App["Topola Viewer App<br/>(React / SVG Charts)"]
|
|
end
|
|
|
|
subgraph "Local Mock Data"
|
|
GedFixture["Local Sample File<br/>(family.ged)"]
|
|
VirtualIframe["Virtual HTML Page<br/>(Embedded Mode Wrapper)"]
|
|
end
|
|
|
|
%% Execution connections
|
|
Runner -->|1. Launches| SilentServer
|
|
Runner -->|2. Controls| BrowserContext
|
|
BrowserContext -->|3. Loads App from| SilentServer
|
|
SilentServer -->|4. Serves Code to| BrowserContext
|
|
|
|
%% Mocking connections
|
|
BrowserContext -->|5. Requests Data| NetworkRouter
|
|
NetworkRouter -->|6. Redirects to| GedFixture
|
|
BrowserContext -->|7. Simulates Embed with| VirtualIframe
|
|
```
|
|
|
|
### Breakdown of Major Components
|
|
|
|
#### 1. The Playwright Test Runner
|
|
|
|
The central brain of our testing environment. It handles parsing our TypeScript
|
|
test specifications, managing test execution, starting the local web server,
|
|
controlling the virtual browser instances, and generating reports.
|
|
|
|
#### 2. The Local Web Server (Vite / Preview)
|
|
|
|
A local server hosting the Topola Viewer application. To ensure E2E tests
|
|
validate the exact production bundle that will be deployed, the test runner in
|
|
CI environments boots the production-built files via Vite's preview server
|
|
(`npx vite preview --port 3000 --strictPort`), with the build process decoupled
|
|
and executed earlier in the CI workflow job. Local environments dynamically run
|
|
Vite dev server (`npx vite --no-open --port 3000 --strictPort`) or reuse an
|
|
existing running server to maintain fast iteration cycles.
|
|
|
|
#### 3. The Built-in Network Router (Interception)
|
|
|
|
The central network traffic controller. When the application attempts to fetch
|
|
the family tree, our network router intercepts the request and returns our
|
|
offline sample data instead. To prevent browser CORS blocks, the mock response
|
|
explicitly supplies the `Access-Control-Allow-Origin: *` header. Wildcard
|
|
interceptors match any request ending with `/family.ged`, allowing E2E tests to
|
|
load family tree data consistently from local mock data without hardcoding
|
|
public GitHub URL paths or relying on CORS proxy overrides.
|
|
|
|
#### 4. The Virtual Page Generator (Iframe Wrapper)
|
|
|
|
A mechanism for generating temporary webpage wrappers directly in-memory during
|
|
test execution. To simulate how our app works inside an iframe, Playwright
|
|
serves a dynamic wrapper page on a mock URL `/test-embedded-frame.html`. This
|
|
wrapper page loads our app inside an iframe and handles standard bidirectional
|
|
postMessage handshakes. Because the application uses `HashRouter`, the iframe
|
|
source points to the hash route `/#/view?embedded=true&handleCors=false` to
|
|
ensure React Router matches the `/view` route.
|
|
|
|
#### 5. The Browser Environment Injector (Init Scripts)
|
|
|
|
Allows the test runner to pre-configure the browser's environment before the web
|
|
page's own code executes. This is essential for simulating experimental features
|
|
like WebMCP tool registration. The injector exposes a mock registration API that
|
|
pushes registered tools to the browser's global `window.__registeredTools`
|
|
array. The runner evaluates execution blocks _inside_ the browser context to
|
|
invoke these tools' non-serializable callbacks, asserting tool registration and
|
|
visual UI updates.
|
|
|
|
## 3. Alternatives Considered & Rejected
|
|
|
|
To establish clear architectural guardrails and prevent future regressions or
|
|
redundant work, this section documents the key design alternatives that were
|
|
evaluated and subsequently ruled out.
|
|
|
|
### A. Phased Migration (Coexistence)
|
|
|
|
- **Considered:** Running both Cypress and Playwright concurrently in the
|
|
repository and migrating the five test specs one by one over time.
|
|
- **Rejected because:** Dual-framework coexistence introduces significant
|
|
developer friction and technical debt. Developers would have to maintain
|
|
duplicate configuration files, manage dual dependency pools in `package.json`,
|
|
and configure complex dual execution stages in GitHub Actions. Given our E2E
|
|
suite is compact, a "clean break" eliminates Cypress-related dependencies
|
|
immediately.
|
|
|
|
### B. Running E2E Tests Against Live URLs (Real-World Feeds)
|
|
|
|
- **Considered:** Continuing the Cypress pattern of loading the sample family
|
|
tree directly from GitHub raw servers over the public internet.
|
|
- **Rejected because:** Live URL calls in automated E2E tests are a primary
|
|
source of test flakiness. Tests can fail randomly due to DNS resolution lags,
|
|
server downtime, or GitHub API rate-limiting, causing false negatives in our
|
|
CI pipeline. Using Playwright's network routing to intercept these calls and
|
|
fulfill them with a local fixture guarantees absolute hermeticity and
|
|
consistency.
|
|
|
|
### C. Maintaining Physical HTML Wrapper Files for Iframe Tests
|
|
|
|
- **Considered:** Storing a physical `tests/fixtures/embedded_frame.html` file
|
|
in the repository to act as the container for iframe tests.
|
|
- **Rejected because:** Storing a physical, standalone test-only wrapper file
|
|
can create environment port synchronization issues and static asset mapping
|
|
overhead.
|
|
- **Actual Implementation Note:** The implementation adopted a hybrid approach.
|
|
A physical template file
|
|
[embedded_frame.html](../tests/fixtures/embedded_frame.html) is maintained as
|
|
the structural source of truth for the frame, but it is loaded in-memory and
|
|
served virtually on `/test-embedded-frame.html` via the network router,
|
|
keeping it on the same origin/port dynamically to bypass cross-origin iframe
|
|
blocks.
|
|
|
|
### D. Retaining `start-server-and-test` for Dev Server Bootstrapping
|
|
|
|
- **Considered:** Continuing to rely on `start-server-and-test` or a custom bash
|
|
script to verify when port `3000` is responsive before running tests.
|
|
- **Rejected because:** Playwright's native `webServer` orchestrator is
|
|
superior, highly optimized, and self-contained. It handles port polling,
|
|
processes recycling on failures, and performs automatic process cleanups upon
|
|
exit natively. Keeping `start-server-and-test` adds unnecessary external
|
|
library dependencies and script complexity.
|
|
|
|
### E. Initial Multi-Browser & Multi-Device Targets
|
|
|
|
- **Considered:** Configuring Chromium, Firefox, WebKit, and mobile emulation
|
|
from Day One.
|
|
- **Rejected because:** The immediate goal is to achieve full, stable parity
|
|
with the existing single-browser Cypress suite. Adding multiple engines right
|
|
away increases execution time and CI resource consumption. Multi-browser
|
|
testing can be easily enabled later by adjusting the configuration in
|
|
`playwright.config.ts`.
|
|
|
|
## 4. Detailed Implementation Plan
|
|
|
|
This section defines the granular step-by-step instructions and enumerates
|
|
**every single file** that will be created, modified, or deleted to ensure a
|
|
flawless migration, including complete, copy-pasteable code contents for all
|
|
configurations and test specifications matching the actual implementation.
|
|
|
|
### A. Enumeration of Files
|
|
|
|
#### 1. Files to [DELETE]
|
|
|
|
- **[cypress.config.ts](../cypress.config.ts)**
|
|
- _Rationale:_ Complete removal of Cypress configurations; no longer needed.
|
|
- **[cypress/e2e/chart_view.cy.js](../cypress/e2e/chart_view.cy.js)**
|
|
- _Rationale:_ Outdated JavaScript test spec. Replaced by type-safe
|
|
`tests/chart_view.spec.ts`.
|
|
- **[cypress/e2e/embedded.cy.js](../cypress/e2e/embedded.cy.js)**
|
|
- _Rationale:_ Outdated JavaScript test spec. Replaced by type-safe
|
|
`tests/embedded.spec.ts`.
|
|
- **[cypress/e2e/intro.cy.js](../cypress/e2e/intro.cy.js)**
|
|
- _Rationale:_ Outdated JavaScript test spec. Replaced by type-safe
|
|
`tests/intro.spec.ts`.
|
|
- **[cypress/e2e/search.cy.js](../cypress/e2e/search.cy.js)**
|
|
- _Rationale:_ Outdated JavaScript test spec. Replaced by type-safe
|
|
`tests/search.spec.ts`.
|
|
- **[cypress/e2e/webmcp.cy.js](../cypress/e2e/webmcp.cy.js)**
|
|
- _Rationale:_ Outdated JavaScript test spec. Replaced by type-safe
|
|
`tests/webmcp.spec.ts`.
|
|
- **`cypress/e2e/README.md`**
|
|
- _Rationale:_ Legacy test documentation that is no longer applicable.
|
|
|
|
#### 2. Files to [MODIFY]
|
|
|
|
- **[package.json](../package.json)**
|
|
- _Rationale:_ Uninstall `cypress` and `start-server-and-test`
|
|
devDependencies. Install `@playwright/test` and `@types/node`. Add the
|
|
silent `"preview": "vite preview"` script, replace the `cy:*` test scripts
|
|
with Playwright E2E execution targets (`"test:e2e": "playwright test"` and
|
|
`"test:e2e:ui": "playwright test --ui"`), and update the `"prettier"` and
|
|
`"lint"` scripts to format and lint both the `src/` and `tests/`
|
|
directories.
|
|
- **[jest.config.ts](../jest.config.ts)**
|
|
- _Rationale:_ Add the `roots` configuration property to isolate Jest unit
|
|
testing to the `src/` directory, preventing Jest from scanning or executing
|
|
Playwright specs inside the `tests/` folder.
|
|
- **[.gitignore](../.gitignore)**
|
|
- _Rationale:_ Ignore locally generated Playwright E2E testing artifacts
|
|
(`playwright-report/`, `test-results/`, and `.playwright/`) to maintain a
|
|
clean working tree.
|
|
- **[PROJECT_STRUCTURE.md](../PROJECT_STRUCTURE.md)**
|
|
- _Rationale:_ Replace references to Cypress (`cypress/`, `cypress.config.ts`)
|
|
with Playwright (`tests/`, `playwright.config.ts`) to keep the repository
|
|
structural documentation fully accurate.
|
|
- **[.github/workflows/node.js.yml](../.github/workflows/node.js.yml)**
|
|
- _Rationale:_ Replace `npm run cy:start-and-run` with cached Playwright
|
|
execution. E2E tests are executed across all matrix Node environments to
|
|
maximize testing coverage and parity across runtimes.
|
|
- **[.github/workflows/deploy-gh-pages.yml](../.github/workflows/deploy-gh-pages.yml)**
|
|
- _Rationale:_ Remove testing and browser-setup steps entirely to speed up the
|
|
deployment flow and separate deploy actions from regular test gating.
|
|
- **[.github/workflows/deploy-wikitree-apps.yml](../.github/workflows/deploy-wikitree-apps.yml)**
|
|
- _Rationale:_ Remove testing and browser-setup steps entirely to speed up the
|
|
deployment flow and separate deploy actions from regular test gating.
|
|
|
|
#### 3. Files to [NEW]
|
|
|
|
- **[playwright.config.ts](../playwright.config.ts)**
|
|
- _Rationale:_ Central configuration for Playwright. Configures parallel
|
|
execution, defines a single Desktop Chrome (Chromium) project, sets the base
|
|
URL and locale to `'en-US'`, and manages the local dev or preview servers
|
|
dynamically on port 3000 with strict port enforcement.
|
|
- **`tests/tsconfig.json`**
|
|
- _Rationale:_ Custom localized compiler configuration for E2E tests that
|
|
extends the root `tsconfig.json` but includes NodeJS environment types
|
|
explicitly and isolates global types from Jest, keeping E2E environments
|
|
perfectly isolated. It sets `"noEmit": true` because E2E tests do not need
|
|
to output compiled JS files.
|
|
- **`tests/global.d.ts`**
|
|
- _Rationale:_ Custom global type declaration file for E2E tests to safely
|
|
declare `__registeredTools` on the `Window` interface without TypeScript
|
|
compiler warnings. Redundant overrides for `Navigator` are omitted because
|
|
the test suite inherits it from the application's core WebMCP declarations.
|
|
- **`tests/helpers.ts`**
|
|
- _Rationale:_ Shared test utilities to encapsulate wildcard route mocking for
|
|
family tree fetching (`setupGedcomRoute`) and hermetic context routing
|
|
(`setupHermeticEnvironment`). This avoids code duplication across spec
|
|
files.
|
|
- **`tests/fixtures/embedded_frame.html`**
|
|
- _Rationale:_ Physical template wrapper file defining the iframe and
|
|
message-passing structure for embedded view E2E verification.
|
|
- **`src/datasource/testdata/test.ged`**
|
|
- _Rationale:_ Instead of checking in a duplicate fixture file, we directly
|
|
read the existing version-controlled test GEDCOM dataset located at
|
|
`src/datasource/testdata/test.ged` inside the Playwright interceptors. This
|
|
eliminates file duplication, reduces repository footprint, and ensures a
|
|
single source of truth.
|
|
- **`tests/intro.spec.ts`**
|
|
- _Rationale:_ Type-safe TS spec checking landing page layout, menu items, and
|
|
basic static DOM presence.
|
|
- **`tests/chart_view.spec.ts`**
|
|
- _Rationale:_ Type-safe TS spec checking interactive tree navigation, relying
|
|
on Playwright's auto-waiting to settle D3 transitions, drawer details
|
|
panels, and routing interception to block analytics/third-party APIs.
|
|
- **`tests/search.spec.ts`**
|
|
- _Rationale:_ Type-safe TS spec checking the search autocompletion (using
|
|
robust, user-facing locators like
|
|
`page.getByPlaceholder('Search for people')` to target the input, and
|
|
Playwright's auto-waiting to handle search debouncing).
|
|
- **`tests/webmcp.spec.ts`**
|
|
- _Rationale:_ Type-safe TS spec verifying WebMCP tools. Emulates
|
|
out-of-process tool executions inside `navigator.modelContext` by evaluating
|
|
execution blocks within the browser context, using polling assertions to
|
|
avoid React `useEffect` mount race conditions.
|
|
- **`tests/embedded.spec.ts`**
|
|
- _Rationale:_ Type-safe TS spec verifying iframe embedded views using a
|
|
virtually served template file `tests/fixtures/embedded_frame.html`
|
|
executing the bidirectional postMessage handshake (`ready` / `gedcom`)
|
|
matching production.
|
|
|
|
### B. Step-by-Step Execution Plan & Complete File Contents
|
|
|
|
#### Step 1: Dependency Purge & Clean Break
|
|
|
|
1. Remove legacy Cypress and server-tester modules from `package.json`:
|
|
`npm uninstall cypress start-server-and-test`
|
|
2. Delete the `cypress.config.ts` configuration and the recursive `cypress/`
|
|
folder from disk.
|
|
3. Install Playwright Test Framework and Node environment types:
|
|
`npm install -D @playwright/test @types/node`
|
|
4. Download the local browser binaries required for Playwright execution:
|
|
`npx playwright install chromium`
|
|
5. Update the `"prettier"` script in `package.json` to cover both `src/` and
|
|
`tests/`: `"prettier": "prettier --write \"{src,tests}/**/*.{ts,tsx,json}\""`
|
|
6. Modify `jest.config.ts` to isolate Jest testing to the `src/` directory and
|
|
prevent test scanning collisions:
|
|
```typescript
|
|
// Add this property to the exported config object in jest.config.ts
|
|
roots: ["<rootDir>/src"],
|
|
```
|
|
7. Update the repository structural documentation
|
|
[PROJECT_STRUCTURE.md](../PROJECT_STRUCTURE.md) to replace Cypress details
|
|
with Playwright details.
|
|
|
|
#### Step 2: Script Alignment & Silent Configs
|
|
|
|
1. Update the `package.json` scripts:
|
|
- Add `"preview": "vite preview"` to support serving the production build in
|
|
CI.
|
|
- Replace `cy:*` script targets with Playwright E2E commands:
|
|
- `"test:e2e": "playwright test"`
|
|
- `"test:e2e:ui": "playwright test --ui"`
|
|
2. Author `playwright.config.ts` to orchestrate the `webServer` dynamically
|
|
based on execution context, and poll port `3000`.
|
|
|
|
**Key Configuration Details for
|
|
[playwright.config.ts](../playwright.config.ts):**
|
|
|
|
- **Test Directory**: Target `./tests` folder.
|
|
- **Parallelism & CI Tuning**: Enable fully parallel execution
|
|
(`fullyParallel: true`), disable `forbidOnly` locally but enforce it in CI,
|
|
and configure retries (2 in CI, 0 locally).
|
|
- **Base Configuration**: Set the `baseURL` to `http://localhost:3000`, force
|
|
the locale to `'en-US'` to ensure consistent translation keys across all runs,
|
|
and capture traces on first retry.
|
|
- **Browsers**: Set up a single project using standard Chromium devices
|
|
(`Desktop Chrome`).
|
|
- **Orchestrated WebServer**: Configure `webServer` to run the Vite dev server
|
|
(`npx vite --no-open --port 3000 --strictPort`) locally or Vite preview
|
|
(`npx vite preview --port 3000 --strictPort`) in CI, targeting port `3000`
|
|
with strict port enforcement and reusing any existing local server instance
|
|
only in local mode.
|
|
|
|
#### Step 3: Establish Test Directories & Compile Settings
|
|
|
|
1. Create the folder path `tests/` and its subfolder `tests/fixtures/`.
|
|
2. Author `tests/tsconfig.json` to isolate test typings from the main
|
|
application and Jest unit tests:
|
|
- **Inheritance & Target**: Extends the root `tsconfig.json`, setting
|
|
`module` and `moduleResolution` to `NodeNext` and targeting `ES2022`.
|
|
- **Isolated Types**: Excludes Jest/app global typings and explicitly pulls
|
|
in only the `"node"` types.
|
|
- **No Output**: Sets `"noEmit": true` as E2E specs do not need compilation
|
|
output.
|
|
3. Author `tests/global.d.ts` to provide TypeScript type definitions for mocked
|
|
window objects:
|
|
- **Type Extension**: Declares `__registeredTools?` on the global `Window`
|
|
interface to prevent TypeScript compilation errors during WebMCP mocks.
|
|
4. Author `tests/helpers.ts` to provide reusable mock setups and routing
|
|
interceptions:
|
|
- **Hermetic Routing**: Implements a `setupHermeticEnvironment(context)`
|
|
helper that intercepts tracking services (`**/*google-analytics.com/**`,
|
|
`**/*googletagmanager.com/**`) and embeds baseline web fonts to guarantee
|
|
deterministic and fast test execution.
|
|
- **GEDCOM Mocks**: Implements a `setupGedcomRoute(context)` helper that
|
|
reads the version-controlled local dataset
|
|
(`src/datasource/testdata/test.ged`) and routes all requests matching
|
|
`**/family.ged` to be fulfilled with it, serving a `200 OK` response with
|
|
CORS enablement headers (`Access-Control-Allow-Origin: *`).
|
|
5. Author the physical template wrapper file
|
|
`tests/fixtures/embedded_frame.html` for testing embedded iframe
|
|
communications:
|
|
- **Structure**: Defines a standard wrapper document housing an iframe that
|
|
points to the app's embedded route:
|
|
`/#/view?embedded=true&handleCors=false`.
|
|
- **Bidirectional Handshake**: Contains script block executing a `fetch()` to
|
|
get the GEDCOM content. It listens for a `'ready'` postMessage from the
|
|
child iframe, and posts the raw GEDCOM content back with a `'gedcom'`
|
|
message once the handshake is complete.
|
|
|
|
#### Step 4: Spec Translation & Spec Designs
|
|
|
|
##### 1. Intro Test (`tests/intro.spec.ts`)
|
|
|
|
Checks the landing page layout, menu items, and basic static DOM presence:
|
|
|
|
- **Setup**: Leverages `beforeEach` to configure hermetic routes using the
|
|
`setupHermeticEnvironment` helper, then loads the index page (`/`).
|
|
- **Assertions**:
|
|
- Verifies that the main intro landing text content (specifically checking for
|
|
the presence of `'Examples'`) is visible on the page.
|
|
- Asserts that core action buttons in the menu (exact text `'Open file'` and
|
|
`'Load from URL'`) are properly rendered and visible to the user.
|
|
|
|
##### 2. Chart View Test (`tests/chart_view.spec.ts`)
|
|
|
|
Checks tree navigation, settles transitions, details panels, and routing
|
|
interception:
|
|
|
|
- **Setup**: Employs `beforeEach` to configure route intercepts via
|
|
`setupGedcomRoute` and navigates to the app passing a mock URL parameter
|
|
(`/#/view?url=https%3A%2F%2Fexample.org%2Ffamily.ged`).
|
|
- **Assertions**:
|
|
- Verifies that the viewer loads and renders the chart nodes, asserting that
|
|
the name `'Bonifacy'` is visible inside the `#content` container.
|
|
- Tests chart interactive capabilities by clicking an individual node (e.g.,
|
|
`'Radobod'`) with `{force: true}` to navigate, asserting that a child node
|
|
(e.g., `'Chike'`) animates and renders.
|
|
- Verifies side-drawer details rendering by asserting that person-specific
|
|
data (e.g., `'a random note'`) is visible.
|
|
|
|
##### 3. Search Test (`tests/search.spec.ts`)
|
|
|
|
Checks search input, suggestion popups, debouncing, and navigation updates:
|
|
|
|
- **Setup**: Prepares GEDCOM routing via `setupGedcomRoute` and loads the chart
|
|
view.
|
|
- **Assertions**:
|
|
- Targets the search input using the user-facing selector
|
|
`page.getByPlaceholder('Search for people')`.
|
|
- Fills in search queries (e.g., `'chik'`), verifies the autocomplete results
|
|
panel (`.results`) debounces and renders the target suggestion (`'Chike'`).
|
|
- Triggers selection by pressing `'Enter'` and asserts that the main chart
|
|
view successfully shifts focus and renders the target person's node.
|
|
|
|
##### 4. WebMCP Test (`tests/webmcp.spec.ts`)
|
|
|
|
Bridges out-of-process serialization, checks tool registrations, and asserts
|
|
detail updates:
|
|
|
|
- **Setup**: Configures GEDCOM intercepts. Prior to navigation, it injects an
|
|
early script (`page.addInitScript`) that mocks
|
|
`navigator.modelContext.registerTool` and
|
|
`navigator.modelContext.unregisterTool` APIs, populating tool metadata in a
|
|
global `window.__registeredTools` list.
|
|
- **Assertions**:
|
|
- Verifies all core WebMCP tools (`get_selected_person`, `search_indi`,
|
|
`inspect_indi`, `focus_indi`, `find_relationship_path`, `get_ancestors`,
|
|
`get_descendants`) register correctly. Uses a polling assertion
|
|
(`page.waitForFunction`) to safely wait for the React hook mounting cycle.
|
|
- Tests interactive integration by evaluating a script in the browser context
|
|
that calls the registered `focus_indi` tool callback with target identifier
|
|
(`{id: 'I21'}`), then asserts that the UI automatically updates the viewer
|
|
focus to `'Chike'`.
|
|
|
|
##### 5. Embedded Test (`tests/embedded.spec.ts`)
|
|
|
|
Serves local wrapper page template virtually and handles complete bidirectional
|
|
postMessage handshake:
|
|
|
|
- **Setup**: Prepares standard GEDCOM routing. Reads the physical
|
|
`embedded_frame.html` template from disk and registers a route interceptor
|
|
serving it dynamically at `/test-embedded-frame.html` so both frames stay on
|
|
the same origin.
|
|
- **Assertions**:
|
|
- Navigates to `/test-embedded-frame.html`.
|
|
- Targets the inner iframe using `page.frameLocator('#topolaFrame')`.
|
|
- Verifies that the bidirectional message passing functions correctly by
|
|
asserting that the inner iframe successfully receives and renders the root
|
|
family chart nodes (asserting the presence of `'Bonifacy'`).
|
|
|
|
#### Step 5: CI Pipeline Alignment
|
|
|
|
Modify the GitHub Actions YAML scripts in `.github/workflows/` to replace all
|
|
legacy Cypress execution steps. E2E testing runs on all Node environments in the
|
|
pipeline matrix for comprehensive validation.
|
|
|
|
##### 1. Key Steps for `node.js.yml`
|
|
|
|
- **Prettier & Lint Checks**: Run formatting checks across both the application
|
|
and the new tests using
|
|
`npx prettier --check "{src,tests}/**/*.{ts,tsx,json}"` and run
|
|
`npm run lint`.
|
|
- **Build & Test**: Run standard `npm run build` and unit tests via `npm test`.
|
|
- **E2E Spec Typecheck**: Run `npx tsc -p tests/tsconfig.json --noEmit` to
|
|
guarantee complete E2E spec compilation/type correctness.
|
|
- **Playwright Browser Caching**: Extract the current Playwright version and
|
|
cache the browser binaries (`~/.cache/ms-playwright`) dynamically using
|
|
`actions/cache@v4` to prevent redundant downloads.
|
|
- **Execution**: Install necessary OS libraries using
|
|
`npx playwright install-deps chromium`, install the browser binary, and run
|
|
the test runner with `npm run test:e2e`.
|
|
- **Artifact Storage**: Archive the resulting `playwright-report/` directory on
|
|
failure or completion using `actions/upload-artifact@v4` with a 30-day
|
|
retention period.
|
|
|
|
##### 2. Key Steps for `deploy-gh-pages.yml` & `deploy-wikitree-apps.yml`
|
|
|
|
- No testing steps are run within the deploy workflows. They are fully
|
|
streamlined to execute checkouts, build production assets, and deploy
|
|
immediately, leaving gating assertions to the primary merge-to-master CI loop
|
|
(`node.js.yml`).
|
|
|
|
## 5. Future Considerations
|
|
|
|
### A. Visual Regression (Screenshot) Testing
|
|
|
|
While the initial migration focuses on full parity with standard Cypress
|
|
text-assertion specs, Topola Viewer is a highly visual, SVG-driven charting
|
|
engine. In a future iteration, we should introduce Playwright visual
|
|
snapshot/regression testing using
|
|
`expect(page.locator('#content svg')).toHaveScreenshot('default-chart.png')`.
|
|
This will automatically catch layout regressions, overlaps, and styled box
|
|
positioning issues that DOM text assertions cannot detect.
|
|
|
|
### B. File Upload Flow Testing
|
|
|
|
To ensure users can reliably upload their family trees locally, a future
|
|
iteration should introduce E2E tests for local file ingestion:
|
|
|
|
- **Single File Upload (.ged)**: Simulating selection and upload of `.ged` text
|
|
files using Playwright's `setInputFiles()` or `filechooser` events, verifying
|
|
that the application correctly transitions to the visual chart view.
|
|
- **Multi-File / Image Upload**: Verifying that uploading a `.ged` file along
|
|
with associated `.jpg` or `.png` image assets resolves and binds photos to
|
|
individuals in the chart without errors.
|
|
- **Fixture Management**: This will require checking in small, 1x1 pixel dummy
|
|
images to act as local mock visual resources.
|
|
|
|
### C. CI/CD Pipeline Optimization (Shared E2E Gating Job)
|
|
|
|
Currently, the manual deployment workflow `deploy-everywhere.yml` triggers both
|
|
`deploy-gh-pages.yml` and `deploy-wikitree-apps.yml` in parallel, which
|
|
duplicates E2E test execution and results in running the slow Playwright test
|
|
runner twice simultaneously. A future optimization should restructure the
|
|
workflows to execute the E2E validation once as a gating pre-deploy job
|
|
(`needs: e2e-validation`), or rely strictly on the main merge-to-master CI
|
|
pipeline validation, ensuring manual deployments are fast, clean, and
|
|
lightweight.
|