From 42ce46b6112fb20280ee5d75e0171f6cdc4ada7e Mon Sep 17 00:00:00 2001 From: Kevin Walker Date: Thu, 8 Oct 2026 09:42:31 +0200 Subject: [PATCH 1/4] feat: add testing helpers for sitemap-driven smoke tests Add `@smartive/utils/testing` (sitemap parsing, route limits, ignore rules, browserless URL check) and `@smartive/utils/testing/playwright` (fixtures that fail a test on client-side errors, third-party request blocking, global setup that hands sitemap routes to the specs). `@playwright/test` is an optional peer and only imported as types, so each project runs the version pinned to its CI image. Both subpaths have a `default` export condition so CommonJS projects can require them. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/test.yml | 15 ++ .gitignore | 5 + README.md | 165 ++++++++++++++++ e2e/fixtures.spec.ts | 93 +++++++++ e2e/fixtures.ts | 5 + e2e/global-setup.ts | 3 + e2e/http.spec.ts | 12 ++ e2e/pages.spec.ts | 17 ++ e2e/playwright.config.ts | 20 ++ e2e/require-check.cts | 14 ++ e2e/server.ts | 90 +++++++++ e2e/tsconfig.json | 13 ++ package-lock.json | 50 +++++ package.json | 25 ++- src/testing/http-check.test.ts | 118 ++++++++++++ src/testing/http-check.ts | 96 ++++++++++ src/testing/ignore.test.ts | 36 ++++ src/testing/ignore.ts | 32 ++++ src/testing/index.ts | 5 + src/testing/patterns.test.ts | 29 +++ src/testing/patterns.ts | 19 ++ src/testing/playwright.test.ts | 339 +++++++++++++++++++++++++++++++++ src/testing/playwright.ts | 300 +++++++++++++++++++++++++++++ src/testing/routes.test.ts | 72 +++++++ src/testing/routes.ts | 42 ++++ src/testing/sitemap.test.ts | 151 +++++++++++++++ src/testing/sitemap.ts | 118 ++++++++++++ 27 files changed, 1881 insertions(+), 3 deletions(-) create mode 100644 e2e/fixtures.spec.ts create mode 100644 e2e/fixtures.ts create mode 100644 e2e/global-setup.ts create mode 100644 e2e/http.spec.ts create mode 100644 e2e/pages.spec.ts create mode 100644 e2e/playwright.config.ts create mode 100644 e2e/require-check.cts create mode 100644 e2e/server.ts create mode 100644 e2e/tsconfig.json create mode 100644 src/testing/http-check.test.ts create mode 100644 src/testing/http-check.ts create mode 100644 src/testing/ignore.test.ts create mode 100644 src/testing/ignore.ts create mode 100644 src/testing/index.ts create mode 100644 src/testing/patterns.test.ts create mode 100644 src/testing/patterns.ts create mode 100644 src/testing/playwright.test.ts create mode 100644 src/testing/playwright.ts create mode 100644 src/testing/routes.test.ts create mode 100644 src/testing/routes.ts create mode 100644 src/testing/sitemap.test.ts create mode 100644 src/testing/sitemap.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 209e229..cbcb58d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,3 +27,18 @@ jobs: - run: npm run typecheck - run: npm run test - run: npm run build + + e2e: + name: Playwright e2e + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7 + with: + node-version: 24 + - run: npm ci + - run: npx playwright install --with-deps chromium + - run: npm run test:e2e diff --git a/.gitignore b/.gitignore index fa28420..43ca2d1 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,8 @@ npm-debug.log* yarn-debug.log* yarn-error.log* + +# playwright e2e +/test-results +/playwright-report +/e2e/test-results diff --git a/README.md b/README.md index d85234e..2bb6cd2 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,171 @@ covers the manual full reset (a missed webhook, or a change to the query-ID form | `DRAFT_SECRET_TOKEN` | Authorizes draft enable/disable and web-previews | | `CACHE_INVALIDATION_SECRET_TOKEN` | Authorizes the revalidate and cache-tag webhooks (`Webhook-Token`) | +## `@smartive/utils/testing` + +Building blocks for sitemap-driven smoke tests. Zero dependencies, no browser. + +```typescript +import { checkUrls, fetchSitemapRoutes, formatUrlCheckFailures } from '@smartive/utils/testing'; + +const routes = await fetchSitemapRoutes({ + baseURL: 'http://localhost:3333', + limits: [{ pattern: '/arbeiten/', max: 3 }], // sample large collections + exclude: ['/ueber-uns/livebilder'], +}); + +const results = await checkUrls(routes, { baseURL: 'http://localhost:3333' }); +``` + +- `fetchSitemapRoutes` follows a sitemap index and includes `xhtml:link` alternates. It replaces the + sitemap host with `baseURL`, deduplicates, applies `exclude` then `limits`, and throws when the + sitemap is unreachable or empty, so a broken sitemap never turns into a green run that checked + nothing. +- `checkUrls` requests every URL without following redirects (a redirecting sitemap URL fails), + retries network errors and 5xx once, and never throws. `formatUrlCheckFailures` turns the + failures into an assertion message. +- `parseSitemap`, `limitRoutes`, `excludeRoutes`, `toPath` and `isIgnored` are exported for custom + setups. Patterns are a `string` (substring) or a `RegExp`. + +### `@smartive/utils/testing/playwright` + +Fixtures that fail a Playwright test on client-side errors: hydration mismatches, React errors, +exceptions in client components, failed first-party requests. Only types are imported from +`@playwright/test`, so install the version that matches your CI image: + +```bash +npm install -D @playwright/test@ +``` + +The automatic `smoke` fixture: + +- blocks every request that is not same-origin with `baseURL` or listed in `allowHosts`, so + trackers, consent banners and embeds neither add noise nor send hits from CI +- collects console errors and warnings (`failOn`), uncaught exceptions and unhandled rejections, + first-party responses with status ≥ 400 and failed first-party requests +- ignores console errors of blocked requests and expected aborts (`