diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 3d82b2d..eec9d91 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -11,3 +11,4 @@ This directory contains GitHub Actions workflow files that automate various task - [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. - [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. +- [prober-wikitree.yml](prober-wikitree.yml): Reusable prober that smoke-tests the WikiTree direct API path on the live WikiTree deployment. Runs daily and after deploy. diff --git a/.github/workflows/deploy-everywhere.yml b/.github/workflows/deploy-everywhere.yml index f22d31c..9da1da9 100644 --- a/.github/workflows/deploy-everywhere.yml +++ b/.github/workflows/deploy-everywhere.yml @@ -21,3 +21,10 @@ jobs: secrets: inherit with: wait_for_propagation: true + + prober-wikitree: + needs: deploy-wikitree-apps + uses: ./.github/workflows/prober-wikitree.yml + secrets: inherit + with: + wait_for_propagation: true diff --git a/.github/workflows/prober-wikitree.yml b/.github/workflows/prober-wikitree.yml new file mode 100644 index 0000000..3aa2ac8 --- /dev/null +++ b/.github/workflows/prober-wikitree.yml @@ -0,0 +1,77 @@ +name: Prober - WikiTree + +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: wikitree.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-wikitree + path: playwright-report/ + retention-days: 30 diff --git a/tests/probers/wikitree.spec.ts b/tests/probers/wikitree.spec.ts new file mode 100644 index 0000000..8edb429 --- /dev/null +++ b/tests/probers/wikitree.spec.ts @@ -0,0 +1,34 @@ +import {expect, test} from '@playwright/test'; + +/** + * Prober: WikiTree direct API + * + * Loads a known WikiTree profile (Skłodowska-2) from the app deployed on + * apps.wikitree.com. Because the app is on the apps.wikitree.com domain, + * WikiTree API calls go direct (no CORS proxy). This exercises the WikiTree + * direct API path and confirms the WikiTree deployment is healthy. + */ +test('WikiTree direct API prober', async ({page}) => { + await page.goto( + 'https://apps.wikitree.com/apps/wiech13/topola-viewer/#/view?source=wikitree&indi=Sk%C5%82odowska-2', + ); + + // 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('Skłodowska'); + + // Assert the expected person's name appears in the side panel. + // Scoped to div.details to avoid matching SVG + // elements in the chart that also carry the "details" class. + await expect(page.locator('div.details')).toContainText('Skłodowska'); + + // 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 , which renders at + // document.body level, not inside #content. + await expect(page.locator('.ui.errorPopup.message')).not.toBeVisible(); +});