@brandlab-digital/conformance 3.13.0 → 3.15.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.
- package/README.md +68 -2
- package/dist/analytics-e2e.d.ts +10 -16
- package/dist/analytics-e2e.d.ts.map +1 -1
- package/dist/analytics-e2e.js +61 -3
- package/dist/analytics-e2e.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/current-release.js +5 -5
- package/dist/current-release.js.map +1 -1
- package/dist/engineering.d.ts.map +1 -1
- package/dist/engineering.js +18 -2
- package/dist/engineering.js.map +1 -1
- package/dist/estate-snapshot.d.ts +54 -0
- package/dist/estate-snapshot.d.ts.map +1 -0
- package/dist/estate-snapshot.js +164 -0
- package/dist/estate-snapshot.js.map +1 -0
- package/dist/estate.d.ts +38 -0
- package/dist/estate.d.ts.map +1 -1
- package/dist/estate.js +71 -28
- package/dist/estate.js.map +1 -1
- package/dist/media-snapshot.d.ts +53 -0
- package/dist/media-snapshot.d.ts.map +1 -0
- package/dist/media-snapshot.js +66 -0
- package/dist/media-snapshot.js.map +1 -0
- package/dist/project.d.ts +20 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +92 -2
- package/dist/project.js.map +1 -1
- package/dist/ready-cli.d.ts.map +1 -1
- package/dist/ready-cli.js +8 -3
- package/dist/ready-cli.js.map +1 -1
- package/dist/rule-registry.d.ts +5 -0
- package/dist/rule-registry.d.ts.map +1 -1
- package/dist/rule-registry.js +1 -0
- package/dist/rule-registry.js.map +1 -1
- package/dist/site-system/checks.d.ts +28 -3
- package/dist/site-system/checks.d.ts.map +1 -1
- package/dist/site-system/checks.js +5 -2
- package/dist/site-system/checks.js.map +1 -1
- package/dist/site-system/config.d.ts +13 -0
- package/dist/site-system/config.d.ts.map +1 -1
- package/dist/site-system/config.js +30 -1
- package/dist/site-system/config.js.map +1 -1
- package/dist/site-system/index.d.ts +1 -1
- package/dist/site-system/index.d.ts.map +1 -1
- package/dist/site-system/index.js +1 -1
- package/dist/site-system/index.js.map +1 -1
- package/dist/site-system/journeys/conversion.d.ts.map +1 -1
- package/dist/site-system/journeys/conversion.js +15 -2
- package/dist/site-system/journeys/conversion.js.map +1 -1
- package/dist/site-system/journeys/menu.d.ts.map +1 -1
- package/dist/site-system/journeys/menu.js +24 -1
- package/dist/site-system/journeys/menu.js.map +1 -1
- package/dist/site-system/journeys/page-helpers.d.ts.map +1 -1
- package/dist/site-system/journeys/page-helpers.js +1 -1
- package/dist/site-system/journeys/page-helpers.js.map +1 -1
- package/dist/site-system/journeys/plan.d.ts +13 -3
- package/dist/site-system/journeys/plan.d.ts.map +1 -1
- package/dist/site-system/journeys/plan.js +12 -2
- package/dist/site-system/journeys/plan.js.map +1 -1
- package/dist/site-system/journeys/shell.d.ts +1 -1
- package/dist/site-system/journeys/shell.js +2 -2
- package/dist/site-system/journeys/shell.js.map +1 -1
- package/dist/site-system/report.d.ts.map +1 -1
- package/dist/site-system/report.js +42 -8
- package/dist/site-system/report.js.map +1 -1
- package/dist/site-system/rule-modules.d.ts.map +1 -1
- package/dist/site-system/rule-modules.js +5 -0
- package/dist/site-system/rule-modules.js.map +1 -1
- package/dist/site-system/rules/delivery/h13-inbox.d.ts +23 -0
- package/dist/site-system/rules/delivery/h13-inbox.d.ts.map +1 -0
- package/dist/site-system/rules/delivery/h13-inbox.js +208 -0
- package/dist/site-system/rules/delivery/h13-inbox.js.map +1 -0
- package/dist/site-system/rules/delivery/index.d.ts +12 -0
- package/dist/site-system/rules/delivery/index.d.ts.map +1 -0
- package/dist/site-system/rules/delivery/index.js +7 -0
- package/dist/site-system/rules/delivery/index.js.map +1 -0
- package/dist/site-system/rules/form/c7-thank-you.d.ts +7 -1
- package/dist/site-system/rules/form/c7-thank-you.d.ts.map +1 -1
- package/dist/site-system/rules/form/c7-thank-you.js +26 -3
- package/dist/site-system/rules/form/c7-thank-you.js.map +1 -1
- package/dist/site-system/rules/form/index.d.ts.map +1 -1
- package/dist/site-system/rules/form/index.js +11 -1
- package/dist/site-system/rules/form/index.js.map +1 -1
- package/dist/site-system/rules/full/common.d.ts +2 -0
- package/dist/site-system/rules/full/common.d.ts.map +1 -1
- package/dist/site-system/rules/full/common.js.map +1 -1
- package/dist/site-system/rules/full/e1-pattern.d.ts +4 -0
- package/dist/site-system/rules/full/e1-pattern.d.ts.map +1 -0
- package/dist/site-system/rules/full/e1-pattern.js +47 -0
- package/dist/site-system/rules/full/e1-pattern.js.map +1 -0
- package/dist/site-system/rules/full/estate.d.ts +26 -3
- package/dist/site-system/rules/full/estate.d.ts.map +1 -1
- package/dist/site-system/rules/full/estate.js +58 -9
- package/dist/site-system/rules/full/estate.js.map +1 -1
- package/dist/site-system/rules/full/geography.d.ts +15 -2
- package/dist/site-system/rules/full/geography.d.ts.map +1 -1
- package/dist/site-system/rules/full/geography.js +15 -2
- package/dist/site-system/rules/full/geography.js.map +1 -1
- package/dist/site-system/rules/full/index.d.ts +4 -3
- package/dist/site-system/rules/full/index.d.ts.map +1 -1
- package/dist/site-system/rules/full/index.js +20 -5
- package/dist/site-system/rules/full/index.js.map +1 -1
- package/dist/site-system/rules/full/k12-slots.d.ts +4 -0
- package/dist/site-system/rules/full/k12-slots.d.ts.map +1 -0
- package/dist/site-system/rules/full/k12-slots.js +40 -0
- package/dist/site-system/rules/full/k12-slots.js.map +1 -0
- package/dist/site-system/rules/full/l10-location-copy.d.ts +1 -1
- package/dist/site-system/rules/full/l10-location-copy.d.ts.map +1 -1
- package/dist/site-system/rules/full/l10-location-copy.js +5 -2
- package/dist/site-system/rules/full/l10-location-copy.js.map +1 -1
- package/dist/site-system/rules/full/l3-neighbours.d.ts +3 -2
- package/dist/site-system/rules/full/l3-neighbours.d.ts.map +1 -1
- package/dist/site-system/rules/full/l3-neighbours.js +4 -1
- package/dist/site-system/rules/full/l3-neighbours.js.map +1 -1
- package/dist/site-system/rules/full/l4-local-copy.d.ts +2 -1
- package/dist/site-system/rules/full/l4-local-copy.d.ts.map +1 -1
- package/dist/site-system/rules/full/l4-local-copy.js +8 -3
- package/dist/site-system/rules/full/l4-local-copy.js.map +1 -1
- package/dist/site-system/rules/full/l9-data-contract.js +2 -2
- package/dist/site-system/rules/full/l9-data-contract.js.map +1 -1
- package/dist/site-system/rules/full/links.d.ts +3 -1
- package/dist/site-system/rules/full/links.d.ts.map +1 -1
- package/dist/site-system/rules/full/links.js +15 -5
- package/dist/site-system/rules/full/links.js.map +1 -1
- package/dist/site-system/rules/full/loc-index.d.ts +5 -0
- package/dist/site-system/rules/full/loc-index.d.ts.map +1 -1
- package/dist/site-system/rules/full/loc-index.js +43 -2
- package/dist/site-system/rules/full/loc-index.js.map +1 -1
- package/dist/site-system/rules/full/route-kinds.d.ts +15 -0
- package/dist/site-system/rules/full/route-kinds.d.ts.map +1 -0
- package/dist/site-system/rules/full/route-kinds.js +52 -0
- package/dist/site-system/rules/full/route-kinds.js.map +1 -0
- package/dist/site-system/rules/full/strategy.d.ts +6 -0
- package/dist/site-system/rules/full/strategy.d.ts.map +1 -1
- package/dist/site-system/rules/full/strategy.js +98 -10
- package/dist/site-system/rules/full/strategy.js.map +1 -1
- package/dist/site-system/rules/sections/k2-skin-coverage.d.ts +2 -2
- package/dist/site-system/rules/sections/k2-skin-coverage.d.ts.map +1 -1
- package/dist/site-system/rules/sections/k2-skin-coverage.js +13 -2
- package/dist/site-system/rules/sections/k2-skin-coverage.js.map +1 -1
- package/dist/site-system/rules/sections/t6-media-entries.d.ts.map +1 -1
- package/dist/site-system/rules/sections/t6-media-entries.js +69 -5
- package/dist/site-system/rules/sections/t6-media-entries.js.map +1 -1
- package/dist/site-system/runners.js +1 -1
- package/dist/site-system/runners.js.map +1 -1
- package/dist/site-system-e2e.d.ts +1 -1
- package/dist/site-system-e2e.d.ts.map +1 -1
- package/dist/site-system-e2e.js +17 -4
- package/dist/site-system-e2e.js.map +1 -1
- package/package.json +10 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/site-system/journeys/plan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Options and planning for the site-system journeys: which journeys a tier registers, the sampled pages and the\n * defaults. Pure, so it is unit-tested without a browser.\n */\nimport { BRANDLAB_CURRENT_RUNTIME_RELEASE } from '../../current-release.js';\nimport { SITE_SYSTEM_CHECKS, SITE_SYSTEM_TIERS, siteSystemReleaseRank, type SiteSystemTier } from '../checks.js';\n\ntype JourneyCheck = Extract<(typeof SITE_SYSTEM_CHECKS)[number], { kind: 'journey' }>;\nexport type SiteSystemJourneyId = JourneyCheck['id'];\n\n/** Every journey check, in the order the journeys register. */\nexport const SITE_SYSTEM_JOURNEY_IDS = Object.freeze(['N3', 'N4', 'N5', 'N6', 'N8', 'K3', 'K4', 'K5', 'K6', 'C4', 'W2', 'C1', 'W9'] as const satisfies readonly SiteSystemJourneyId[]);\n\n/** Desktop widths for N6: both ends and the middle of the compact band, the desktop breakpoint and two wide screens. */\nexport const SITE_SYSTEM_DESKTOP_WIDTHS = Object.freeze([1024, 1100, 1280, 1440, 1920]);\nexport const SITE_SYSTEM_PHONE_VIEWPORT = Object.freeze({ width: 390, height: 844 });\nexport const SITE_SYSTEM_DESKTOP_VIEWPORT = Object.freeze({ width: 1440, height: 900 });\n\n/** The quote action's accessible name when the site does not record one. */\nexport const SITE_SYSTEM_QUOTE_NAME = /\\bquote\\b/i;\n\nexport type SiteSystemActionOrder = 'phone-first' | 'quote-first';\n\nexport interface BrandlabSiteSystemTestOptions {\n /** The adoption tier from brandlab.config.ts (`siteSystem.tier`). C1 registers from `enquiry`. */\n tier: SiteSystemTier;\n /**\n * The release whose journeys register (default: this conformance release). A journey registers only from the\n * release that brings it, so a later journey never turns a site's e2e run red before the gate blocks on it. Name a\n * later release to preview its journeys.\n */\n release?: string;\n /**\n * The sampled pages: home, the money pages (service pages with the enquiry form) and the contact page. `families`\n * (W9, full tier from 3.13.0) names one built page per dynamic route family, such as `/services/blocked-drains` and\n * `/locations/ryde`: its URL variants are checked.\n */\n pages: { home: string; money?: string | readonly string[]; contact?: string; families?: string | readonly string[] };\n /** Desktop widths for N6, each 1024 px or more (default 1024, 1100, 1280, 1440 and 1920). */\n desktopWidths?: readonly number[];\n /** The recorded order of the phone and quote actions (K6), default `phone-first`. */\n actionOrder?: SiteSystemActionOrder;\n /** The quote action's accessible name (default /\\bquote\\b/i), for a recorded label such as \"Book an inspection\". */\n quoteName?: string | RegExp;\n /** The main menu's accessible name (default \"Main\"). */\n navName?: string;\n /** The phone menu button's accessible name (default \"Menu\"). */\n menuName?: string | RegExp;\n /** How long a document may take to load, default 45 seconds; a timeout is retried once. */\n navigationTimeoutMs?: number;\n /** How long to wait for the network to settle after a load, default 10 seconds; a busy network is not a failure. */\n settleTimeoutMs?: number;\n /** The most Tab presses K5 makes on one page (default 400); a longer page is reported, not failed. */\n maxTabStops?: number;\n}\n\nexport interface SiteSystemJourneyPlan {\n tier: SiteSystemTier;\n release: string;\n journeys: readonly SiteSystemJourneyId[];\n home: string;\n money: readonly string[];\n contact: string | undefined;\n /** One page per dynamic route family, for W9's URL variants. */\n families: readonly string[];\n /** Home, the money pages and the contact page, without repeats: K5, K6 and C4 run on each. */\n sampled: readonly string[];\n desktopWidths: readonly number[];\n actionOrder: SiteSystemActionOrder;\n quoteName: RegExp;\n navName: string;\n menuName: string | RegExp;\n navigationTimeoutMs: number;\n settleTimeoutMs: number;\n maxTabStops: number;\n /** Gaps that fail a journey when it runs (fail closed), rather than stopping the whole spec file. */\n problems: Partial<Record<SiteSystemJourneyId, string>>;\n}\n\nexport function siteSystemJourneyTitle(id: SiteSystemJourneyId, text: string): string {\n return `[${id}] ${text}`;\n}\n\n/**\n * The journey checks a tier registers on a release: its own and the tiers below it, each from the release that brings\n * it (default: this conformance release).\n */\nexport function siteSystemJourneysFor(tier: SiteSystemTier, release: string = BRANDLAB_CURRENT_RUNTIME_RELEASE.releaseVersion): SiteSystemJourneyId[] {\n const rank = SITE_SYSTEM_TIERS.indexOf(tier);\n const releaseRank = siteSystemReleaseRank(release);\n const journeys = new Map<string, { tier: string; from: string }>(SITE_SYSTEM_CHECKS.filter((check) => check.kind === 'journey').map((check) => [check.id, check]));\n return SITE_SYSTEM_JOURNEY_IDS.filter((id) => {\n const check = journeys.get(id);\n return check !== undefined\n && SITE_SYSTEM_TIERS.indexOf(check.tier as SiteSystemTier) <= rank\n && siteSystemReleaseRank(check.from) <= releaseRank;\n });\n}\n\nfunction pathProblem(label: string, path: unknown): string | null {\n if (typeof path !== 'string' || !path.startsWith('/') || path.startsWith('//') || /\\s/.test(path)) {\n return `${label} must be a site path starting with \"/\" (got ${JSON.stringify(path)})`;\n }\n return null;\n}\n\n/** Validate the options and fill the defaults. Malformed options throw, listing every problem. */\nexport function planBrandlabSiteSystemJourneys(options: BrandlabSiteSystemTestOptions): SiteSystemJourneyPlan {\n const errors: string[] = [];\n const input = (options ?? {}) as Partial<BrandlabSiteSystemTestOptions>;\n if (!SITE_SYSTEM_TIERS.includes(input.tier as SiteSystemTier)) {\n errors.push(`tier must be one of ${SITE_SYSTEM_TIERS.join(', ')} (got ${JSON.stringify(input.tier)})`);\n }\n const pages = input.pages ?? ({} as BrandlabSiteSystemTestOptions['pages']);\n const homeProblem = pathProblem('pages.home', pages.home);\n if (homeProblem) errors.push(homeProblem);\n const money = pages.money === undefined ? [] : typeof pages.money === 'string' ? [pages.money] : [...pages.money];\n money.forEach((path, index) => {\n const problem = pathProblem(`pages.money[${index}]`, path);\n if (problem) errors.push(problem);\n });\n if (pages.contact !== undefined) {\n const problem = pathProblem('pages.contact', pages.contact);\n if (problem) errors.push(problem);\n }\n const families = pages.families === undefined ? [] : typeof pages.families === 'string' ? [pages.families] : [...pages.families];\n families.forEach((path, index) => {\n const problem = pathProblem(`pages.families[${index}]`, path) ?? (/[?#]/.test(path) || path === '/' ? `pages.families[${index}] must be a page path below home with no query (got ${JSON.stringify(path)})` : null);\n if (problem) errors.push(problem);\n });\n const desktopWidths = input.desktopWidths?.length ? [...input.desktopWidths] : [...SITE_SYSTEM_DESKTOP_WIDTHS];\n for (const width of desktopWidths) {\n if (!Number.isInteger(width) || width < 1024 || width > 3840) errors.push(`desktopWidths must be whole pixel widths from 1024 to 3840 (got ${width})`);\n }\n if (input.actionOrder !== undefined && input.actionOrder !== 'phone-first' && input.actionOrder !== 'quote-first') {\n errors.push(`actionOrder must be phone-first or quote-first (got ${JSON.stringify(input.actionOrder)})`);\n }\n for (const key of ['navigationTimeoutMs', 'settleTimeoutMs', 'maxTabStops'] as const) {\n const value = input[key];\n if (value !== undefined && (!Number.isInteger(value) || value <= 0)) errors.push(`${key} must be a positive whole number (got ${value})`);\n }\n if (input.release !== undefined && (typeof input.release !== 'string' || !/^\\d+\\.\\d+\\.\\d+$/.test(input.release))) {\n errors.push(`release must be a version such as 3.9.0 (got ${JSON.stringify(input.release)})`);\n }\n if (input.navName !== undefined && (typeof input.navName !== 'string' || !input.navName.trim())) errors.push('navName must be a non-empty string');\n if (errors.length > 0) throw new TypeError(`defineBrandlabSiteSystemTests: ${errors.join('; ')}`);\n\n const tier = input.tier as SiteSystemTier;\n const release = input.release ?? BRANDLAB_CURRENT_RUNTIME_RELEASE.releaseVersion;\n const journeys = siteSystemJourneysFor(tier, release);\n const problems: SiteSystemJourneyPlan['problems'] = {};\n if (journeys.includes('C1') && money.length === 0) {\n problems.C1 = 'pages.money names no money page: C1 checks the first screen of each service page with the enquiry form';\n }\n if (journeys.includes('W9') && families.length === 0) {\n problems.W9 = 'pages.families names no page: W9 checks the URL variants of one built page per dynamic route family';\n }\n const quoteName = input.quoteName === undefined\n ? SITE_SYSTEM_QUOTE_NAME\n : input.quoteName instanceof RegExp\n ? input.quoteName\n : new RegExp(`^\\\\s*${input.quoteName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\s*$`, 'i');\n return {\n tier,\n release,\n journeys,\n home: pages.home,\n money,\n contact: pages.contact,\n families: [...new Set(families)],\n sampled: [...new Set([pages.home, ...money, ...(pages.contact ? [pages.contact] : [])])],\n desktopWidths,\n actionOrder: input.actionOrder ?? 'phone-first',\n quoteName,\n navName: input.navName ?? 'Main',\n menuName: input.menuName ?? 'Menu',\n navigationTimeoutMs: input.navigationTimeoutMs ?? 45_000,\n settleTimeoutMs: input.settleTimeoutMs ?? 10_000,\n maxTabStops: input.maxTabStops ?? 400,\n problems,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/site-system/journeys/plan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Options and planning for the site-system journeys: which journeys a tier registers, the sampled pages and the\n * defaults. Pure, so it is unit-tested without a browser.\n */\nimport { BRANDLAB_CURRENT_RUNTIME_RELEASE } from '../../current-release.js';\nimport { detectBrandlabCanaryRelease, detectInstalledBrandlabRelease } from '../../project.js';\nimport { SITE_SYSTEM_CHECKS, SITE_SYSTEM_TIERS, siteSystemReleaseRank, type SiteSystemTier } from '../checks.js';\n\ntype JourneyCheck = Extract<(typeof SITE_SYSTEM_CHECKS)[number], { kind: 'journey' }>;\nexport type SiteSystemJourneyId = JourneyCheck['id'];\n\n/** Every journey check, in the order the journeys register. */\nexport const SITE_SYSTEM_JOURNEY_IDS = Object.freeze(['N3', 'N4', 'N5', 'N6', 'N8', 'K3', 'K4', 'K5', 'K6', 'C4', 'W2', 'C1', 'W9'] as const satisfies readonly SiteSystemJourneyId[]);\n\n/** Desktop widths for N6: both ends and the middle of the compact band, the desktop breakpoint and two wide screens. */\nexport const SITE_SYSTEM_DESKTOP_WIDTHS = Object.freeze([1024, 1100, 1280, 1440, 1920]);\nexport const SITE_SYSTEM_PHONE_VIEWPORT = Object.freeze({ width: 390, height: 844 });\nexport const SITE_SYSTEM_DESKTOP_VIEWPORT = Object.freeze({ width: 1440, height: 900 });\n\n/** The quote action's accessible name when the site does not record one. */\nexport const SITE_SYSTEM_QUOTE_NAME = /\\bquote\\b/i;\n\nexport type SiteSystemActionOrder = 'phone-first' | 'quote-first';\n\nexport interface BrandlabSiteSystemTestOptions {\n /** The adoption tier from brandlab.config.ts (`siteSystem.tier`). C1 registers from `enquiry`. */\n tier: SiteSystemTier;\n /**\n * The release whose journeys register. `defineBrandlabSiteSystemTests` defaults it to the site's installed Brandlab\n * release, read from its package.json as `brandlab-ready` reads it (one exact version, or one canary such as\n * `3.15.0-canary.2`), else this conformance release. A journey registers only from the release that brings it, so a\n * later journey never turns a site's e2e run red before the gate blocks on it, and a check that blocks has its\n * journey. Name a later release to preview its journeys.\n */\n release?: string;\n /**\n * The sampled pages: home, the money pages (service pages with the enquiry form) and the contact page. `families`\n * (W9, full tier from 3.13.0) names one built page per dynamic route family, such as `/services/blocked-drains` and\n * `/locations/ryde`: its URL variants are checked.\n */\n pages: { home: string; money?: string | readonly string[]; contact?: string; families?: string | readonly string[] };\n /** Desktop widths for N6, each 1024 px or more (default 1024, 1100, 1280, 1440 and 1920). */\n desktopWidths?: readonly number[];\n /** The recorded order of the phone and quote actions (K6), default `phone-first`. */\n actionOrder?: SiteSystemActionOrder;\n /** The quote action's accessible name (default /\\bquote\\b/i), for a recorded label such as \"Book an inspection\". */\n quoteName?: string | RegExp;\n /** The main menu's accessible name (default \"Main\"). */\n navName?: string;\n /** The phone menu button's accessible name (default \"Menu\"). */\n menuName?: string | RegExp;\n /** How long a document may take to load, default 45 seconds; a timeout is retried once. */\n navigationTimeoutMs?: number;\n /** How long to wait for the network to settle after a load, default 10 seconds; a busy network is not a failure. */\n settleTimeoutMs?: number;\n /** The most Tab presses K5 makes on one page (default 400); a longer page is reported, not failed. */\n maxTabStops?: number;\n}\n\nexport interface SiteSystemJourneyPlan {\n tier: SiteSystemTier;\n release: string;\n journeys: readonly SiteSystemJourneyId[];\n home: string;\n money: readonly string[];\n contact: string | undefined;\n /** One page per dynamic route family, for W9's URL variants. */\n families: readonly string[];\n /** Home, the money pages and the contact page, without repeats: K5, K6 and C4 run on each. */\n sampled: readonly string[];\n desktopWidths: readonly number[];\n actionOrder: SiteSystemActionOrder;\n quoteName: RegExp;\n navName: string;\n menuName: string | RegExp;\n navigationTimeoutMs: number;\n settleTimeoutMs: number;\n maxTabStops: number;\n /** Gaps that fail a journey when it runs (fail closed), rather than stopping the whole spec file. */\n problems: Partial<Record<SiteSystemJourneyId, string>>;\n}\n\nexport function siteSystemJourneyTitle(id: SiteSystemJourneyId, text: string): string {\n return `[${id}] ${text}`;\n}\n\n/**\n * The journey checks a tier registers on a release: its own and the tiers below it, each from the release that brings\n * it (default: this conformance release).\n */\nexport function siteSystemJourneysFor(tier: SiteSystemTier, release: string = BRANDLAB_CURRENT_RUNTIME_RELEASE.releaseVersion): SiteSystemJourneyId[] {\n const rank = SITE_SYSTEM_TIERS.indexOf(tier);\n const releaseRank = siteSystemReleaseRank(release);\n const journeys = new Map<string, { tier: string; from: string }>(SITE_SYSTEM_CHECKS.filter((check) => check.kind === 'journey').map((check) => [check.id, check]));\n return SITE_SYSTEM_JOURNEY_IDS.filter((id) => {\n const check = journeys.get(id);\n return check !== undefined\n && SITE_SYSTEM_TIERS.indexOf(check.tier as SiteSystemTier) <= rank\n && siteSystemReleaseRank(check.from) <= releaseRank;\n });\n}\n\n/**\n * The release the journeys register for on a site: its installed Brandlab release as `brandlab-ready` reads it (all\n * four packages at one exact version, or one canary, from package.json), else this conformance release. A canary's\n * own release manifest still names the last published release, so without this its new journeys (W2 and W9 on\n * 3.15.0-canary.2) would not register while the gate blocks on them.\n */\nexport function siteSystemJourneyRelease(packageJson: Parameters<typeof detectInstalledBrandlabRelease>[0]): string {\n return detectInstalledBrandlabRelease(packageJson) ?? detectBrandlabCanaryRelease(packageJson)?.version ?? BRANDLAB_CURRENT_RUNTIME_RELEASE.releaseVersion;\n}\n\nfunction pathProblem(label: string, path: unknown): string | null {\n if (typeof path !== 'string' || !path.startsWith('/') || path.startsWith('//') || /\\s/.test(path)) {\n return `${label} must be a site path starting with \"/\" (got ${JSON.stringify(path)})`;\n }\n return null;\n}\n\n/** Validate the options and fill the defaults. Malformed options throw, listing every problem. */\nexport function planBrandlabSiteSystemJourneys(options: BrandlabSiteSystemTestOptions): SiteSystemJourneyPlan {\n const errors: string[] = [];\n const input = (options ?? {}) as Partial<BrandlabSiteSystemTestOptions>;\n if (!SITE_SYSTEM_TIERS.includes(input.tier as SiteSystemTier)) {\n errors.push(`tier must be one of ${SITE_SYSTEM_TIERS.join(', ')} (got ${JSON.stringify(input.tier)})`);\n }\n const pages = input.pages ?? ({} as BrandlabSiteSystemTestOptions['pages']);\n const homeProblem = pathProblem('pages.home', pages.home);\n if (homeProblem) errors.push(homeProblem);\n const money = pages.money === undefined ? [] : typeof pages.money === 'string' ? [pages.money] : [...pages.money];\n money.forEach((path, index) => {\n const problem = pathProblem(`pages.money[${index}]`, path);\n if (problem) errors.push(problem);\n });\n if (pages.contact !== undefined) {\n const problem = pathProblem('pages.contact', pages.contact);\n if (problem) errors.push(problem);\n }\n const families = pages.families === undefined ? [] : typeof pages.families === 'string' ? [pages.families] : [...pages.families];\n families.forEach((path, index) => {\n const problem = pathProblem(`pages.families[${index}]`, path) ?? (/[?#]/.test(path) || path === '/' ? `pages.families[${index}] must be a page path below home with no query (got ${JSON.stringify(path)})` : null);\n if (problem) errors.push(problem);\n });\n const desktopWidths = input.desktopWidths?.length ? [...input.desktopWidths] : [...SITE_SYSTEM_DESKTOP_WIDTHS];\n for (const width of desktopWidths) {\n if (!Number.isInteger(width) || width < 1024 || width > 3840) errors.push(`desktopWidths must be whole pixel widths from 1024 to 3840 (got ${width})`);\n }\n if (input.actionOrder !== undefined && input.actionOrder !== 'phone-first' && input.actionOrder !== 'quote-first') {\n errors.push(`actionOrder must be phone-first or quote-first (got ${JSON.stringify(input.actionOrder)})`);\n }\n for (const key of ['navigationTimeoutMs', 'settleTimeoutMs', 'maxTabStops'] as const) {\n const value = input[key];\n if (value !== undefined && (!Number.isInteger(value) || value <= 0)) errors.push(`${key} must be a positive whole number (got ${value})`);\n }\n if (input.release !== undefined && (typeof input.release !== 'string' || !/^\\d+\\.\\d+\\.\\d+(?:-canary\\.\\d+)?$/.test(input.release))) {\n errors.push(`release must be a version such as 3.9.0 or 3.15.0-canary.2 (got ${JSON.stringify(input.release)})`);\n }\n if (input.navName !== undefined && (typeof input.navName !== 'string' || !input.navName.trim())) errors.push('navName must be a non-empty string');\n if (errors.length > 0) throw new TypeError(`defineBrandlabSiteSystemTests: ${errors.join('; ')}`);\n\n const tier = input.tier as SiteSystemTier;\n const release = input.release ?? BRANDLAB_CURRENT_RUNTIME_RELEASE.releaseVersion;\n const journeys = siteSystemJourneysFor(tier, release);\n const problems: SiteSystemJourneyPlan['problems'] = {};\n if (journeys.includes('C1') && money.length === 0) {\n problems.C1 = 'pages.money names no money page: C1 checks the first screen of each service page with the enquiry form';\n }\n if (journeys.includes('W9') && families.length === 0) {\n problems.W9 = 'pages.families names no page: W9 checks the URL variants of one built page per dynamic route family';\n }\n const quoteName = input.quoteName === undefined\n ? SITE_SYSTEM_QUOTE_NAME\n : input.quoteName instanceof RegExp\n ? input.quoteName\n : new RegExp(`^\\\\s*${input.quoteName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\s*$`, 'i');\n return {\n tier,\n release,\n journeys,\n home: pages.home,\n money,\n contact: pages.contact,\n families: [...new Set(families)],\n sampled: [...new Set([pages.home, ...money, ...(pages.contact ? [pages.contact] : [])])],\n desktopWidths,\n actionOrder: input.actionOrder ?? 'phone-first',\n quoteName,\n navName: input.navName ?? 'Main',\n menuName: input.menuName ?? 'Menu',\n navigationTimeoutMs: input.navigationTimeoutMs ?? 45_000,\n settleTimeoutMs: input.settleTimeoutMs ?? 10_000,\n maxTabStops: input.maxTabStops ?? 400,\n problems,\n };\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* N6 and N8: the header at every desktop width, and the phone drawer and call bar. The header stays at the top with a
|
|
3
3
|
* readable phone and the quote action from 1024 px up; the drawer is a modal dialog that starts on its close button,
|
|
4
|
-
* keeps focus, closes on Escape, a link tap and a widening past
|
|
4
|
+
* keeps focus, closes on Escape, a link tap and a widening past the 1200 px desktop breakpoint; the call bar's phone reports `fab`.
|
|
5
5
|
*/
|
|
6
6
|
import { type Locator, type Page } from '@playwright/test';
|
|
7
7
|
import { type SiteSystemJourneyPlan } from './plan.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* N6 and N8: the header at every desktop width, and the phone drawer and call bar. The header stays at the top with a
|
|
3
3
|
* readable phone and the quote action from 1024 px up; the drawer is a modal dialog that starts on its close button,
|
|
4
|
-
* keeps focus, closes on Escape, a link tap and a widening past
|
|
4
|
+
* keeps focus, closes on Escape, a link tap and a widening past the 1200 px desktop breakpoint; the call bar's phone reports `fab`.
|
|
5
5
|
*/
|
|
6
6
|
import { expect, test } from '@playwright/test';
|
|
7
7
|
import { SITE_SYSTEM_AXE_TAGS, describeAxe, mainNavigation, note, openSitePage, raiseTimeout, runAxe, seriousOrCritical, settle, siteHeader, waitUntil, } from './browser.js';
|
|
@@ -244,7 +244,7 @@ export function defineShellJourneys(plan, runs) {
|
|
|
244
244
|
await page.waitForTimeout(300);
|
|
245
245
|
button = menuButton(await siteHeader(page), plan);
|
|
246
246
|
}
|
|
247
|
-
expect(await button.count(), `no visible "${String(plan.menuName)}" button below
|
|
247
|
+
expect(await button.count(), `no visible "${String(plan.menuName)}" button below 1200 px`).toBe(1);
|
|
248
248
|
expect(await openDrawer(page, button, 'click'), 'the Menu button showed no dialog').not.toBeNull();
|
|
249
249
|
await page.setViewportSize({ width: 1440, height: 800 });
|
|
250
250
|
await page.waitForTimeout(400);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../../src/site-system/journeys/shell.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * N6 and N8: the header at every desktop width, and the phone drawer and call bar. The header stays at the top with a\n * readable phone and the quote action from 1024 px up; the drawer is a modal dialog that starts on its close button,\n * keeps focus, closes on Escape, a link tap and a widening past 1280 px; the call bar's phone reports `fab`.\n */\nimport { expect, test, type Locator, type Page } from '@playwright/test';\nimport {\n SITE_SYSTEM_AXE_TAGS,\n describeAxe,\n mainNavigation,\n note,\n openSitePage,\n raiseTimeout,\n runAxe,\n seriousOrCritical,\n settle,\n siteHeader,\n waitUntil,\n} from './browser.js';\nimport { SITE_SYSTEM_PHONE_VIEWPORT, siteSystemJourneyTitle as title, type SiteSystemJourneyPlan } from './plan.js';\n\n/** The visible phone menu button in the header. */\nexport function menuButton(header: Locator, plan: Pick<SiteSystemJourneyPlan, 'menuName'>): Locator {\n const name = plan.menuName;\n return header.getByRole('button', typeof name === 'string' ? { name, exact: true } : { name }).filter({ visible: true }).first();\n}\n\n/** The drawer the menu button opens: the element its aria-controls names, else the visible dialog. Marked `drawer`. */\nexport async function openDrawer(page: Page, button: Locator, how: 'tap' | 'click'): Promise<Locator | null> {\n await (how === 'tap' ? button.tap() : button.click());\n const controls = (await button.getAttribute('aria-controls'))?.trim();\n const named = controls ? page.locator(`[id=\"${controls.replace(/[\"\\\\]/g, '\\\\$&')}\"]`) : null;\n const drawer = named && (await named.count()) === 1 ? named : page.getByRole('dialog').filter({ visible: true }).first();\n if (!(await waitUntil(async () => (await drawer.count()) > 0 && (await drawer.isVisible()), 1_000))) return null;\n await page.waitForTimeout(250);\n await drawer.evaluate((element) => window.__brandlabSiteSystem.markElement(element, 'drawer'));\n return drawer;\n}\n\n/** Whether any dialog is still open or shown. */\nexport async function anyDialogOpen(page: Page): Promise<boolean> {\n return page.evaluate(() => Array.from(document.querySelectorAll('dialog')).some((dialog) => dialog.open)\n || Array.from(document.querySelectorAll('[role=\"dialog\"]')).some((dialog) => window.__brandlabSiteSystem.isRendered(dialog)));\n}\n\n/**\n * Scroll a phone page down past its hero, half a screen at a time, until a call bar shows; return its phone links,\n * or null when none shows before the end of the page.\n */\nexport async function callBarLinks(page: Page): Promise<{ description: string; placement: string; invalid: string | null }[] | null> {\n let previous = -1;\n for (let screens = 1; screens <= 8; screens += 0.5) {\n const scrolled = await page.evaluate((factor) => {\n window.scrollTo({ top: window.innerHeight * factor, behavior: 'instant' });\n return window.scrollY;\n }, screens);\n if (scrolled === previous) return null;\n previous = scrolled;\n await page.waitForTimeout(250);\n const links = await page.evaluate(() => {\n const helpers = window.__brandlabSiteSystem;\n const bar = helpers.findCallBar();\n if (!bar) return null;\n helpers.markElement(bar, 'call-bar');\n return Array.from(bar.querySelectorAll('a[href^=\"tel:\"]')).filter(helpers.isRendered)\n .map((link) => ({ description: helpers.describeElement(link), ...helpers.phonePlacement(link) }));\n });\n if (links) return links;\n }\n return null;\n}\n\nexport function defineShellJourneys(plan: SiteSystemJourneyPlan, runs: ReadonlySet<string>): void {\n const quote = { source: plan.quoteName.source, flags: plan.quoteName.flags };\n\n if (runs.has('N6')) {\n test.describe('header at desktop widths', () => {\n for (const width of plan.desktopWidths) {\n test(title('N6', `the header stays at the top with the phone and quote visible at ${width} px`), async ({ page }, testInfo) => {\n await page.setViewportSize({ width, height: 900 });\n await openSitePage(page, plan.home, plan);\n const header = await siteHeader(page);\n expect(await header.count(), `${plan.home} has no header (a <header> banner landmark)`).toBe(1);\n const problems: string[] = [];\n const inspect = async (moment: string) => {\n const seen = await header.evaluate((element, name) => {\n const helpers = window.__brandlabSiteSystem;\n const inView = (node: Element) => {\n const rect = node.getBoundingClientRect();\n return rect.top >= -1 && rect.bottom <= window.innerHeight + 1;\n };\n const phones = Array.from(element.querySelectorAll('a[href^=\"tel:\"]')).filter(helpers.isRendered);\n const readable = phones.filter((link) => ((link as HTMLElement).innerText.match(/\\d/g) ?? []).length >= 6 && inView(link));\n return { phones: phones.length, readable: readable.length, quotes: helpers.quoteActions(element, name).filter(inView).length };\n }, quote);\n if (seen.readable === 0) problems.push(`${moment}: no phone number is readable in the header (${seen.phones} phone link(s) without the number)`);\n if (seen.quotes === 0) problems.push(`${moment}: no quote action is visible in the header`);\n };\n await inspect('at the top');\n const nav = await mainNavigation(page, plan);\n if (!nav && !(await menuButton(header, plan).count())) problems.push(`neither the menu named \"${plan.navName}\" nor a Menu button is visible`);\n const scrolled = await page.evaluate(() => {\n window.scrollTo({ top: 2_000, behavior: 'instant' });\n return window.scrollY;\n });\n await page.waitForTimeout(300);\n if (scrolled < 400) note(testInfo, `${plan.home} at ${width} px scrolls only ${scrolled} px, too little to show whether the header stays at the top`);\n const top = await header.evaluate((element) => Math.round(element.getBoundingClientRect().top));\n if (scrolled > 0 && Math.abs(top) > 1) problems.push(`after scrolling ${scrolled} px the header's top is at ${top} px (expected 0: keep it sticky)`);\n if (scrolled > 0) await inspect(`after scrolling ${scrolled} px`);\n const overflow = await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth);\n if (overflow > 0) problems.push(`the page scrolls sideways by ${overflow} px`);\n expect(problems).toEqual([]);\n });\n }\n });\n }\n\n if (!runs.has('N8')) return;\n\n test.describe('phone drawer and call bar at 390 px', () => {\n test.use({ viewport: { ...SITE_SYSTEM_PHONE_VIEWPORT }, isMobile: true, hasTouch: true });\n\n test(title('N8', 'the Menu button opens a modal drawer that starts on its close button, keeps focus inside and closes on Escape'), async ({ page }, testInfo) => {\n await openSitePage(page, plan.home, plan);\n const header = await siteHeader(page);\n const button = menuButton(header, plan);\n expect(await button.count(), `no visible \"${String(plan.menuName)}\" button in the header at 390 px`).toBe(1);\n const drawer = await openDrawer(page, button, 'tap');\n expect(drawer, 'tapping the Menu button showed no dialog').not.toBeNull();\n const problems: string[] = [];\n const facts = await drawer!.evaluate((element) => ({\n modal: (element instanceof HTMLDialogElement && element.matches(':modal')) || element.getAttribute('aria-modal') === 'true',\n focus: element.contains(document.activeElement) ? window.__brandlabSiteSystem.accessibleName(document.activeElement!) : null,\n }));\n if (!facts.modal) problems.push('the drawer is not a modal dialog (showModal() or aria-modal=\"true\")');\n if (facts.focus === null) problems.push('focus did not move into the drawer');\n else if (!/close/i.test(facts.focus)) problems.push(`focus starts on \"${facts.focus}\", not the close button`);\n\n const groups = drawer!.locator('button[aria-expanded], summary').filter({ visible: true });\n const groupCount = await groups.count();\n if (groupCount > 0) {\n await groups.nth(0).tap();\n if (groupCount > 1) await groups.nth(1).tap();\n await page.waitForTimeout(150);\n const expanded = await drawer!.evaluate((element) => element.querySelectorAll('button[aria-expanded=\"true\"]').length + element.querySelectorAll('details[open]').length);\n if (expanded !== 1) problems.push(`opening drawer groups left ${expanded} open (one at a time)`);\n } else note(testInfo, 'The drawer has no groups.');\n\n const escaped: string[] = [];\n for (let press = 0; press < 40; press += 1) {\n await page.keyboard.press('Tab');\n const outside = await drawer!.evaluate((element) => {\n const active = document.activeElement;\n if (!active || active === document.body || element.contains(active)) return null;\n return window.__brandlabSiteSystem.describeElement(active);\n });\n if (outside) escaped.push(outside);\n }\n if (escaped.length) problems.push(`Tab moved focus out of the drawer to ${[...new Set(escaped)].slice(0, 3).join(', ')}`);\n await page.keyboard.press('Escape');\n await page.waitForTimeout(300);\n if (await anyDialogOpen(page)) problems.push('Escape did not close the drawer');\n expect(problems).toEqual([]);\n });\n\n test(title('N8', 'axe finds no serious or critical issue with the drawer open'), async ({ page }) => {\n await openSitePage(page, plan.home, plan);\n const drawer = await openDrawer(page, menuButton(await siteHeader(page), plan), 'tap');\n expect(drawer, 'tapping the Menu button showed no dialog').not.toBeNull();\n const outcome = await runAxe(page, ['[data-brandlab-journey~=\"drawer\"]'], { tags: SITE_SYSTEM_AXE_TAGS });\n expect(describeAxe(seriousOrCritical(outcome.violations))).toEqual([]);\n });\n\n test(title('N8', 'a link tap in the drawer closes it and loads the page'), async ({ page }) => {\n await openSitePage(page, plan.home, plan);\n const drawer = await openDrawer(page, menuButton(await siteHeader(page), plan), 'tap');\n expect(drawer, 'tapping the Menu button showed no dialog').not.toBeNull();\n const href = await drawer!.evaluate((element) => {\n const link = Array.from(element.querySelectorAll<HTMLAnchorElement>('a[href]')).find((anchor) => window.__brandlabSiteSystem.isRendered(anchor)\n && anchor.origin === location.origin && anchor.pathname !== location.pathname);\n if (!link) return null;\n window.__brandlabSiteSystem.markElement(link, 'drawer-link');\n return link.pathname;\n });\n expect(href, 'the open drawer shows no link to another page').not.toBeNull();\n await page.locator('[data-brandlab-journey~=\"drawer-link\"]').tap();\n await page.waitForURL((url) => url.pathname === href, { timeout: plan.navigationTimeoutMs });\n await settle(page, plan.settleTimeoutMs);\n expect(await anyDialogOpen(page), `the drawer is still open on ${href}`).toBe(false);\n });\n\n test(title('N8', 'the phone header shows a call control named with the number, and no page scrolls sideways at 390 px'), async ({ page }, testInfo) => {\n raiseTimeout(testInfo, 180_000);\n const problems: string[] = [];\n for (const path of plan.sampled) {\n await openSitePage(page, path, plan);\n await siteHeader(page);\n // Against the device width: a phone browser widens its layout viewport (and innerWidth) to overflowing content.\n const seen = await page.evaluate((width) => {\n const helpers = window.__brandlabSiteSystem;\n const header = document.querySelector('[data-brandlab-journey~=\"header\"]');\n const calls = Array.from(header?.querySelectorAll('a[href^=\"tel:\"]') ?? []).filter(helpers.isRendered)\n .map((link) => ({ description: helpers.describeElement(link), digits: (helpers.accessibleName(link).match(/\\d/g) ?? []).length }));\n return { calls, overflow: document.documentElement.scrollWidth - width };\n }, SITE_SYSTEM_PHONE_VIEWPORT.width);\n if (seen.calls.length === 0) problems.push(`${path}: the phone header shows no call control`);\n for (const call of seen.calls) {\n if (call.digits < 6) problems.push(`${path}: the header's ${call.description} is not named with the phone number`);\n }\n if (seen.overflow > 0) problems.push(`${path}: the page scrolls sideways by ${seen.overflow} px at 390 px`);\n }\n note(testInfo, `Checked ${plan.sampled.join(', ')}`);\n expect(problems).toEqual([]);\n });\n\n test(title('N8', 'the call bar\\'s phone reports placement fab'), async ({ page }, testInfo) => {\n raiseTimeout(testInfo, 180_000);\n const problems: string[] = [];\n for (const path of [plan.home, ...plan.money]) {\n await openSitePage(page, path, plan);\n const links = await callBarLinks(page);\n if (!links) {\n note(testInfo, `${path}: no call bar showed after scrolling.`);\n continue;\n }\n if (links.length === 0) problems.push(`${path}: the call bar shows no phone link`);\n for (const link of links) {\n if (link.placement !== 'fab' || link.invalid) problems.push(`${path}: ${link.description} reports placement ${link.placement}${link.invalid ? ` (it declares \"${link.invalid}\")` : ''}, not fab`);\n }\n }\n expect(problems).toEqual([]);\n });\n });\n\n test.describe('drawer across the desktop breakpoint', () => {\n test(title('N8', 'widening past 1280 px closes the drawer and leaves the page usable'), async ({ page }) => {\n await page.setViewportSize({ width: 1100, height: 800 });\n await openSitePage(page, plan.home, plan);\n let button = menuButton(await siteHeader(page), plan);\n if (!(await button.count())) {\n await page.setViewportSize({ ...SITE_SYSTEM_PHONE_VIEWPORT });\n await page.waitForTimeout(300);\n button = menuButton(await siteHeader(page), plan);\n }\n expect(await button.count(), `no visible \"${String(plan.menuName)}\" button below 1280 px`).toBe(1);\n expect(await openDrawer(page, button, 'click'), 'the Menu button showed no dialog').not.toBeNull();\n await page.setViewportSize({ width: 1440, height: 800 });\n await page.waitForTimeout(400);\n const problems: string[] = [];\n if (await anyDialogOpen(page)) problems.push('the drawer stayed open at 1440 px');\n const usable = await page.evaluate(() => {\n const hit = document.elementFromPoint(window.innerWidth / 2, window.innerHeight * 0.75);\n const locked = [document.documentElement, document.body].some((element) => getComputedStyle(element).overflowY === 'hidden');\n return { covered: Boolean(hit?.closest('dialog, [role=\"dialog\"]')), inert: document.body.inert || Boolean(document.querySelector('main')?.closest('[inert]')), locked };\n });\n if (usable.covered) problems.push('a dialog still covers the page at 1440 px');\n if (usable.inert) problems.push('the page is still inert at 1440 px');\n if (usable.locked) problems.push('page scrolling is still locked at 1440 px');\n expect(problems).toEqual([]);\n });\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../../src/site-system/journeys/shell.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * N6 and N8: the header at every desktop width, and the phone drawer and call bar. The header stays at the top with a\n * readable phone and the quote action from 1024 px up; the drawer is a modal dialog that starts on its close button,\n * keeps focus, closes on Escape, a link tap and a widening past the 1200 px desktop breakpoint; the call bar's phone reports `fab`.\n */\nimport { expect, test, type Locator, type Page } from '@playwright/test';\nimport {\n SITE_SYSTEM_AXE_TAGS,\n describeAxe,\n mainNavigation,\n note,\n openSitePage,\n raiseTimeout,\n runAxe,\n seriousOrCritical,\n settle,\n siteHeader,\n waitUntil,\n} from './browser.js';\nimport { SITE_SYSTEM_PHONE_VIEWPORT, siteSystemJourneyTitle as title, type SiteSystemJourneyPlan } from './plan.js';\n\n/** The visible phone menu button in the header. */\nexport function menuButton(header: Locator, plan: Pick<SiteSystemJourneyPlan, 'menuName'>): Locator {\n const name = plan.menuName;\n return header.getByRole('button', typeof name === 'string' ? { name, exact: true } : { name }).filter({ visible: true }).first();\n}\n\n/** The drawer the menu button opens: the element its aria-controls names, else the visible dialog. Marked `drawer`. */\nexport async function openDrawer(page: Page, button: Locator, how: 'tap' | 'click'): Promise<Locator | null> {\n await (how === 'tap' ? button.tap() : button.click());\n const controls = (await button.getAttribute('aria-controls'))?.trim();\n const named = controls ? page.locator(`[id=\"${controls.replace(/[\"\\\\]/g, '\\\\$&')}\"]`) : null;\n const drawer = named && (await named.count()) === 1 ? named : page.getByRole('dialog').filter({ visible: true }).first();\n if (!(await waitUntil(async () => (await drawer.count()) > 0 && (await drawer.isVisible()), 1_000))) return null;\n await page.waitForTimeout(250);\n await drawer.evaluate((element) => window.__brandlabSiteSystem.markElement(element, 'drawer'));\n return drawer;\n}\n\n/** Whether any dialog is still open or shown. */\nexport async function anyDialogOpen(page: Page): Promise<boolean> {\n return page.evaluate(() => Array.from(document.querySelectorAll('dialog')).some((dialog) => dialog.open)\n || Array.from(document.querySelectorAll('[role=\"dialog\"]')).some((dialog) => window.__brandlabSiteSystem.isRendered(dialog)));\n}\n\n/**\n * Scroll a phone page down past its hero, half a screen at a time, until a call bar shows; return its phone links,\n * or null when none shows before the end of the page.\n */\nexport async function callBarLinks(page: Page): Promise<{ description: string; placement: string; invalid: string | null }[] | null> {\n let previous = -1;\n for (let screens = 1; screens <= 8; screens += 0.5) {\n const scrolled = await page.evaluate((factor) => {\n window.scrollTo({ top: window.innerHeight * factor, behavior: 'instant' });\n return window.scrollY;\n }, screens);\n if (scrolled === previous) return null;\n previous = scrolled;\n await page.waitForTimeout(250);\n const links = await page.evaluate(() => {\n const helpers = window.__brandlabSiteSystem;\n const bar = helpers.findCallBar();\n if (!bar) return null;\n helpers.markElement(bar, 'call-bar');\n return Array.from(bar.querySelectorAll('a[href^=\"tel:\"]')).filter(helpers.isRendered)\n .map((link) => ({ description: helpers.describeElement(link), ...helpers.phonePlacement(link) }));\n });\n if (links) return links;\n }\n return null;\n}\n\nexport function defineShellJourneys(plan: SiteSystemJourneyPlan, runs: ReadonlySet<string>): void {\n const quote = { source: plan.quoteName.source, flags: plan.quoteName.flags };\n\n if (runs.has('N6')) {\n test.describe('header at desktop widths', () => {\n for (const width of plan.desktopWidths) {\n test(title('N6', `the header stays at the top with the phone and quote visible at ${width} px`), async ({ page }, testInfo) => {\n await page.setViewportSize({ width, height: 900 });\n await openSitePage(page, plan.home, plan);\n const header = await siteHeader(page);\n expect(await header.count(), `${plan.home} has no header (a <header> banner landmark)`).toBe(1);\n const problems: string[] = [];\n const inspect = async (moment: string) => {\n const seen = await header.evaluate((element, name) => {\n const helpers = window.__brandlabSiteSystem;\n const inView = (node: Element) => {\n const rect = node.getBoundingClientRect();\n return rect.top >= -1 && rect.bottom <= window.innerHeight + 1;\n };\n const phones = Array.from(element.querySelectorAll('a[href^=\"tel:\"]')).filter(helpers.isRendered);\n const readable = phones.filter((link) => ((link as HTMLElement).innerText.match(/\\d/g) ?? []).length >= 6 && inView(link));\n return { phones: phones.length, readable: readable.length, quotes: helpers.quoteActions(element, name).filter(inView).length };\n }, quote);\n if (seen.readable === 0) problems.push(`${moment}: no phone number is readable in the header (${seen.phones} phone link(s) without the number)`);\n if (seen.quotes === 0) problems.push(`${moment}: no quote action is visible in the header`);\n };\n await inspect('at the top');\n const nav = await mainNavigation(page, plan);\n if (!nav && !(await menuButton(header, plan).count())) problems.push(`neither the menu named \"${plan.navName}\" nor a Menu button is visible`);\n const scrolled = await page.evaluate(() => {\n window.scrollTo({ top: 2_000, behavior: 'instant' });\n return window.scrollY;\n });\n await page.waitForTimeout(300);\n if (scrolled < 400) note(testInfo, `${plan.home} at ${width} px scrolls only ${scrolled} px, too little to show whether the header stays at the top`);\n const top = await header.evaluate((element) => Math.round(element.getBoundingClientRect().top));\n if (scrolled > 0 && Math.abs(top) > 1) problems.push(`after scrolling ${scrolled} px the header's top is at ${top} px (expected 0: keep it sticky)`);\n if (scrolled > 0) await inspect(`after scrolling ${scrolled} px`);\n const overflow = await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth);\n if (overflow > 0) problems.push(`the page scrolls sideways by ${overflow} px`);\n expect(problems).toEqual([]);\n });\n }\n });\n }\n\n if (!runs.has('N8')) return;\n\n test.describe('phone drawer and call bar at 390 px', () => {\n test.use({ viewport: { ...SITE_SYSTEM_PHONE_VIEWPORT }, isMobile: true, hasTouch: true });\n\n test(title('N8', 'the Menu button opens a modal drawer that starts on its close button, keeps focus inside and closes on Escape'), async ({ page }, testInfo) => {\n await openSitePage(page, plan.home, plan);\n const header = await siteHeader(page);\n const button = menuButton(header, plan);\n expect(await button.count(), `no visible \"${String(plan.menuName)}\" button in the header at 390 px`).toBe(1);\n const drawer = await openDrawer(page, button, 'tap');\n expect(drawer, 'tapping the Menu button showed no dialog').not.toBeNull();\n const problems: string[] = [];\n const facts = await drawer!.evaluate((element) => ({\n modal: (element instanceof HTMLDialogElement && element.matches(':modal')) || element.getAttribute('aria-modal') === 'true',\n focus: element.contains(document.activeElement) ? window.__brandlabSiteSystem.accessibleName(document.activeElement!) : null,\n }));\n if (!facts.modal) problems.push('the drawer is not a modal dialog (showModal() or aria-modal=\"true\")');\n if (facts.focus === null) problems.push('focus did not move into the drawer');\n else if (!/close/i.test(facts.focus)) problems.push(`focus starts on \"${facts.focus}\", not the close button`);\n\n const groups = drawer!.locator('button[aria-expanded], summary').filter({ visible: true });\n const groupCount = await groups.count();\n if (groupCount > 0) {\n await groups.nth(0).tap();\n if (groupCount > 1) await groups.nth(1).tap();\n await page.waitForTimeout(150);\n const expanded = await drawer!.evaluate((element) => element.querySelectorAll('button[aria-expanded=\"true\"]').length + element.querySelectorAll('details[open]').length);\n if (expanded !== 1) problems.push(`opening drawer groups left ${expanded} open (one at a time)`);\n } else note(testInfo, 'The drawer has no groups.');\n\n const escaped: string[] = [];\n for (let press = 0; press < 40; press += 1) {\n await page.keyboard.press('Tab');\n const outside = await drawer!.evaluate((element) => {\n const active = document.activeElement;\n if (!active || active === document.body || element.contains(active)) return null;\n return window.__brandlabSiteSystem.describeElement(active);\n });\n if (outside) escaped.push(outside);\n }\n if (escaped.length) problems.push(`Tab moved focus out of the drawer to ${[...new Set(escaped)].slice(0, 3).join(', ')}`);\n await page.keyboard.press('Escape');\n await page.waitForTimeout(300);\n if (await anyDialogOpen(page)) problems.push('Escape did not close the drawer');\n expect(problems).toEqual([]);\n });\n\n test(title('N8', 'axe finds no serious or critical issue with the drawer open'), async ({ page }) => {\n await openSitePage(page, plan.home, plan);\n const drawer = await openDrawer(page, menuButton(await siteHeader(page), plan), 'tap');\n expect(drawer, 'tapping the Menu button showed no dialog').not.toBeNull();\n const outcome = await runAxe(page, ['[data-brandlab-journey~=\"drawer\"]'], { tags: SITE_SYSTEM_AXE_TAGS });\n expect(describeAxe(seriousOrCritical(outcome.violations))).toEqual([]);\n });\n\n test(title('N8', 'a link tap in the drawer closes it and loads the page'), async ({ page }) => {\n await openSitePage(page, plan.home, plan);\n const drawer = await openDrawer(page, menuButton(await siteHeader(page), plan), 'tap');\n expect(drawer, 'tapping the Menu button showed no dialog').not.toBeNull();\n const href = await drawer!.evaluate((element) => {\n const link = Array.from(element.querySelectorAll<HTMLAnchorElement>('a[href]')).find((anchor) => window.__brandlabSiteSystem.isRendered(anchor)\n && anchor.origin === location.origin && anchor.pathname !== location.pathname);\n if (!link) return null;\n window.__brandlabSiteSystem.markElement(link, 'drawer-link');\n return link.pathname;\n });\n expect(href, 'the open drawer shows no link to another page').not.toBeNull();\n await page.locator('[data-brandlab-journey~=\"drawer-link\"]').tap();\n await page.waitForURL((url) => url.pathname === href, { timeout: plan.navigationTimeoutMs });\n await settle(page, plan.settleTimeoutMs);\n expect(await anyDialogOpen(page), `the drawer is still open on ${href}`).toBe(false);\n });\n\n test(title('N8', 'the phone header shows a call control named with the number, and no page scrolls sideways at 390 px'), async ({ page }, testInfo) => {\n raiseTimeout(testInfo, 180_000);\n const problems: string[] = [];\n for (const path of plan.sampled) {\n await openSitePage(page, path, plan);\n await siteHeader(page);\n // Against the device width: a phone browser widens its layout viewport (and innerWidth) to overflowing content.\n const seen = await page.evaluate((width) => {\n const helpers = window.__brandlabSiteSystem;\n const header = document.querySelector('[data-brandlab-journey~=\"header\"]');\n const calls = Array.from(header?.querySelectorAll('a[href^=\"tel:\"]') ?? []).filter(helpers.isRendered)\n .map((link) => ({ description: helpers.describeElement(link), digits: (helpers.accessibleName(link).match(/\\d/g) ?? []).length }));\n return { calls, overflow: document.documentElement.scrollWidth - width };\n }, SITE_SYSTEM_PHONE_VIEWPORT.width);\n if (seen.calls.length === 0) problems.push(`${path}: the phone header shows no call control`);\n for (const call of seen.calls) {\n if (call.digits < 6) problems.push(`${path}: the header's ${call.description} is not named with the phone number`);\n }\n if (seen.overflow > 0) problems.push(`${path}: the page scrolls sideways by ${seen.overflow} px at 390 px`);\n }\n note(testInfo, `Checked ${plan.sampled.join(', ')}`);\n expect(problems).toEqual([]);\n });\n\n test(title('N8', 'the call bar\\'s phone reports placement fab'), async ({ page }, testInfo) => {\n raiseTimeout(testInfo, 180_000);\n const problems: string[] = [];\n for (const path of [plan.home, ...plan.money]) {\n await openSitePage(page, path, plan);\n const links = await callBarLinks(page);\n if (!links) {\n note(testInfo, `${path}: no call bar showed after scrolling.`);\n continue;\n }\n if (links.length === 0) problems.push(`${path}: the call bar shows no phone link`);\n for (const link of links) {\n if (link.placement !== 'fab' || link.invalid) problems.push(`${path}: ${link.description} reports placement ${link.placement}${link.invalid ? ` (it declares \"${link.invalid}\")` : ''}, not fab`);\n }\n }\n expect(problems).toEqual([]);\n });\n });\n\n test.describe('drawer across the desktop breakpoint', () => {\n test(title('N8', 'widening past 1280 px closes the drawer and leaves the page usable'), async ({ page }) => {\n await page.setViewportSize({ width: 1100, height: 800 });\n await openSitePage(page, plan.home, plan);\n let button = menuButton(await siteHeader(page), plan);\n if (!(await button.count())) {\n await page.setViewportSize({ ...SITE_SYSTEM_PHONE_VIEWPORT });\n await page.waitForTimeout(300);\n button = menuButton(await siteHeader(page), plan);\n }\n expect(await button.count(), `no visible \"${String(plan.menuName)}\" button below 1200 px`).toBe(1);\n expect(await openDrawer(page, button, 'click'), 'the Menu button showed no dialog').not.toBeNull();\n await page.setViewportSize({ width: 1440, height: 800 });\n await page.waitForTimeout(400);\n const problems: string[] = [];\n if (await anyDialogOpen(page)) problems.push('the drawer stayed open at 1440 px');\n const usable = await page.evaluate(() => {\n const hit = document.elementFromPoint(window.innerWidth / 2, window.innerHeight * 0.75);\n const locked = [document.documentElement, document.body].some((element) => getComputedStyle(element).overflowY === 'hidden');\n return { covered: Boolean(hit?.closest('dialog, [role=\"dialog\"]')), inert: document.body.inert || Boolean(document.querySelector('main')?.closest('[inert]')), locked };\n });\n if (usable.covered) problems.push('a dialog still covers the page at 1440 px');\n if (usable.inert) problems.push('the page is still inert at 1440 px');\n if (usable.locked) problems.push('page scrolling is still locked at 1440 px');\n expect(problems).toEqual([]);\n });\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/site-system/report.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAKL,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACpB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAqD,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACxG,OAAO,EAIL,KAAK,oBAAoB,EAE1B,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAE5D,eAAO,MAAM,8BAA8B;;;CAGjC,CAAC;AAEX,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,gBAAgB,CAAC;AAEhG,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,QAAQ,CAAC,IAAI,EAAE,mBAAmB,GAAG,QAAQ,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,wBAAyB,SAAQ,mBAAmB;IACnE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC;IACrD,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,2DAA2D;IAC3D,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,8GAA8G;IAC9G,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C;AAED,MAAM,WAAW,qBAAqB;IACpC,6FAA6F;IAC7F,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,aAAa,EAAE,OAAO,wBAAwB,CAAC;IACxD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACjD,QAAQ,CAAC,KAAK,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC/C,QAAQ,CAAC,UAAU,EAAE,SAAS,wBAAwB,EAAE,CAAC;IACzD,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,qGAAqG;AACrG,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,yBAAyB,EAAE,cAAc,GAAG,qBAAqB,CAAC,CAAC;AAE7G,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAChD,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC/C,QAAQ,CAAC,aAAa,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACpD,QAAQ,CAAC,YAAY,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACnD,QAAQ,CAAC,UAAU,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACpD,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC;IACnB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,kHAAkH;IAClH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAKD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,+BAA+B,GAAG,qBAAqB,
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/site-system/report.ts"],"names":[],"mappings":"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"}
|
|
@@ -71,7 +71,7 @@ export function buildSiteSystemReadyReport(input) {
|
|
|
71
71
|
};
|
|
72
72
|
const checks = SITE_SYSTEM_CHECKS.map((check) => {
|
|
73
73
|
const blocks = site ? siteSystemCheckBlocks(check, site) : false;
|
|
74
|
-
const merged = mergeFindings(findings.filter((finding) => finding.checkId === check.id), notRunMessage(check));
|
|
74
|
+
const merged = launchOnlyNotRun(check, blocks, input.launch === true, mergeFindings(findings.filter((finding) => finding.checkId === check.id), notRunMessage(check, input.inputs, settings)));
|
|
75
75
|
const { status, messages } = applyException(check.id, blocks, merged.status, merged.messages);
|
|
76
76
|
return {
|
|
77
77
|
id: check.id,
|
|
@@ -134,8 +134,20 @@ export function buildSiteSystemReadyReport(input) {
|
|
|
134
134
|
};
|
|
135
135
|
}
|
|
136
136
|
/**
|
|
137
|
-
*
|
|
138
|
-
*
|
|
137
|
+
* A check whose not-run blocks only at launch (H13): under `--launch` a blocking not-run is a failure; otherwise it
|
|
138
|
+
* stays not run with a note, and the verdict does not count it.
|
|
139
|
+
*/
|
|
140
|
+
function launchOnlyNotRun(check, blocks, launch, merged) {
|
|
141
|
+
if (check.notRunBlocks !== "launch" || merged.status !== "not-run" || !blocks)
|
|
142
|
+
return merged;
|
|
143
|
+
if (launch)
|
|
144
|
+
return { ...merged, status: "fail", messages: merged.messages.map((message) => `Launch needs this check to run. ${message}`) };
|
|
145
|
+
return { ...merged, messages: [...merged.messages, "It blocks only at launch (brandlab-ready --launch)."] };
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Any fail fails the check; otherwise a rule's own not-run result (naming what it needed) leaves it not run; otherwise
|
|
149
|
+
* any pass passes it; only not-applicable results make it not applicable. A warning is a pass that carries its message
|
|
150
|
+
* as a warning, whatever status it names.
|
|
139
151
|
*/
|
|
140
152
|
function mergeFindings(findings, notRun) {
|
|
141
153
|
const warnings = [...new Set(findings.filter((finding) => finding.severity === "warning").map((finding) => finding.message))];
|
|
@@ -143,7 +155,7 @@ function mergeFindings(findings, notRun) {
|
|
|
143
155
|
if (warnings.length > 0 && !results.some((finding) => finding.status !== "not-applicable")) {
|
|
144
156
|
return { status: "pass", messages: [], warnings };
|
|
145
157
|
}
|
|
146
|
-
for (const status of ["fail", "pass", "not-applicable"]) {
|
|
158
|
+
for (const status of ["fail", "not-run", "pass", "not-applicable"]) {
|
|
147
159
|
const scoped = results.filter((finding) => finding.status === status);
|
|
148
160
|
if (scoped.length > 0)
|
|
149
161
|
return { status, messages: [...new Set(scoped.map((finding) => finding.message))], warnings };
|
|
@@ -167,10 +179,30 @@ function verifyStatus(family, findings) {
|
|
|
167
179
|
return { status: "not-applicable", messages: ["No brandlab-verify rule in this family applies to this project."], warnings };
|
|
168
180
|
return { status: "pass", messages: [`brandlab-verify found nothing to fix in ${family.title.toLowerCase()}.`], warnings };
|
|
169
181
|
}
|
|
170
|
-
|
|
182
|
+
/** What a site's site-system spec must pass for a journey to register, beyond its tier. */
|
|
183
|
+
const JOURNEY_PAGES = {
|
|
184
|
+
C1: "pages: { money: [...] }",
|
|
185
|
+
W9: "pages: { families: [...] }",
|
|
186
|
+
};
|
|
187
|
+
const JOURNEY_PAGES_WHY = {
|
|
188
|
+
C1: "pages.money names the service pages with the enquiry form",
|
|
189
|
+
W9: "pages.families names one built page per dynamic route family",
|
|
190
|
+
};
|
|
191
|
+
function notRunMessage(check, inputs, settings) {
|
|
171
192
|
switch (check.kind) {
|
|
172
|
-
case "journey":
|
|
173
|
-
|
|
193
|
+
case "journey": {
|
|
194
|
+
if (!inputs?.journeyReport || inputs.journeyTests === 0) {
|
|
195
|
+
return "No journey result: run the site-system journeys (npm run test:e2e) before brandlab-ready.";
|
|
196
|
+
}
|
|
197
|
+
// Other journeys ran, so this one did not register: the spec's tier or pages, or a conformance release before it.
|
|
198
|
+
const tier = settings?.tier ?? check.tier;
|
|
199
|
+
const pages = JOURNEY_PAGES[check.id];
|
|
200
|
+
const why = JOURNEY_PAGES_WHY[check.id];
|
|
201
|
+
return `No journey result: ${inputs.journeyReport} has ${plural(inputs.journeyTests, "site-system test run")} but none for ${check.id}. ` +
|
|
202
|
+
`The journeys register by tier and release: tests/e2e/site-system.spec.ts calls defineBrandlabSiteSystemTests({ tier: '${tier}'${pages ? `, ${pages}` : ""} }) ` +
|
|
203
|
+
`(${check.id} is a ${check.tier}-tier journey from ${check.from}${why ? `, and ${why}` : ""}), and @brandlab-digital/conformance must be ${check.from} or later; ` +
|
|
204
|
+
"then run npm run test:e2e with the JSON reporter before brandlab-ready.";
|
|
205
|
+
}
|
|
174
206
|
case "rendered":
|
|
175
207
|
return "No result: no rule module reported this check for the sampled pages.";
|
|
176
208
|
case "static":
|
|
@@ -202,7 +234,9 @@ function readyStep(step, file, record) {
|
|
|
202
234
|
function readyVerdict(input) {
|
|
203
235
|
const blocking = input.checks.filter((check) => check.blocks);
|
|
204
236
|
const failed = blocking.filter((check) => check.status === "fail").map((check) => check.id);
|
|
205
|
-
const
|
|
237
|
+
const launchOnly = new Set(SITE_SYSTEM_CHECKS.filter((check) => check.notRunBlocks === "launch").map((check) => check.id));
|
|
238
|
+
// A launch-only check that did not run is reported, not counted: under --launch it is already a failure.
|
|
239
|
+
const notRun = blocking.filter((check) => check.status === "not-run" && !launchOnly.has(check.id)).map((check) => check.id);
|
|
206
240
|
const excepted = blocking.filter((check) => check.status === "excepted").map((check) => check.id);
|
|
207
241
|
const stepsToRecord = input.steps.filter((step) => !step.recorded).map((step) => step.id);
|
|
208
242
|
const adopted = input.settings !== null;
|