From f2ca885a4c820a90fc165e5460f8979fd1b94308 Mon Sep 17 00:00:00 2001 From: Nish <257724087+nish3451@users.noreply.github.com> Date: Fri, 14 Aug 2026 16:21:09 +0530 Subject: [PATCH 1/2] test(public): guard public pages against launch-prep footer copy regression PR #35 replaced the launch-prep footer line ('gives each product a clean public foundation before launch') with visitor-facing copy on all twelve shared-footer pages, but shipped without a regression test. Add test-public-footer-copy.mjs, wired into npm test and npm run ci, which fails if any public page's footer block re-introduces launch-prep phrasing or drops the product-naming visitor copy. --- package.json | 4 +- scripts/test-public-footer-copy.mjs | 98 +++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 scripts/test-public-footer-copy.mjs diff --git a/package.json b/package.json index c9b7c4d8..319a5700 100644 --- a/package.json +++ b/package.json @@ -93,9 +93,9 @@ "product:truth": "node scripts/check-product-truth.mjs", "mobbin:run": "node scripts/run-design-system-proving-lab.mjs", "mobbin:check": "node scripts/run-design-system-proving-lab.mjs --dry-run", - "ci": "node scripts/test-service-engine.mjs && node scripts/test-sales-intake-contract.mjs && node scripts/test-active-offer-projection.mjs && node scripts/test-active-operator-surfaces.mjs && node scripts/test-direction-proof-gate.mjs && node scripts/test-client-readiness-contract.mjs && node scripts/test-validated-service-client.mjs && node scripts/test-client-acceptance-gates.mjs && node scripts/test-operator-check-strictness.mjs && node scripts/check-product-truth.mjs && node scripts/check-human-service-kit.mjs && node scripts/test-design-system-proving-lab.mjs && node scripts/check-retention-automation.mjs && node scripts/test-retention-automation.mjs && node scripts/check-agency-defaults.mjs && node scripts/check-outbound-claim-safety.mjs && node scripts/check-outbound-send-readiness.mjs && node scripts/test-outbound-send-readiness.mjs && node scripts/test-public-conversion-signal.mjs && node scripts/test-public-structured-data.mjs && node scripts/test-public-brand-disambiguation.mjs && node scripts/test-public-heading-hierarchy.mjs && node scripts/test-public-link-targets.mjs && node scripts/test-public-social-preview.mjs && node scripts/test-public-soft-404.mjs && node scripts/test-public-deploy-bundle.mjs && node scripts/test-deploy-public-site-workflow.mjs && node scripts/test-pages-release.mjs && find scripts -name '*.mjs' -print0 | xargs -0 -n1 node --check", + "ci": "node scripts/test-service-engine.mjs && node scripts/test-sales-intake-contract.mjs && node scripts/test-active-offer-projection.mjs && node scripts/test-active-operator-surfaces.mjs && node scripts/test-direction-proof-gate.mjs && node scripts/test-client-readiness-contract.mjs && node scripts/test-validated-service-client.mjs && node scripts/test-client-acceptance-gates.mjs && node scripts/test-operator-check-strictness.mjs && node scripts/check-product-truth.mjs && node scripts/check-human-service-kit.mjs && node scripts/test-design-system-proving-lab.mjs && node scripts/check-retention-automation.mjs && node scripts/test-retention-automation.mjs && node scripts/check-agency-defaults.mjs && node scripts/check-outbound-claim-safety.mjs && node scripts/check-outbound-send-readiness.mjs && node scripts/test-outbound-send-readiness.mjs && node scripts/test-public-conversion-signal.mjs && node scripts/test-public-structured-data.mjs && node scripts/test-public-brand-disambiguation.mjs && node scripts/test-public-heading-hierarchy.mjs && node scripts/test-public-link-targets.mjs && node scripts/test-public-social-preview.mjs && node scripts/test-public-soft-404.mjs && node scripts/test-public-footer-copy.mjs && node scripts/test-public-deploy-bundle.mjs && node scripts/test-deploy-public-site-workflow.mjs && node scripts/test-pages-release.mjs && find scripts -name '*.mjs' -print0 | xargs -0 -n1 node --check", "check": "npm test", - "test": "node scripts/test-service-engine.mjs && node scripts/test-sales-intake-contract.mjs && node scripts/test-active-offer-projection.mjs && node scripts/test-active-operator-surfaces.mjs && node scripts/test-direction-proof-gate.mjs && node scripts/test-client-readiness-contract.mjs && node scripts/test-validated-service-client.mjs && node scripts/test-client-acceptance-gates.mjs && node scripts/test-operator-check-strictness.mjs && node scripts/check-product-truth.mjs && node scripts/check-human-service-kit.mjs && node scripts/test-design-system-proving-lab.mjs && node scripts/check-retention-automation.mjs && node scripts/test-retention-automation.mjs && node scripts/check-agency-defaults.mjs && node scripts/check-outbound-claim-safety.mjs && node scripts/check-outbound-send-readiness.mjs && node scripts/test-outbound-send-readiness.mjs && node scripts/test-public-conversion-signal.mjs && node scripts/test-public-structured-data.mjs && node scripts/test-public-brand-disambiguation.mjs && node scripts/test-public-heading-hierarchy.mjs && node scripts/test-public-link-targets.mjs && node scripts/test-public-social-preview.mjs && node scripts/test-public-soft-404.mjs && node scripts/test-public-deploy-bundle.mjs && node scripts/test-deploy-public-site-workflow.mjs && node scripts/test-pages-release.mjs && find scripts -name '*.mjs' -print0 | xargs -0 -n1 node --check", + "test": "node scripts/test-service-engine.mjs && node scripts/test-sales-intake-contract.mjs && node scripts/test-active-offer-projection.mjs && node scripts/test-active-operator-surfaces.mjs && node scripts/test-direction-proof-gate.mjs && node scripts/test-client-readiness-contract.mjs && node scripts/test-validated-service-client.mjs && node scripts/test-client-acceptance-gates.mjs && node scripts/test-operator-check-strictness.mjs && node scripts/check-product-truth.mjs && node scripts/check-human-service-kit.mjs && node scripts/test-design-system-proving-lab.mjs && node scripts/check-retention-automation.mjs && node scripts/test-retention-automation.mjs && node scripts/check-agency-defaults.mjs && node scripts/check-outbound-claim-safety.mjs && node scripts/check-outbound-send-readiness.mjs && node scripts/test-outbound-send-readiness.mjs && node scripts/test-public-conversion-signal.mjs && node scripts/test-public-structured-data.mjs && node scripts/test-public-brand-disambiguation.mjs && node scripts/test-public-heading-hierarchy.mjs && node scripts/test-public-link-targets.mjs && node scripts/test-public-social-preview.mjs && node scripts/test-public-soft-404.mjs && node scripts/test-public-footer-copy.mjs && node scripts/test-public-deploy-bundle.mjs && node scripts/test-deploy-public-site-workflow.mjs && node scripts/test-pages-release.mjs && find scripts -name '*.mjs' -print0 | xargs -0 -n1 node --check", "site:publish": "node scripts/publish-public-site.mjs", "site:publish:check": "node scripts/publish-public-site.mjs --prepare-only" }, diff --git a/scripts/test-public-footer-copy.mjs b/scripts/test-public-footer-copy.mjs new file mode 100644 index 00000000..afb18acb --- /dev/null +++ b/scripts/test-public-footer-copy.mjs @@ -0,0 +1,98 @@ +import { readFileSync } from "node:fs" +import { fileURLToPath } from "node:url" +import { dirname, join } from "node:path" + +const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..") +const read = (p) => readFileSync(join(ROOT, p), "utf8") + +let failures = 0 +let checks = 0 +const ok = (cond, msg) => { + checks++ + if (cond) console.log(` ok ${msg}`) + else { + failures++ + console.error(` FAIL ${msg}`) + } +} + +// Every public page that carries the shared footer block. Kept as an explicit +// list so adding a new page with the old launch-prep footer copy fails CI +// instead of being silently missed. +const FOOTER_PAGES = [ + "public/404.html", + "public/contact/index.html", + "public/drishti/index.html", + "public/drishti/privacy/index.html", + "public/drishti/support/index.html", + "public/privacy-choices/index.html", + "public/privacy/index.html", + "public/promptly/index.html", + "public/promptly/privacy/index.html", + "public/promptly/support/index.html", + "public/support/index.html", + "public/terms/index.html" +] + +// The old footer line described the internal launch-prep process ("gives each +// product a clean public foundation before launch"). Any of these fragments +// in a footer block means the visitor-facing rewrite has regressed. +const LAUNCH_PREP_FRAGMENTS = [ + "clean public foundation", + "foundation before launch", + "gives each product", + "before launch" +] + +// The replacement footer line names the actual products and what they do. +const VISITOR_FACING_FRAGMENTS = ["Promptly", "Drishti"] + +const footerBlockOf = (html) => { + const start = html.indexOf("") + return start >= 0 && end > start ? html.slice(start, end) : "" +} + +console.log("test-public-footer-copy: no public page ends with launch-prep footer copy") + +console.log("A. every page with the shared footer block has visitor-facing footer copy") +for (const page of FOOTER_PAGES) { + const html = read(page) + const footer = footerBlockOf(html) + ok(footer.length > 0, `${page} has a footer block`) + if (footer.length === 0) continue + + const copyBlock = footer.match(/