mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-07-17 17:21:48 +00:00
Add GitHub Pages prober
This commit is contained in:
1
.github/workflows/README.md
vendored
1
.github/workflows/README.md
vendored
@@ -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.
|
||||||
|
|||||||
7
.github/workflows/deploy-everywhere.yml
vendored
7
.github/workflows/deploy-everywhere.yml
vendored
@@ -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
77
.github/workflows/prober-gh-pages.yml
vendored
Normal 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
|
||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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": ".",
|
||||||
|
|||||||
@@ -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'],
|
||||||
},
|
},
|
||||||
|
|||||||
33
playwright.prober.config.ts
Normal file
33
playwright.prober.config.ts
Normal 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
30
tests/probers/README.md
Normal 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.
|
||||||
35
tests/probers/gh-pages-gedcom.spec.ts
Normal file
35
tests/probers/gh-pages-gedcom.spec.ts
Normal 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();
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user