Add GitHub Pages prober

This commit is contained in:
Przemek Więch
2026-07-03 23:39:16 +02:00
parent 6af745ca3d
commit f28dfbf21d
11 changed files with 191 additions and 4 deletions

View File

@@ -10,3 +10,4 @@ This directory contains GitHub Actions workflow files that automate various task
- [deploy-gh-pages.yml](deploy-gh-pages.yml): Handles the deployment of the application to GitHub Pages. - [deploy-gh-pages.yml](deploy-gh-pages.yml): Handles the deployment of the application to GitHub Pages.
- [deploy-wikitree-apps.yml](deploy-wikitree-apps.yml): Manages the deployment of the application to WikiTree Apps using SFTP. - [deploy-wikitree-apps.yml](deploy-wikitree-apps.yml): Manages the deployment of the application to WikiTree Apps using SFTP.
- [node.js.yml](node.js.yml): The main Continuous Integration (CI) workflow. It installs dependencies, checks formatting, lints, builds, and runs tests across multiple Node.js versions. - [node.js.yml](node.js.yml): The main Continuous Integration (CI) workflow. It installs dependencies, checks formatting, lints, builds, and runs tests across multiple Node.js versions.
- [prober-gh-pages.yml](prober-gh-pages.yml): Reusable prober that smoke-tests the GitHub Pages deployment with GEDCOM-from-URL through the CORS proxy. Runs daily and after deploy.

View File

@@ -14,3 +14,10 @@ jobs:
deploy-docker: deploy-docker:
uses: ./.github/workflows/deploy-docker.yml uses: ./.github/workflows/deploy-docker.yml
secrets: inherit secrets: inherit
prober-gh-pages:
needs: deploy-gh-pages
uses: ./.github/workflows/prober-gh-pages.yml
secrets: inherit
with:
wait_for_propagation: true

77
.github/workflows/prober-gh-pages.yml vendored Normal file
View File

@@ -0,0 +1,77 @@
name: Prober - GitHub Pages
on:
workflow_call:
inputs:
wait_for_propagation:
type: boolean
default: false
workflow_dispatch:
inputs:
wait_for_propagation:
type: boolean
default: false
schedule:
- cron: '0 5 * * *'
permissions:
contents: read
actions: write
concurrency:
group: prober-${{ github.workflow }}
cancel-in-progress: false
jobs:
prober:
runs-on: ubuntu-latest
timeout-minutes: 15
env:
SPEC: gh-pages-gedcom.spec.ts
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 24.x
cache: 'npm'
- run: npm ci
- name: Wait for deployment propagation
if: inputs.wait_for_propagation
run: sleep 180
- name: Get Playwright version
id: playwright-version
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT
- name: Cache Playwright Browsers
id: cache-playwright
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }}
- name: Install Playwright System Dependencies
run: npx playwright install-deps chromium
- name: Install Playwright Browsers (If Not Cached)
if: steps.cache-playwright.outputs.cache-hit != 'true'
run: npx playwright install chromium
- name: Run prober
env:
PLAYWRIGHT_HTML_REPORT: playwright-report/prober
run: npx playwright test --config=playwright.prober.config.ts "${SPEC}"
- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@v4
with:
name: prober-report-gh-pages
path: playwright-report/
retention-days: 30

View File

@@ -30,6 +30,7 @@ Here is an enumeration of the files in this directory, categorized by their role
### Testing ### Testing
* **[playwright.config.ts](playwright.config.ts)**: Configuration file for Playwright end-to-end testing framework. * **[playwright.config.ts](playwright.config.ts)**: Configuration file for Playwright end-to-end testing framework.
* **[playwright.prober.config.ts](playwright.prober.config.ts)**: Separate Playwright config for prober (live smoke) tests against deployed URLs.
* **[jest.config.ts](jest.config.ts)**: Configuration file for the Jest testing framework used for unit tests. * **[jest.config.ts](jest.config.ts)**: Configuration file for the Jest testing framework used for unit tests.
### Documentation & Assets ### Documentation & Assets
@@ -52,3 +53,4 @@ Based on the documentation in the subdirectories, here is a high-level overview
* **[util](src/util)**: Common utilities for dates, analytics, and data processing. * **[util](src/util)**: Common utilities for dates, analytics, and data processing.
* **[public](public)**: Contains static assets (like the favicon) served directly at the root path. * **[public](public)**: Contains static assets (like the favicon) served directly at the root path.
* **[tests](tests)**: Contains end-to-end tests. * **[tests](tests)**: Contains end-to-end tests.
* **[tests/probers](tests/probers)**: Live smoke tests (probers) that run against deployed URLs and external services.

View File

@@ -351,7 +351,7 @@ targets a different URL and asserts a different expected name.
subsequent `#chart` text assertion relies on Playwright's auto-wait subsequent `#chart` text assertion relies on Playwright's auto-wait
to bridge this gap. to bridge this gap.
3. Assert expected name appears in #chart (chart SVG text). 3. Assert expected name appears in #chart (chart SVG text).
4. Assert expected name appears in .details (side panel). 4. Assert expected name appears in div.details (side panel).
5. Assert .ui.error.message is not visible (no fatal error). 5. Assert .ui.error.message is not visible (no fatal error).
6. Assert .ui.errorPopup.message is not visible (no popup error). 6. Assert .ui.errorPopup.message is not visible (no popup error).
``` ```
@@ -366,7 +366,7 @@ Selectors are derived from the source code:
* `#content` — main container, visible when chart state is `SHOWING_CHART` * `#content` — main container, visible when chart state is `SHOWING_CHART`
(see `src/pages/view_page.tsx:202`). (see `src/pages/view_page.tsx:202`).
* `#chart` — SVG group inside the chart (see `src/chart.tsx:599`). * `#chart` — SVG group inside the chart (see `src/chart.tsx:599`).
* `.details` — side panel Details tab content (see `src/sidepanel/details/details.tsx:357`). * `div.details` — side panel Details tab content (see `src/sidepanel/details/details.tsx:357`).
* `.ui.error.message` — fatal error replacing the chart (see * `.ui.error.message` — fatal error replacing the chart (see
`src/components/error_display.tsx`, rendered when state is `ERROR`). The `ui` and `src/components/error_display.tsx`, rendered when state is `ERROR`). The `ui` and
`message` classes are added by Semantic UI React's `<Message>` `message` classes are added by Semantic UI React's `<Message>`
@@ -385,7 +385,7 @@ Selectors are derived from the source code:
The side panel is expanded by default on desktop viewports (the prober project The side panel is expanded by default on desktop viewports (the prober project
uses `devices['Desktop Chrome']`). The `getShowSidePanel` function in uses `devices['Desktop Chrome']`). The `getShowSidePanel` function in
`src/util/url_args.ts:177` returns `true` on non-mobile screens, so the `.details` `src/util/url_args.ts:177` returns `true` on non-mobile screens, so the `div.details`
container is visible without any URL parameters. container is visible without any URL parameters.
### Step 3: Prober GitHub Actions workflows ### Step 3: Prober GitHub Actions workflows

View File

@@ -13,3 +13,4 @@ While new features *may* follow this methodology to ensure robust design validat
* **[PLAYWRIGHT_DESIGN.md](PLAYWRIGHT_DESIGN.md)**: Playwright E2E testing architecture, Vite development/preview server lifecycle integration, tracking blocker interceptors, and embedded iframe communication. * **[PLAYWRIGHT_DESIGN.md](PLAYWRIGHT_DESIGN.md)**: Playwright E2E testing architecture, Vite development/preview server lifecycle integration, tracking blocker interceptors, and embedded iframe communication.
* **[SCREENSHOT_TESTS_DESIGN.md](SCREENSHOT_TESTS_DESIGN.md)**: Pixel-perfect visual regression testing infrastructure, animation stabilization, sandbox environment/DOM sanitization, and isolated Playwright projects. * **[SCREENSHOT_TESTS_DESIGN.md](SCREENSHOT_TESTS_DESIGN.md)**: Pixel-perfect visual regression testing infrastructure, animation stabilization, sandbox environment/DOM sanitization, and isolated Playwright projects.
* **[WEBMCP_DESIGN.md](WEBMCP_DESIGN.md)**: Model Context Protocol (MCP) bridge and TS tool registration for AI agent interaction. * **[WEBMCP_DESIGN.md](WEBMCP_DESIGN.md)**: Model Context Protocol (MCP) bridge and TS tool registration for AI agent interaction.
* **[PROBERS_DESIGN.md](PROBERS_DESIGN.md)**: Live prober smoke tests against deployed GitHub Pages, WikiTree URLs, and local Docker container, covering WikiTree API, CORS proxy, GEDCOM-from-URL, and Docker build paths.

View File

@@ -103,6 +103,7 @@
"test:visual": "playwright test --project=visual", "test:visual": "playwright test --project=visual",
"test:visual:update": "playwright test --project=visual --update-snapshots", "test:visual:update": "playwright test --project=visual --update-snapshots",
"test:visual:ui": "playwright test --project=visual --ui", "test:visual:ui": "playwright test --project=visual --ui",
"test:probers": "playwright test --config=playwright.prober.config.ts",
"check:all": "prettier --check \"{src,tests}/**/*.{ts,tsx,json}\" && npm run lint && npm run build && npm test && tsc -p tests/tsconfig.json --noEmit && npm run test:e2e && npm run test:visual" "check:all": "prettier --check \"{src,tests}/**/*.{ts,tsx,json}\" && npm run lint && npm run build && npm test && tsc -p tests/tsconfig.json --noEmit && npm run test:e2e && npm run test:visual"
}, },
"homepage": ".", "homepage": ".",

View File

@@ -24,7 +24,7 @@ export default defineConfig({
projects: [ projects: [
{ {
name: 'e2e', name: 'e2e',
testIgnore: '*_visual.spec.ts', testIgnore: ['*_visual.spec.ts', 'probers/**'],
use: { use: {
...devices['Desktop Chrome'], ...devices['Desktop Chrome'],
}, },

View File

@@ -0,0 +1,33 @@
import {defineConfig, devices} from '@playwright/test';
/**
* Playwright configuration for prober (live smoke) tests.
*
* Unlike the main playwright.config.ts, this config:
* - Does not start a local dev server (specs navigate to absolute URLs).
* - Runs tests sequentially to avoid rate-limiting external APIs.
* - Enforces forbidOnly unconditionally (probers always run in CI).
* - Captures screenshots, video, and traces for debugging live failures.
*/
export default defineConfig({
testDir: './tests/probers',
fullyParallel: false,
forbidOnly: true,
retries: 2,
timeout: 120000,
reporter: [['html', {open: 'never'}], ['list']],
use: {
locale: 'en-US',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'on-first-retry',
},
projects: [
{
name: 'prober',
use: {
...devices['Desktop Chrome'],
},
},
],
});

30
tests/probers/README.md Normal file
View File

@@ -0,0 +1,30 @@
# Prober Tests
These are **live smoke tests** that run against deployed URLs and external
services. They are NOT hermetic — they make real network requests to the
WikiTree API, CORS proxy, and GitHub raw URLs.
## Running
```bash
npm run test:probers
```
This uses the separate `playwright.prober.config.ts` configuration, which
does not start a local dev server. Each spec navigates to a full absolute
URL (or `localhost:8080` for the Docker prober).
## What They Test
| Spec | Target | Exercises |
| --- | --- | --- |
| `gh-pages-gedcom.spec.ts` | `pewu.github.io` | GitHub Pages deployment, CORS proxy, GEDCOM-from-URL |
| `wikitree.spec.ts` | `apps.wikitree.com` | WikiTree direct API, WikiTree deployment |
| `wikitree-cors-gedcom.spec.ts` | `apps.wikitree.com` | WikiTree deployment, CORS proxy via GEDCOM-from-URL |
| `docker.spec.ts` | `localhost:8080` | Published Docker image from GHCR |
## Notes
- Probers run sequentially (`fullyParallel: false`) to avoid rate-limiting.
- Each prober has its own GitHub Actions workflow for independent triggering.
- Probers do not block Google Analytics, so live runs generate real analytics events.

View File

@@ -0,0 +1,35 @@
import {expect, test} from '@playwright/test';
/**
* Prober: GitHub Pages GEDCOM via CORS proxy
*
* Loads a GEDCOM file from a raw GitHub URL through the app deployed on
* pewu.github.io. Because the app is not on the apps.wikitree.com domain,
* GEDCOM URL requests are routed through the CORS proxy
* (topolaproxy.bieda.it) by default. This exercises the GitHub Pages
* deployment, the CORS proxy, and GEDCOM-from-URL loading.
*/
test('GitHub Pages GEDCOM prober', async ({page}) => {
await page.goto(
'https://pewu.github.io/topola-viewer/#/view?url=https://raw.githubusercontent.com/PeWu/topola-viewer/master/src/datasource/testdata/test.ged&indi=I1',
);
// Wait for the app to reach SHOWING_CHART state.
await expect(page.locator('#content')).toBeVisible();
// Assert the expected person's name appears in the chart SVG.
await expect(page.locator('#chart')).toContainText('Bonifacy');
// Assert the expected person's name appears in the side panel.
// Scoped to div.details to avoid matching <text class="details sex"> SVG
// elements in the chart that also carry the "details" class.
await expect(page.locator('div.details')).toContainText('Bonifacy');
// Assert no fatal error is displayed (replaces chart when state is ERROR).
await expect(page.locator('.ui.error.message')).not.toBeVisible();
// Assert no popup error is displayed.
// ErrorPopup uses Semantic UI React's <Portal>, which renders at
// document.body level, not inside #content.
await expect(page.locator('.ui.errorPopup.message')).not.toBeVisible();
});