@brandlab-digital/conformance 3.17.1 → 3.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/current-release.js +5 -5
  2. package/dist/current-release.js.map +1 -1
  3. package/dist/site-system/checks.d.ts +6 -0
  4. package/dist/site-system/checks.d.ts.map +1 -1
  5. package/dist/site-system/checks.js +1 -0
  6. package/dist/site-system/checks.js.map +1 -1
  7. package/dist/site-system/journeys/grounds.d.ts +3 -0
  8. package/dist/site-system/journeys/grounds.d.ts.map +1 -0
  9. package/dist/site-system/journeys/grounds.js +29 -0
  10. package/dist/site-system/journeys/grounds.js.map +1 -0
  11. package/dist/site-system/journeys/page-helpers.d.ts +22 -0
  12. package/dist/site-system/journeys/page-helpers.d.ts.map +1 -1
  13. package/dist/site-system/journeys/page-helpers.js +81 -1
  14. package/dist/site-system/journeys/page-helpers.js.map +1 -1
  15. package/dist/site-system/journeys/plan.d.ts +8 -1
  16. package/dist/site-system/journeys/plan.d.ts.map +1 -1
  17. package/dist/site-system/journeys/plan.js +8 -1
  18. package/dist/site-system/journeys/plan.js.map +1 -1
  19. package/dist/site-system/rules/full/k12-manifests.d.ts +4 -1
  20. package/dist/site-system/rules/full/k12-manifests.d.ts.map +1 -1
  21. package/dist/site-system/rules/full/k12-manifests.js +12 -2
  22. package/dist/site-system/rules/full/k12-manifests.js.map +1 -1
  23. package/dist/site-system/rules/shell/budgets.d.ts.map +1 -1
  24. package/dist/site-system/rules/shell/budgets.js +7 -3
  25. package/dist/site-system/rules/shell/budgets.js.map +1 -1
  26. package/dist/site-system-e2e.d.ts.map +1 -1
  27. package/dist/site-system-e2e.js +3 -1
  28. package/dist/site-system-e2e.js.map +1 -1
  29. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"budgets.js","sourceRoot":"","sources":["../../../../src/site-system/rules/shell/budgets.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve, sep } from \"node:path\";\nimport { gzipSync } from \"node:zlib\";\nimport { descendants, findAll, isWithin, type HtmlElement } from \"./html.js\";\nimport type { ShellPage } from \"./page.js\";\nimport {\n failFinding, passFinding, warningFinding, type ShellAssetReader, type ShellFinding,\n} from \"./types.js\";\n\n/**\n * B1: lab budgets read from the built page HTML (spec 5.8): JavaScript, third-party requests, the hero image and the\n * HTML itself, with no chat widget, pixel, heatmap or tag manager unless the project records the decision. Script and\n * image sizes come from the project's build output, then the base URL; a size that can't be read is left out of the\n * total and said so, never guessed.\n */\n\n/** First-party JavaScript per page, gzip: a warning from here. Starting value, calibrated in the R1 canaries. */\nexport const B1_FIRST_PARTY_JS_GZIP_WARN_BYTES = 180 * 1024;\n/** First-party JavaScript per page, gzip: the spec's starting budget; over it blocks. */\nexport const B1_FIRST_PARTY_JS_GZIP_FAIL_BYTES = 250 * 1024;\nexport const B1_HTML_MAX_BYTES = 500 * 1024;\nexport const B1_HERO_IMAGE_MAX_BYTES = 200 * 1024;\n/** The viewport width the hero image is judged at. */\nexport const B1_HERO_VIEWPORT_PX = 1440;\n\ntype ThirdPartyKind = \"chat\" | \"pixel\" | \"heatmap\" | \"tag-manager\";\n\ninterface Category {\n kind: ThirdPartyKind;\n label: string;\n hosts: readonly string[];\n}\n\nconst CATEGORIES: readonly Category[] = [\n { kind: \"chat\", label: \"a chat widget\", hosts: [\n \"widget.intercom.io\", \"js.intercomcdn.com\", \"intercom.io\", \"tawk.to\", \"crisp.chat\", \"livechatinc.com\", \"tidio.co\",\n \"driftt.com\", \"drift.com\", \"usemessages.com\", \"zdassets.com\", \"freshchat.com\", \"olark.com\", \"smartsuppchat.com\",\n \"chatra.io\", \"jivosite.com\", \"manychat.com\", \"chatwoot.com\",\n ] },\n { kind: \"pixel\", label: \"an advertising pixel\", hosts: [\n \"connect.facebook.net\", \"snap.licdn.com\", \"px.ads.linkedin.com\", \"static.ads-twitter.com\", \"analytics.twitter.com\",\n \"analytics.tiktok.com\", \"s.pinimg.com\", \"bat.bing.com\", \"sc-static.net\", \"tr.snapchat.com\", \"adroll.com\",\n \"criteo.net\", \"outbrain.com\", \"taboola.com\",\n ] },\n { kind: \"heatmap\", label: \"a heatmap or session recorder\", hosts: [\n \"hotjar.com\", \"hotjar.io\", \"clarity.ms\", \"mouseflow.com\", \"crazyegg.com\", \"fullstory.com\", \"logrocket.com\",\n \"lr-ingest.io\", \"luckyorange.com\", \"luckyorange.net\", \"smartlook.com\", \"inspectlet.com\", \"heapanalytics.com\",\n ] },\n { kind: \"tag-manager\", label: \"a tag manager\", hosts: [\n \"tags.tiqcdn.com\", \"tiqcdn.com\", \"cdn.segment.com\", \"assets.adobedtm.com\", \"cdn.tealium.com\",\n ] },\n];\n\n/** Hosts the shared analytics, Ads, maps and form-protection setup uses (see the Content-Security-Policy in site-next). */\nconst ALLOWED_HOSTS: readonly string[] = [\n \"google-analytics.com\", \"analytics.google.com\", \"googleadservices.com\", \"doubleclick.net\", \"googlesyndication.com\",\n \"maps.googleapis.com\", \"maps.gstatic.com\", \"gstatic.com\", \"challenges.cloudflare.com\",\n];\n\nconst INLINE_SIGNATURES: readonly { kind: ThirdPartyKind; label: string; regex: RegExp }[] = [\n { kind: \"pixel\", label: \"a Meta pixel\", regex: /\\bfbq\\s*\\(/ },\n { kind: \"tag-manager\", label: \"a tag manager\", regex: /gtm\\.start|googletagmanager\\.com\\/gtm\\.js/ },\n { kind: \"heatmap\", label: \"a heatmap or session recorder\", regex: /\\bhj\\s*\\(\\s*['\"]|static\\.hotjar\\.com|clarity\\.ms|\\bclarity\\s*\\(/ },\n { kind: \"chat\", label: \"a chat widget\", regex: /\\bTawk_API\\b|\\$crisp\\b|window\\.Intercom|\\bIntercom\\s*\\(|drift\\.load|LiveChatWidget|tidioChatApi|\\bzE\\s*\\(|\\bfcWidget\\b/ },\n];\n\nfunction hostMatches(host: string, domain: string): boolean {\n return host === domain || host.endsWith(`.${domain}`);\n}\n\ninterface Verdict {\n kind: ThirdPartyKind | \"other\";\n label: string;\n}\n\n/** What a third-party URL is, or null when the shared setup allows it. */\nexport function judgeThirdParty(url: URL): Verdict | null {\n const host = url.hostname.toLowerCase();\n if (hostMatches(host, \"googletagmanager.com\")) {\n return /^\\/gtag\\/js/.test(url.pathname) ? null : { kind: \"tag-manager\", label: \"a tag manager\" };\n }\n if (host === \"www.google.com\" || host === \"google.com\") {\n return /^\\/(?:maps|recaptcha)\\//.test(url.pathname) ? null : { kind: \"other\", label: \"a third-party request\" };\n }\n for (const category of CATEGORIES) {\n if (category.hosts.some((domain) => hostMatches(host, domain))) return { kind: category.kind, label: category.label };\n }\n if (ALLOWED_HOSTS.some((domain) => hostMatches(host, domain))) return null;\n return { kind: \"other\", label: \"a third-party request\" };\n}\n\nfunction isRecorded(recorded: readonly string[], url: URL, verdict: Verdict): boolean {\n const host = url.hostname.toLowerCase();\n return recorded.some((entry) => {\n const value = entry.trim().toLowerCase();\n return value !== \"\" && (value === verdict.kind || hostMatches(host, value));\n });\n}\n\nfunction sameSite(host: string, baseHost: string): boolean {\n const strip = (value: string) => value.replace(/^www\\./, \"\");\n return strip(host.toLowerCase()) === strip(baseHost.toLowerCase());\n}\n\n/**\n * The origin standing in for the site when there is no base URL (build-output mode): relative asset URLs resolve to it,\n * so they count as first-party and are read from the project's build output alone.\n */\nexport const BUILD_OUTPUT_ORIGIN = \"https://build-output.invalid\";\n\nfunction parseBase(baseUrl: string): URL | null {\n try {\n return new URL(baseUrl);\n } catch {\n return null;\n }\n}\n\n/**\n * The default reader: the project's build output for its own paths (`.next/static`, `public`, `out`), then the base\n * URL when there is one. Never reads other hosts.\n */\nexport const readBuiltAsset: ShellAssetReader = async (url, { projectRoot, baseUrl }) => {\n const given = parseBase(baseUrl);\n const base = given ?? new URL(BUILD_OUTPUT_ORIGIN);\n if (!sameSite(url.hostname, base.hostname)) return undefined;\n let pathname = url.pathname;\n try {\n pathname = decodeURIComponent(pathname);\n } catch {\n // Keep the encoded path.\n }\n const root = resolve(projectRoot);\n const candidates = pathname.startsWith(\"/_next/static/\")\n ? [join(root, \".next\", pathname.slice(\"/_next/\".length))]\n : pathname.startsWith(\"/_next/\") ? [] : [join(root, \"public\", pathname), join(root, \"out\", pathname)];\n for (const candidate of candidates) {\n const resolved = resolve(candidate);\n if (resolved.startsWith(root + sep) && existsSync(resolved)) {\n try {\n return new Uint8Array(readFileSync(resolved));\n } catch {\n // Fall through to the network.\n }\n }\n }\n if (!given || !/^https?:$/.test(url.protocol)) return undefined;\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(15_000) });\n return response.ok ? new Uint8Array(await response.arrayBuffer()) : undefined;\n } catch {\n return undefined;\n }\n};\n\ninterface Resource {\n url: URL;\n kind: \"script\" | \"other\";\n}\n\nfunction resolveUrl(value: string | undefined, page: URL): URL | null {\n if (!value || /^\\s*(?:data|blob|about|javascript|mailto|tel):/i.test(value)) return null;\n try {\n return new URL(value.trim(), page);\n } catch {\n return null;\n }\n}\n\n/** The scripts, frames and stylesheets a page requests. */\nfunction pageResources(page: ShellPage, pageUrl: URL): Resource[] {\n const resources: Resource[] = [];\n for (const element of descendants(page.doc.root)) {\n const { tag, attrs } = element;\n if (tag === \"script\" && attrs.src) {\n if (attrs.nomodule !== undefined) continue;\n const url = resolveUrl(attrs.src, pageUrl);\n if (url) resources.push({ url, kind: \"script\" });\n } else if (tag === \"link\") {\n const rel = (attrs.rel ?? \"\").toLowerCase().split(/\\s+/);\n const wantsScript = rel.includes(\"modulepreload\") || (rel.includes(\"preload\") && attrs.as === \"script\");\n const wantsOther = rel.includes(\"stylesheet\") || (rel.includes(\"preload\") && attrs.as !== \"script\" && attrs.as !== undefined && attrs.as !== \"image\");\n if (wantsScript || wantsOther) {\n const url = resolveUrl(attrs.href, pageUrl);\n if (url) resources.push({ url, kind: wantsScript ? \"script\" : \"other\" });\n }\n } else if (tag === \"iframe\" || tag === \"embed\" || tag === \"object\") {\n const url = resolveUrl(attrs.src ?? attrs.data, pageUrl);\n if (url) resources.push({ url, kind: \"other\" });\n }\n }\n return resources;\n}\n\nfunction inlineScripts(page: ShellPage): string[] {\n return findAll(page.doc.root, (element) =>\n element.tag === \"script\" && !element.attrs.src && !/(?:json|importmap|speculationrules)/i.test(element.attrs.type ?? \"\"))\n .map((script) => script.children.map((child) => (child.kind === \"text\" ? child.text : \"\")).join(\"\"))\n // The framework's streamed page data holds the page's words, not code that runs a widget.\n .filter((text) => !text.includes(\"__next_f\"));\n}\n\nfunction srcsetCandidates(srcset: string): { url: string; width: number }[] {\n return srcset.split(\",\").map((part) => part.trim().split(/\\s+/)).filter((parts) => parts[0])\n .map(([url, descriptor]) => ({ url: url!, width: descriptor?.endsWith(\"w\") ? Number.parseInt(descriptor, 10) : descriptor?.endsWith(\"x\") ? Number.parseFloat(descriptor) * 1000 : 0 }));\n}\n\n/** The image the hero shows on a wide screen: the smallest candidate at least 1440 px wide, else the widest. */\nfunction heroImage(page: ShellPage): { element: HtmlElement; source: string | undefined } | null {\n const hero = page.hero;\n if (!hero) return null;\n const images = findAll(hero, (element) => element.tag === \"img\" && !page.headers.some((header) => isWithin(element, header)) && element.attrs[\"data-bl\"] !== \"logo\");\n if (images.length === 0) return null;\n const width = (image: HtmlElement) => Number.parseInt(image.attrs.width ?? \"0\", 10) || 0;\n const element = images.find((image) => image.attrs.fetchpriority === \"high\") ?? images.reduce((best, image) => (width(image) > width(best) ? image : best), images[0]!);\n const candidates = srcsetCandidates(element.attrs.srcset ?? \"\");\n const wide = candidates.filter((candidate) => candidate.width >= B1_HERO_VIEWPORT_PX).sort((left, right) => left.width - right.width)[0]\n ?? candidates.sort((left, right) => right.width - left.width)[0];\n return { element, source: wide?.url ?? element.attrs.src };\n}\n\nfunction gzipBytes(bytes: Uint8Array): number {\n return gzipSync(Buffer.from(bytes)).length;\n}\n\nfunction kilobytes(bytes: number): string {\n return `${Math.round(bytes / 1024)} KB`;\n}\n\nexport interface BudgetOptions {\n baseUrl: string;\n projectRoot: string;\n recordedThirdParties?: readonly string[];\n readAsset?: ShellAssetReader;\n}\n\n/** B1 over the sampled pages. */\nexport async function checkLabBudgets(pages: readonly ShellPage[], options: BudgetOptions): Promise<ShellFinding[]> {\n const read = options.readAsset ?? readBuiltAsset;\n const recorded = options.recordedThirdParties ?? [];\n const cache = new Map<string, Promise<Uint8Array | undefined>>();\n const readCached = (url: URL) => {\n const key = url.href;\n if (!cache.has(key)) cache.set(key, read(url, { projectRoot: options.projectRoot, baseUrl: options.baseUrl }).catch(() => undefined));\n return cache.get(key)!;\n };\n const base = parseBase(options.baseUrl) ?? new URL(BUILD_OUTPUT_ORIGIN);\n const failures: ShellFinding[] = [];\n const warnings: ShellFinding[] = [];\n const hostsSeen = new Set<string>();\n let largestJs = 0;\n let jsPages = 0;\n\n for (const page of pages) {\n const pageUrl = new URL(page.path, base);\n const htmlBytes = Buffer.byteLength(page.html);\n if (htmlBytes > B1_HTML_MAX_BYTES) {\n failures.push(failFinding(\"B1\", page.path, `The page ${page.path} is ${kilobytes(htmlBytes)} of HTML, over the ${kilobytes(B1_HTML_MAX_BYTES)} budget.`));\n }\n\n const resources = pageResources(page, pageUrl);\n const flagged = new Set<string>();\n for (const resource of resources) {\n if (sameSite(resource.url.hostname, base.hostname)) continue;\n hostsSeen.add(resource.url.hostname);\n const verdict = judgeThirdParty(resource.url);\n if (!verdict || isRecorded(recorded, resource.url, verdict)) continue;\n const key = `${resource.url.hostname}\\u0000${verdict.kind}`;\n if (flagged.has(key)) continue;\n flagged.add(key);\n failures.push(failFinding(\"B1\", page.path, verdict.kind === \"other\"\n ? `The page ${page.path} requests ${resource.url.hostname}, a third party outside analytics, maps and the reviews feed, with no recorded decision.`\n : `The page ${page.path} loads ${verdict.label} from ${resource.url.hostname} with no recorded decision.`));\n }\n for (const script of inlineScripts(page)) {\n for (const signature of INLINE_SIGNATURES) {\n const key = `inline\\u0000${signature.kind}`;\n if (flagged.has(key) || !signature.regex.test(script)) continue;\n if (recorded.some((entry) => entry.trim().toLowerCase() === signature.kind)) continue;\n flagged.add(key);\n failures.push(failFinding(\"B1\", page.path, `The page ${page.path} runs ${signature.label} from an inline script with no recorded decision.`));\n }\n }\n\n const scripts = [...new Map(resources.filter((resource) => resource.kind === \"script\" && sameSite(resource.url.hostname, base.hostname)).map((resource) => [resource.url.href, resource.url])).values()];\n if (scripts.length > 0) {\n const sizes = await Promise.all(scripts.map(readCached));\n const measured = sizes.filter((bytes): bytes is Uint8Array => bytes !== undefined);\n const total = measured.reduce((sum, bytes) => sum + gzipBytes(bytes), 0);\n if (measured.length > 0) {\n jsPages += 1;\n largestJs = Math.max(largestJs, total);\n const unread = scripts.length - measured.length;\n const note = unread > 0 ? ` (${unread} of ${scripts.length} script file${scripts.length === 1 ? \"\" : \"s\"} could not be read)` : \"\";\n if (total > B1_FIRST_PARTY_JS_GZIP_FAIL_BYTES) {\n failures.push(failFinding(\"B1\", page.path, `The page ${page.path} loads ${kilobytes(total)} of first-party JavaScript (gzip)${note}, over the ${kilobytes(B1_FIRST_PARTY_JS_GZIP_FAIL_BYTES)} budget.`));\n } else if (total > B1_FIRST_PARTY_JS_GZIP_WARN_BYTES) {\n warnings.push(warningFinding(\"B1\", `Warning: the page ${page.path} loads ${kilobytes(total)} of first-party JavaScript (gzip)${note}, over the ${kilobytes(B1_FIRST_PARTY_JS_GZIP_WARN_BYTES)} warning threshold.`, page.path));\n }\n }\n }\n\n const hero = heroImage(page);\n if (hero) {\n const { element, source } = hero;\n if (element.attrs.loading === \"lazy\" || element.attrs.fetchpriority === \"low\" || /\\blazy(?:load|loaded)?\\b/.test(element.attrs.class ?? \"\")) {\n failures.push(failFinding(\"B1\", page.path, `The hero image on ${page.path} is set to load lazily; the first-screen image must load straight away.`));\n }\n const url = resolveUrl(source, pageUrl);\n if (url && sameSite(url.hostname, base.hostname)) {\n const bytes = await readCached(url);\n if (bytes && bytes.length > B1_HERO_IMAGE_MAX_BYTES) {\n failures.push(failFinding(\"B1\", page.path, `The hero image on ${page.path} is ${kilobytes(bytes.length)}, over the ${kilobytes(B1_HERO_IMAGE_MAX_BYTES)} budget at ${B1_HERO_VIEWPORT_PX} px.`));\n }\n }\n }\n }\n if (failures.length > 0) return [...failures, ...warnings];\n const jsNote = jsPages > 0 ? ` The heaviest page loads ${kilobytes(largestJs)} of first-party JavaScript (gzip).` : \" Script sizes could not be read from the build output or the base URL, so the JavaScript budget was not measured.\";\n const hostNote = hostsSeen.size > 0 ? ` Third-party hosts seen: ${[...hostsSeen].sort().join(\", \")}.` : \" No third-party requests.\";\n const within = pages.length === 1 ? \"The sampled page is\" : `The ${pages.length} sampled pages are`;\n return [passFinding(\"B1\", `${within} within the HTML, hero image and third-party budgets.${jsNote}${hostNote}`), ...warnings];\n}\n"]}
1
+ {"version":3,"file":"budgets.js","sourceRoot":"","sources":["../../../../src/site-system/rules/shell/budgets.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve, sep } from \"node:path\";\nimport { gzipSync } from \"node:zlib\";\nimport { descendants, findAll, isWithin, type HtmlElement } from \"./html.js\";\nimport type { ShellPage } from \"./page.js\";\nimport {\n failFinding, passFinding, warningFinding, type ShellAssetReader, type ShellFinding,\n} from \"./types.js\";\n\n/**\n * B1: lab budgets read from the built page HTML (spec 5.8): JavaScript, third-party requests, the hero image and the\n * HTML itself, with no chat widget, pixel, heatmap or tag manager unless the project records the decision. Script and\n * image sizes come from the project's build output, then the base URL; a size that can't be read is left out of the\n * total and said so, never guessed.\n */\n\n/** First-party JavaScript per page, gzip: a warning from here. Starting value, calibrated in the R1 canaries. */\nexport const B1_FIRST_PARTY_JS_GZIP_WARN_BYTES = 180 * 1024;\n/** First-party JavaScript per page, gzip: the spec's starting budget; over it blocks. */\nexport const B1_FIRST_PARTY_JS_GZIP_FAIL_BYTES = 250 * 1024;\nexport const B1_HTML_MAX_BYTES = 500 * 1024;\nexport const B1_HERO_IMAGE_MAX_BYTES = 200 * 1024;\n/** The viewport width the hero image is judged at. */\nexport const B1_HERO_VIEWPORT_PX = 1440;\n\ntype ThirdPartyKind = \"chat\" | \"pixel\" | \"heatmap\" | \"tag-manager\";\n\ninterface Category {\n kind: ThirdPartyKind;\n label: string;\n hosts: readonly string[];\n}\n\nconst CATEGORIES: readonly Category[] = [\n { kind: \"chat\", label: \"a chat widget\", hosts: [\n \"widget.intercom.io\", \"js.intercomcdn.com\", \"intercom.io\", \"tawk.to\", \"crisp.chat\", \"livechatinc.com\", \"tidio.co\",\n \"driftt.com\", \"drift.com\", \"usemessages.com\", \"zdassets.com\", \"freshchat.com\", \"olark.com\", \"smartsuppchat.com\",\n \"chatra.io\", \"jivosite.com\", \"manychat.com\", \"chatwoot.com\",\n ] },\n { kind: \"pixel\", label: \"an advertising pixel\", hosts: [\n \"connect.facebook.net\", \"snap.licdn.com\", \"px.ads.linkedin.com\", \"static.ads-twitter.com\", \"analytics.twitter.com\",\n \"analytics.tiktok.com\", \"s.pinimg.com\", \"bat.bing.com\", \"sc-static.net\", \"tr.snapchat.com\", \"adroll.com\",\n \"criteo.net\", \"outbrain.com\", \"taboola.com\",\n ] },\n { kind: \"heatmap\", label: \"a heatmap or session recorder\", hosts: [\n \"hotjar.com\", \"hotjar.io\", \"clarity.ms\", \"mouseflow.com\", \"crazyegg.com\", \"fullstory.com\", \"logrocket.com\",\n \"lr-ingest.io\", \"luckyorange.com\", \"luckyorange.net\", \"smartlook.com\", \"inspectlet.com\", \"heapanalytics.com\",\n ] },\n { kind: \"tag-manager\", label: \"a tag manager\", hosts: [\n \"tags.tiqcdn.com\", \"tiqcdn.com\", \"cdn.segment.com\", \"assets.adobedtm.com\", \"cdn.tealium.com\",\n ] },\n];\n\n/** Hosts the shared analytics, Ads, maps and form-protection setup uses (see the Content-Security-Policy in site-next). */\nconst ALLOWED_HOSTS: readonly string[] = [\n \"google-analytics.com\", \"analytics.google.com\", \"googleadservices.com\", \"doubleclick.net\", \"googlesyndication.com\",\n \"maps.googleapis.com\", \"maps.gstatic.com\", \"gstatic.com\", \"challenges.cloudflare.com\",\n];\n\nconst INLINE_SIGNATURES: readonly { kind: ThirdPartyKind; label: string; regex: RegExp }[] = [\n { kind: \"pixel\", label: \"a Meta pixel\", regex: /\\bfbq\\s*\\(/ },\n { kind: \"tag-manager\", label: \"a tag manager\", regex: /gtm\\.start|googletagmanager\\.com\\/gtm\\.js/ },\n { kind: \"heatmap\", label: \"a heatmap or session recorder\", regex: /\\bhj\\s*\\(\\s*['\"]|static\\.hotjar\\.com|clarity\\.ms|\\bclarity\\s*\\(/ },\n { kind: \"chat\", label: \"a chat widget\", regex: /\\bTawk_API\\b|\\$crisp\\b|window\\.Intercom|\\bIntercom\\s*\\(|drift\\.load|LiveChatWidget|tidioChatApi|\\bzE\\s*\\(|\\bfcWidget\\b/ },\n];\n\nfunction hostMatches(host: string, domain: string): boolean {\n return host === domain || host.endsWith(`.${domain}`);\n}\n\ninterface Verdict {\n kind: ThirdPartyKind | \"other\";\n label: string;\n}\n\n/** What a third-party URL is, or null when the shared setup allows it. */\nexport function judgeThirdParty(url: URL): Verdict | null {\n const host = url.hostname.toLowerCase();\n if (hostMatches(host, \"googletagmanager.com\")) {\n return /^\\/gtag\\/js/.test(url.pathname) ? null : { kind: \"tag-manager\", label: \"a tag manager\" };\n }\n if (host === \"www.google.com\" || host === \"google.com\") {\n return /^\\/(?:maps|recaptcha)\\//.test(url.pathname) ? null : { kind: \"other\", label: \"a third-party request\" };\n }\n for (const category of CATEGORIES) {\n if (category.hosts.some((domain) => hostMatches(host, domain))) return { kind: category.kind, label: category.label };\n }\n if (ALLOWED_HOSTS.some((domain) => hostMatches(host, domain))) return null;\n return { kind: \"other\", label: \"a third-party request\" };\n}\n\nfunction isRecorded(recorded: readonly string[], url: URL, verdict: Verdict): boolean {\n const host = url.hostname.toLowerCase();\n return recorded.some((entry) => {\n const value = entry.trim().toLowerCase();\n return value !== \"\" && (value === verdict.kind || hostMatches(host, value));\n });\n}\n\nfunction sameSite(host: string, baseHost: string): boolean {\n const strip = (value: string) => value.replace(/^www\\./, \"\");\n return strip(host.toLowerCase()) === strip(baseHost.toLowerCase());\n}\n\n/**\n * The origin standing in for the site when there is no base URL (build-output mode): relative asset URLs resolve to it,\n * so they count as first-party and are read from the project's build output alone.\n */\nexport const BUILD_OUTPUT_ORIGIN = \"https://build-output.invalid\";\n\nfunction parseBase(baseUrl: string): URL | null {\n try {\n return new URL(baseUrl);\n } catch {\n return null;\n }\n}\n\n/**\n * The default reader: the project's build output for its own paths (`.next/static`, `public`, `out`), then the base\n * URL when there is one. Never reads other hosts.\n */\nexport const readBuiltAsset: ShellAssetReader = async (url, { projectRoot, baseUrl }) => {\n const given = parseBase(baseUrl);\n const base = given ?? new URL(BUILD_OUTPUT_ORIGIN);\n if (!sameSite(url.hostname, base.hostname)) return undefined;\n let pathname = url.pathname;\n try {\n pathname = decodeURIComponent(pathname);\n } catch {\n // Keep the encoded path.\n }\n const root = resolve(projectRoot);\n const candidates = pathname.startsWith(\"/_next/static/\")\n ? [join(root, \".next\", pathname.slice(\"/_next/\".length))]\n : pathname.startsWith(\"/_next/\") ? [] : [join(root, \"public\", pathname), join(root, \"out\", pathname)];\n for (const candidate of candidates) {\n const resolved = resolve(candidate);\n if (resolved.startsWith(root + sep) && existsSync(resolved)) {\n try {\n return new Uint8Array(readFileSync(resolved));\n } catch {\n // Fall through to the network.\n }\n }\n }\n if (!given || !/^https?:$/.test(url.protocol)) return undefined;\n try {\n // A browser asks for WebP, and Next's optimiser answers in the format asked for (3.18.0).\n const response = await fetch(url, { headers: { accept: \"image/webp,image/*;q=0.8\" }, signal: AbortSignal.timeout(15_000) });\n return response.ok ? new Uint8Array(await response.arrayBuffer()) : undefined;\n } catch {\n return undefined;\n }\n};\n\ninterface Resource {\n url: URL;\n kind: \"script\" | \"other\";\n}\n\nfunction resolveUrl(value: string | undefined, page: URL): URL | null {\n if (!value || /^\\s*(?:data|blob|about|javascript|mailto|tel):/i.test(value)) return null;\n try {\n return new URL(value.trim(), page);\n } catch {\n return null;\n }\n}\n\n/** The scripts, frames and stylesheets a page requests. */\nfunction pageResources(page: ShellPage, pageUrl: URL): Resource[] {\n const resources: Resource[] = [];\n for (const element of descendants(page.doc.root)) {\n const { tag, attrs } = element;\n if (tag === \"script\" && attrs.src) {\n if (attrs.nomodule !== undefined) continue;\n const url = resolveUrl(attrs.src, pageUrl);\n if (url) resources.push({ url, kind: \"script\" });\n } else if (tag === \"link\") {\n const rel = (attrs.rel ?? \"\").toLowerCase().split(/\\s+/);\n const wantsScript = rel.includes(\"modulepreload\") || (rel.includes(\"preload\") && attrs.as === \"script\");\n const wantsOther = rel.includes(\"stylesheet\") || (rel.includes(\"preload\") && attrs.as !== \"script\" && attrs.as !== undefined && attrs.as !== \"image\");\n if (wantsScript || wantsOther) {\n const url = resolveUrl(attrs.href, pageUrl);\n if (url) resources.push({ url, kind: wantsScript ? \"script\" : \"other\" });\n }\n } else if (tag === \"iframe\" || tag === \"embed\" || tag === \"object\") {\n const url = resolveUrl(attrs.src ?? attrs.data, pageUrl);\n if (url) resources.push({ url, kind: \"other\" });\n }\n }\n return resources;\n}\n\nfunction inlineScripts(page: ShellPage): string[] {\n return findAll(page.doc.root, (element) =>\n element.tag === \"script\" && !element.attrs.src && !/(?:json|importmap|speculationrules)/i.test(element.attrs.type ?? \"\"))\n .map((script) => script.children.map((child) => (child.kind === \"text\" ? child.text : \"\")).join(\"\"))\n // The framework's streamed page data holds the page's words, not code that runs a widget.\n .filter((text) => !text.includes(\"__next_f\"));\n}\n\nfunction srcsetCandidates(srcset: string): { url: string; width: number }[] {\n return srcset.split(\",\").map((part) => part.trim().split(/\\s+/)).filter((parts) => parts[0])\n .map(([url, descriptor]) => ({ url: url!, width: descriptor?.endsWith(\"w\") ? Number.parseInt(descriptor, 10) : descriptor?.endsWith(\"x\") ? Number.parseFloat(descriptor) * 1000 : 0 }));\n}\n\n/** Below this rendered width an image is an avatar, icon or badge, never the hero's photo (3.18.0). */\nconst B1_HERO_MIN_IMAGE_PX = 160;\n\n/** The image the hero shows on a wide screen: the smallest candidate at least 1440 px wide, else the widest. */\nfunction heroImage(page: ShellPage): { element: HtmlElement; source: string | undefined } | null {\n const hero = page.hero;\n if (!hero) return null;\n const width = (image: HtmlElement) => Number.parseInt(image.attrs.width ?? \"0\", 10) || 0;\n const images = findAll(hero, (element) => element.tag === \"img\" && !page.headers.some((header) => isWithin(element, header)) && element.attrs[\"data-bl\"] !== \"logo\")\n .filter((image) => image.attrs.fetchpriority === \"high\" || width(image) === 0 || width(image) >= B1_HERO_MIN_IMAGE_PX);\n if (images.length === 0) return null;\n const element = images.find((image) => image.attrs.fetchpriority === \"high\") ?? images.reduce((best, image) => (width(image) > width(best) ? image : best), images[0]!);\n const candidates = srcsetCandidates(element.attrs.srcset ?? \"\");\n const wide = candidates.filter((candidate) => candidate.width >= B1_HERO_VIEWPORT_PX).sort((left, right) => left.width - right.width)[0]\n ?? candidates.sort((left, right) => right.width - left.width)[0];\n return { element, source: wide?.url ?? element.attrs.src };\n}\n\nfunction gzipBytes(bytes: Uint8Array): number {\n return gzipSync(Buffer.from(bytes)).length;\n}\n\nfunction kilobytes(bytes: number): string {\n return `${Math.round(bytes / 1024)} KB`;\n}\n\nexport interface BudgetOptions {\n baseUrl: string;\n projectRoot: string;\n recordedThirdParties?: readonly string[];\n readAsset?: ShellAssetReader;\n}\n\n/** B1 over the sampled pages. */\nexport async function checkLabBudgets(pages: readonly ShellPage[], options: BudgetOptions): Promise<ShellFinding[]> {\n const read = options.readAsset ?? readBuiltAsset;\n const recorded = options.recordedThirdParties ?? [];\n const cache = new Map<string, Promise<Uint8Array | undefined>>();\n const readCached = (url: URL) => {\n const key = url.href;\n if (!cache.has(key)) cache.set(key, read(url, { projectRoot: options.projectRoot, baseUrl: options.baseUrl }).catch(() => undefined));\n return cache.get(key)!;\n };\n const base = parseBase(options.baseUrl) ?? new URL(BUILD_OUTPUT_ORIGIN);\n const failures: ShellFinding[] = [];\n const warnings: ShellFinding[] = [];\n const hostsSeen = new Set<string>();\n let largestJs = 0;\n let jsPages = 0;\n\n for (const page of pages) {\n const pageUrl = new URL(page.path, base);\n const htmlBytes = Buffer.byteLength(page.html);\n if (htmlBytes > B1_HTML_MAX_BYTES) {\n failures.push(failFinding(\"B1\", page.path, `The page ${page.path} is ${kilobytes(htmlBytes)} of HTML, over the ${kilobytes(B1_HTML_MAX_BYTES)} budget.`));\n }\n\n const resources = pageResources(page, pageUrl);\n const flagged = new Set<string>();\n for (const resource of resources) {\n if (sameSite(resource.url.hostname, base.hostname)) continue;\n hostsSeen.add(resource.url.hostname);\n const verdict = judgeThirdParty(resource.url);\n if (!verdict || isRecorded(recorded, resource.url, verdict)) continue;\n const key = `${resource.url.hostname}\\u0000${verdict.kind}`;\n if (flagged.has(key)) continue;\n flagged.add(key);\n failures.push(failFinding(\"B1\", page.path, verdict.kind === \"other\"\n ? `The page ${page.path} requests ${resource.url.hostname}, a third party outside analytics, maps and the reviews feed, with no recorded decision.`\n : `The page ${page.path} loads ${verdict.label} from ${resource.url.hostname} with no recorded decision.`));\n }\n for (const script of inlineScripts(page)) {\n for (const signature of INLINE_SIGNATURES) {\n const key = `inline\\u0000${signature.kind}`;\n if (flagged.has(key) || !signature.regex.test(script)) continue;\n if (recorded.some((entry) => entry.trim().toLowerCase() === signature.kind)) continue;\n flagged.add(key);\n failures.push(failFinding(\"B1\", page.path, `The page ${page.path} runs ${signature.label} from an inline script with no recorded decision.`));\n }\n }\n\n const scripts = [...new Map(resources.filter((resource) => resource.kind === \"script\" && sameSite(resource.url.hostname, base.hostname)).map((resource) => [resource.url.href, resource.url])).values()];\n if (scripts.length > 0) {\n const sizes = await Promise.all(scripts.map(readCached));\n const measured = sizes.filter((bytes): bytes is Uint8Array => bytes !== undefined);\n const total = measured.reduce((sum, bytes) => sum + gzipBytes(bytes), 0);\n if (measured.length > 0) {\n jsPages += 1;\n largestJs = Math.max(largestJs, total);\n const unread = scripts.length - measured.length;\n const note = unread > 0 ? ` (${unread} of ${scripts.length} script file${scripts.length === 1 ? \"\" : \"s\"} could not be read)` : \"\";\n if (total > B1_FIRST_PARTY_JS_GZIP_FAIL_BYTES) {\n failures.push(failFinding(\"B1\", page.path, `The page ${page.path} loads ${kilobytes(total)} of first-party JavaScript (gzip)${note}, over the ${kilobytes(B1_FIRST_PARTY_JS_GZIP_FAIL_BYTES)} budget.`));\n } else if (total > B1_FIRST_PARTY_JS_GZIP_WARN_BYTES) {\n warnings.push(warningFinding(\"B1\", `Warning: the page ${page.path} loads ${kilobytes(total)} of first-party JavaScript (gzip)${note}, over the ${kilobytes(B1_FIRST_PARTY_JS_GZIP_WARN_BYTES)} warning threshold.`, page.path));\n }\n }\n }\n\n const hero = heroImage(page);\n if (hero) {\n const { element, source } = hero;\n if (element.attrs.loading === \"lazy\" || element.attrs.fetchpriority === \"low\" || /\\blazy(?:load|loaded)?\\b/.test(element.attrs.class ?? \"\")) {\n failures.push(failFinding(\"B1\", page.path, `The hero image on ${page.path} is set to load lazily; the first-screen image must load straight away.`));\n }\n const url = resolveUrl(source, pageUrl);\n if (url && sameSite(url.hostname, base.hostname)) {\n const bytes = await readCached(url);\n if (bytes && bytes.length > B1_HERO_IMAGE_MAX_BYTES) {\n failures.push(failFinding(\"B1\", page.path, `The hero image on ${page.path} is ${kilobytes(bytes.length)}, over the ${kilobytes(B1_HERO_IMAGE_MAX_BYTES)} budget at ${B1_HERO_VIEWPORT_PX} px.`));\n }\n }\n }\n }\n if (failures.length > 0) return [...failures, ...warnings];\n const jsNote = jsPages > 0 ? ` The heaviest page loads ${kilobytes(largestJs)} of first-party JavaScript (gzip).` : \" Script sizes could not be read from the build output or the base URL, so the JavaScript budget was not measured.\";\n const hostNote = hostsSeen.size > 0 ? ` Third-party hosts seen: ${[...hostsSeen].sort().join(\", \")}.` : \" No third-party requests.\";\n const within = pages.length === 1 ? \"The sampled page is\" : `The ${pages.length} sampled pages are`;\n return [passFinding(\"B1\", `${within} within the HTML, hero image and third-party budgets.${jsNote}${hostNote}`), ...warnings];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"site-system-e2e.d.ts","sourceRoot":"","sources":["../src/site-system-e2e.ts"],"names":[],"mappings":"AAgCA,OAAO,EAA4D,KAAK,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAK9I,OAAO,EACL,4BAA4B,EAC5B,0BAA0B,EAC1B,uBAAuB,EACvB,0BAA0B,EAC1B,sBAAsB,EACtB,8BAA8B,EAC9B,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,6BAA6B,EAClC,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,GAC3B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AACjG,OAAO,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,WAAW,EACX,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,oCAAoC,CAAC;AAa5C,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,6BAA6B,GAAG,IAAI,CAuB1F"}
1
+ {"version":3,"file":"site-system-e2e.d.ts","sourceRoot":"","sources":["../src/site-system-e2e.ts"],"names":[],"mappings":"AAiCA,OAAO,EAA4D,KAAK,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAK9I,OAAO,EACL,4BAA4B,EAC5B,0BAA0B,EAC1B,uBAAuB,EACvB,0BAA0B,EAC1B,sBAAsB,EACtB,8BAA8B,EAC9B,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,6BAA6B,EAClC,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,GAC3B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AACjG,OAAO,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,WAAW,EACX,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,oCAAoC,CAAC;AAa5C,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,6BAA6B,GAAG,IAAI,CAwB1F"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The Site System v2 browser journeys for a Brandlab production build (release 3.8.0): the header and its menu,
3
3
  * the phone drawer and call bar, contrast, targets, focus, the action order, the money-page first screen and phone
4
- * placements, from 3.13.0 prefetch by link role (W2) and (full tier) the URL variants of each page family (W9). Every
4
+ * placements, from 3.13.0 prefetch by link role (W2), from 3.19.0 alternating backgrounds (K14) and (full tier) the URL variants of each page family (W9). Every
5
5
  * test title starts with its ready-gate check id in square brackets ("[N3] ...") so `brandlab-ready` can read the
6
6
  * Playwright JSON report.
7
7
  *
@@ -29,6 +29,7 @@ import { isolateFromNetwork } from './e2e-support.js';
29
29
  import { defineAccessJourneys } from './site-system/journeys/access.js';
30
30
  import { installPageHelpers } from './site-system/journeys/browser.js';
31
31
  import { defineConversionJourneys } from './site-system/journeys/conversion.js';
32
+ import { defineGroundJourneys } from './site-system/journeys/grounds.js';
32
33
  import { defineMenuJourneys } from './site-system/journeys/menu.js';
33
34
  import { planBrandlabSiteSystemJourneys, siteSystemJourneyRelease } from './site-system/journeys/plan.js';
34
35
  import { definePrefetchJourneys } from './site-system/journeys/prefetch.js';
@@ -64,6 +65,7 @@ export function defineBrandlabSiteSystemTests(options) {
64
65
  defineMenuJourneys(plan, runs);
65
66
  defineShellJourneys(plan, runs);
66
67
  definePrefetchJourneys(plan, runs);
68
+ defineGroundJourneys(plan, runs);
67
69
  defineConversionJourneys(plan, runs);
68
70
  defineVariantJourneys(plan, runs);
69
71
  });
@@ -1 +1 @@
1
- {"version":3,"file":"site-system-e2e.js","sourceRoot":"","sources":["../src/site-system-e2e.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Site System v2 browser journeys for a Brandlab production build (release 3.8.0): the header and its menu,\n * the phone drawer and call bar, contrast, targets, focus, the action order, the money-page first screen and phone\n * placements, from 3.13.0 prefetch by link role (W2) and (full tier) the URL variants of each page family (W9). Every\n * test title starts with its ready-gate check id in square brackets (\"[N3] ...\") so `brandlab-ready` can read the\n * Playwright JSON report.\n *\n * // tests/e2e/site-system.spec.ts\n * import { defineBrandlabSiteSystemTests } from '@brandlab-digital/conformance/site-system-e2e'\n *\n * defineBrandlabSiteSystemTests({\n * tier: 'enquiry',\n * pages: { home: '/', money: ['/services/blocked-drains'], contact: '/contact' },\n * })\n *\n * The journeys find the header parts by role, so they test a bespoke header and the shared one alike: the header is\n * the banner landmark, the menu the navigation named \"Main\", each submenu a `button[aria-expanded][aria-controls]`\n * and its panel the element that names. The tier decides which journeys register (C1 from `enquiry`, W9 at `full`\n * with `pages.families`), each from the release that brings it: the site's installed Brandlab release (a canary\n * included), read from its package.json as brandlab-ready reads it, so every journey the gate blocks on runs. They run in\n * Chromium; K5 (focus not hidden) runs in every browser project the site's Playwright config defines, so add a\n * WebKit project to cover Safari. axe comes from `@axe-core/playwright` when the site has it, else `axe-core`.\n * Every request leaves the browser only as a GET or HEAD to the build under test.\n */\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { test } from '@playwright/test';\nimport { isolateFromNetwork } from './e2e-support.js';\nimport { defineAccessJourneys } from './site-system/journeys/access.js';\nimport { installPageHelpers } from './site-system/journeys/browser.js';\nimport { defineConversionJourneys } from './site-system/journeys/conversion.js';\nimport { defineMenuJourneys } from './site-system/journeys/menu.js';\nimport { planBrandlabSiteSystemJourneys, siteSystemJourneyRelease, type BrandlabSiteSystemTestOptions } from './site-system/journeys/plan.js';\nimport { definePrefetchJourneys } from './site-system/journeys/prefetch.js';\nimport { defineShellJourneys } from './site-system/journeys/shell.js';\nimport { defineVariantJourneys } from './site-system/journeys/variants.js';\n\nexport {\n SITE_SYSTEM_DESKTOP_VIEWPORT,\n SITE_SYSTEM_DESKTOP_WIDTHS,\n SITE_SYSTEM_JOURNEY_IDS,\n SITE_SYSTEM_PHONE_VIEWPORT,\n SITE_SYSTEM_QUOTE_NAME,\n planBrandlabSiteSystemJourneys,\n siteSystemJourneyRelease,\n siteSystemJourneyTitle,\n siteSystemJourneysFor,\n type BrandlabSiteSystemTestOptions,\n type SiteSystemActionOrder,\n type SiteSystemJourneyId,\n type SiteSystemJourneyPlan,\n} from './site-system/journeys/plan.js';\nexport { HOVER_OPEN_WINDOW_MS, MOUSE_OUT_CLOSE_WINDOW_MS } from './site-system/journeys/menu.js';\nexport { SITE_SYSTEM_PHONE_PLACEMENTS } from './site-system/journeys/page-helpers.js';\nexport {\n W9_CACHE_HEADERS,\n W9_TRACKING_QUERY,\n W9_UNKNOWN_SLUG,\n notFoundVariantProblems,\n trackingVariantProblems,\n urlVariants,\n type W9Response,\n type W9Variants,\n} from './site-system/journeys/variants.js';\n\nconst CHROMIUM_ONLY = 'The site-system journeys run in Chromium; K5 runs in every browser project.';\n\n/** The site's package.json (Playwright runs from the project root), or null when it cannot be read. */\nfunction sitePackageJson(): Parameters<typeof siteSystemJourneyRelease>[0] {\n try {\n return JSON.parse(readFileSync(join(process.cwd(), 'package.json'), 'utf8')) as Parameters<typeof siteSystemJourneyRelease>[0];\n } catch {\n return null;\n }\n}\n\nexport function defineBrandlabSiteSystemTests(options: BrandlabSiteSystemTestOptions): void {\n const plan = planBrandlabSiteSystemJourneys({ ...options, release: options.release ?? siteSystemJourneyRelease(sitePackageJson()) });\n const runs = new Set<string>(plan.journeys);\n const chromiumOnly = () => test.skip(({ browserName }) => browserName !== 'chromium', CHROMIUM_ONLY);\n\n test.describe('Brandlab site system', () => {\n // Service workers could answer requests outside page and context routing.\n test.use({ serviceWorkers: 'block' });\n test.beforeEach(async ({ page, baseURL }) => {\n await isolateFromNetwork(page, { baseURL, googleTag: 'stub' });\n await installPageHelpers(page);\n });\n\n test.describe('Chromium journeys', () => {\n chromiumOnly();\n defineMenuJourneys(plan, runs);\n defineShellJourneys(plan, runs);\n definePrefetchJourneys(plan, runs);\n defineConversionJourneys(plan, runs);\n defineVariantJourneys(plan, runs);\n });\n defineAccessJourneys(plan, runs, { chromiumOnly });\n });\n}\n"]}
1
+ {"version":3,"file":"site-system-e2e.js","sourceRoot":"","sources":["../src/site-system-e2e.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Site System v2 browser journeys for a Brandlab production build (release 3.8.0): the header and its menu,\n * the phone drawer and call bar, contrast, targets, focus, the action order, the money-page first screen and phone\n * placements, from 3.13.0 prefetch by link role (W2), from 3.19.0 alternating backgrounds (K14) and (full tier) the URL variants of each page family (W9). Every\n * test title starts with its ready-gate check id in square brackets (\"[N3] ...\") so `brandlab-ready` can read the\n * Playwright JSON report.\n *\n * // tests/e2e/site-system.spec.ts\n * import { defineBrandlabSiteSystemTests } from '@brandlab-digital/conformance/site-system-e2e'\n *\n * defineBrandlabSiteSystemTests({\n * tier: 'enquiry',\n * pages: { home: '/', money: ['/services/blocked-drains'], contact: '/contact' },\n * })\n *\n * The journeys find the header parts by role, so they test a bespoke header and the shared one alike: the header is\n * the banner landmark, the menu the navigation named \"Main\", each submenu a `button[aria-expanded][aria-controls]`\n * and its panel the element that names. The tier decides which journeys register (C1 from `enquiry`, W9 at `full`\n * with `pages.families`), each from the release that brings it: the site's installed Brandlab release (a canary\n * included), read from its package.json as brandlab-ready reads it, so every journey the gate blocks on runs. They run in\n * Chromium; K5 (focus not hidden) runs in every browser project the site's Playwright config defines, so add a\n * WebKit project to cover Safari. axe comes from `@axe-core/playwright` when the site has it, else `axe-core`.\n * Every request leaves the browser only as a GET or HEAD to the build under test.\n */\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { test } from '@playwright/test';\nimport { isolateFromNetwork } from './e2e-support.js';\nimport { defineAccessJourneys } from './site-system/journeys/access.js';\nimport { installPageHelpers } from './site-system/journeys/browser.js';\nimport { defineConversionJourneys } from './site-system/journeys/conversion.js';\nimport { defineGroundJourneys } from './site-system/journeys/grounds.js';\nimport { defineMenuJourneys } from './site-system/journeys/menu.js';\nimport { planBrandlabSiteSystemJourneys, siteSystemJourneyRelease, type BrandlabSiteSystemTestOptions } from './site-system/journeys/plan.js';\nimport { definePrefetchJourneys } from './site-system/journeys/prefetch.js';\nimport { defineShellJourneys } from './site-system/journeys/shell.js';\nimport { defineVariantJourneys } from './site-system/journeys/variants.js';\n\nexport {\n SITE_SYSTEM_DESKTOP_VIEWPORT,\n SITE_SYSTEM_DESKTOP_WIDTHS,\n SITE_SYSTEM_JOURNEY_IDS,\n SITE_SYSTEM_PHONE_VIEWPORT,\n SITE_SYSTEM_QUOTE_NAME,\n planBrandlabSiteSystemJourneys,\n siteSystemJourneyRelease,\n siteSystemJourneyTitle,\n siteSystemJourneysFor,\n type BrandlabSiteSystemTestOptions,\n type SiteSystemActionOrder,\n type SiteSystemJourneyId,\n type SiteSystemJourneyPlan,\n} from './site-system/journeys/plan.js';\nexport { HOVER_OPEN_WINDOW_MS, MOUSE_OUT_CLOSE_WINDOW_MS } from './site-system/journeys/menu.js';\nexport { SITE_SYSTEM_PHONE_PLACEMENTS } from './site-system/journeys/page-helpers.js';\nexport {\n W9_CACHE_HEADERS,\n W9_TRACKING_QUERY,\n W9_UNKNOWN_SLUG,\n notFoundVariantProblems,\n trackingVariantProblems,\n urlVariants,\n type W9Response,\n type W9Variants,\n} from './site-system/journeys/variants.js';\n\nconst CHROMIUM_ONLY = 'The site-system journeys run in Chromium; K5 runs in every browser project.';\n\n/** The site's package.json (Playwright runs from the project root), or null when it cannot be read. */\nfunction sitePackageJson(): Parameters<typeof siteSystemJourneyRelease>[0] {\n try {\n return JSON.parse(readFileSync(join(process.cwd(), 'package.json'), 'utf8')) as Parameters<typeof siteSystemJourneyRelease>[0];\n } catch {\n return null;\n }\n}\n\nexport function defineBrandlabSiteSystemTests(options: BrandlabSiteSystemTestOptions): void {\n const plan = planBrandlabSiteSystemJourneys({ ...options, release: options.release ?? siteSystemJourneyRelease(sitePackageJson()) });\n const runs = new Set<string>(plan.journeys);\n const chromiumOnly = () => test.skip(({ browserName }) => browserName !== 'chromium', CHROMIUM_ONLY);\n\n test.describe('Brandlab site system', () => {\n // Service workers could answer requests outside page and context routing.\n test.use({ serviceWorkers: 'block' });\n test.beforeEach(async ({ page, baseURL }) => {\n await isolateFromNetwork(page, { baseURL, googleTag: 'stub' });\n await installPageHelpers(page);\n });\n\n test.describe('Chromium journeys', () => {\n chromiumOnly();\n defineMenuJourneys(plan, runs);\n defineShellJourneys(plan, runs);\n definePrefetchJourneys(plan, runs);\n defineGroundJourneys(plan, runs);\n defineConversionJourneys(plan, runs);\n defineVariantJourneys(plan, runs);\n });\n defineAccessJourneys(plan, runs, { chromiumOnly });\n });\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brandlab-digital/conformance",
3
- "version": "3.17.1",
3
+ "version": "3.19.0",
4
4
  "license": "UNLICENSED",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,7 +29,7 @@
29
29
  "typecheck": "tsc --noEmit -p tsconfig.json"
30
30
  },
31
31
  "dependencies": {
32
- "@brandlab-digital/site-core": "3.17.1",
32
+ "@brandlab-digital/site-core": "3.19.0",
33
33
  "typescript": "6.0.3"
34
34
  },
35
35
  "peerDependencies": {