diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index b864446..4a5d8ff 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -177,6 +177,20 @@ jobs: } $global:LASTEXITCODE = 0 + landing-pricing: + name: Landing pricing contract + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v5 + + # Network-free by design: the test stubs fetch, so a red run means the + # PAGE changed, never that the pricing API wobbled. Guards against the + # 2026-07-26 drift where get.traylinx.com advertised three retired plans + # and a money-back guarantee the terms of sale contradict. + - name: Landing page must render prices from the live API, not literals + run: node tests/landing-pricing.test.mjs + rust: name: Rust ${{ matrix.os }} runs-on: ${{ matrix.os }} diff --git a/tests/landing-pricing.test.mjs b/tests/landing-pricing.test.mjs new file mode 100644 index 0000000..4899361 --- /dev/null +++ b/tests/landing-pricing.test.mjs @@ -0,0 +1,245 @@ +// Landing-page pricing contract. Network-free on purpose: it stubs `fetch`, so +// CI never depends on the pricing API being up, and a red run always means the +// PAGE changed rather than production wobbling. +// +// Why this exists. Until 2026-07-26 this page hardcoded three plans that had +// been retired (Explorer/Creator/Operator at $39/$79/$149), advertised "Save 2 +// months", and promised a "7-day money-back guarantee" that the terms of sale +// directly contradict. Nothing caught it because nothing was watching. These +// checks watch. +// +// Run: node tests/landing-pricing.test.mjs +// +// NOT in web/. That directory is the published asset root -- Cloudflare Workers +// serves ./web directly and the Pages job does `cp -rL web/. _site/` -- so a +// test file living there would be downloadable at get.traylinx.com. + +import fs from 'node:fs'; +import vm from 'node:vm'; +import assert from 'node:assert/strict'; + +const HTML = fs.readFileSync(new URL('../web/index.html', import.meta.url), 'utf8'); +const SCRIPT = HTML.match(/