Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions packages/ui/tests/route-impact.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { describe, expect, it } from "bun:test";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import {
ATLAS_REPRESENTATIVES,
buildImpact,
docsRepresentatives,
lockReachesRuntime,
ownRoutes,
select,
VISUAL_ROUTES,
} from "../../../scripts/route-impact";
import { TERMS, termSlug } from "../../../site/src/data/atlas/atlas";

Expand Down Expand Up @@ -283,3 +286,23 @@ describe("route-impact", () => {
});
});
});

// The land gate rebuilds and retests the pages `pages.visual.spec.ts` captures from `VISUAL_ROUTES`. Two copies
// kept "in step" by a comment let a page get a baseline that no land ever rebuilt (#651): one list, imported.
describe("VISUAL_ROUTES", () => {
const spec = readFileSync(
join(import.meta.dir, "../../../site/tests/pages.visual.spec.ts"),
"utf8"
);
it("is the list the visual spec captures, not a copy of it", () => {
expect(spec).toMatch(
/import \{[^}]*\bVISUAL_ROUTES\b[^}]*\} from "..\/..\/scripts\/route-impact"/
);
expect(spec).not.toMatch(/^\s*"\/templates\//m);
});
it("lists real, distinct routes", () => {
expect(VISUAL_ROUTES.length).toBeGreaterThan(0);
expect(new Set(VISUAL_ROUTES).size).toBe(VISUAL_ROUTES.length);
for (const r of VISUAL_ROUTES) expect(r).toMatch(/^\/(.*\/)?$/);
});
});
14 changes: 14 additions & 0 deletions scripts/route-impact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,20 @@ export const GALLERY_REPRESENTATIVES = [
"page-auth-sign-in",
];

/**
* The pages `site/tests/pages.visual.spec.ts` captures at the viewport: the landing, the templates and the theme
* editor. Every docs page is a stack of component demos that the component baselines already compare one by one, and
* the layout audit checks their geometry on every route. The land gate rebuilds exactly these when a diff reaches one
* (`test-changed.ts`), and the spec imports the same list (#651).
*/
export const VISUAL_ROUTES = [
"/",
"/templates/",
"/templates/app/dashboard/",
"/templates/auth/sign-in/",
"/theme/",
];

/**
* `/atlas/<slug>/` is one template (`pages/atlas/[slug].astro`) over every term of the atlas, so the land gate
* audits the pages that stand for all of them, and so does the release sweep (`test:routes`, #613); the HTML checks read every one (#595): a term with sources and style
Expand Down
15 changes: 3 additions & 12 deletions scripts/test-changed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { spawn, spawnSync } from "node:child_process";
import { existsSync, readFileSync, statSync } from "node:fs";
import { join } from "node:path";
import { distCovers, distStale, readScope } from "./dist-fresh.ts";
import { lockReachesRuntime, ownRoutes, ROOT, select } from "./route-impact.ts";
import { lockReachesRuntime, ownRoutes, ROOT, select, VISUAL_ROUTES } from "./route-impact.ts";
import {
affected,
buildGraph,
Expand All @@ -57,15 +57,6 @@ const CANARIES = [
"/theme/",
];

/** The routes `pages.visual.spec.ts` captures (keep in step with its PAGES). */
const VISUAL_ROUTES = new Set([
"/",
"/templates/",
"/templates/app/dashboard/",
"/templates/auth/sign-in/",
"/theme/",
]);

/**
* A site spec that is not the route harness: it runs itself when it changed. `no-flash.spec.ts` is not one of
* them: it paints real pages at 6x CPU on Slow 3G (~90 s for its cases), so it runs in `test:e2e` at release.
Expand Down Expand Up @@ -121,14 +112,14 @@ const specs = changed.filter(ownSpec);
const routes = sel.all ? [] : [...new Set([...sel.routes, ...(land ? CANARIES : [])])].sort();
const sweepAll = sel.all || (land && sharedFile !== undefined);
const siteRun = sweepAll || routes.length > 0 || specs.length > 0;
const visualRun = sel.all || sel.routes.some((r) => VISUAL_ROUTES.has(r));
const visualRun = sel.all || sel.routes.some((r) => VISUAL_ROUTES.includes(r));
const routeRun = sweepAll || routes.length > 0;
// A narrow site run builds only the pages it audits (`CA_SITE_ROUTES`, site/src/lib/only-routes.ts): a behaviour spec
// visits arbitrary pages and a sweep audits all of them, so those need the whole site. 915 pages are ~80 s of the
// page generation, 80 pages ~11 s.
const builtRoutes: string[] | undefined =
!sweepAll && specs.length === 0
? [...new Set([...routes, ...(visualRun ? [...VISUAL_ROUTES] : [])])].sort()
? [...new Set([...routes, ...(visualRun ? VISUAL_ROUTES : [])])].sort()
: undefined;
// Shared: everything that can reach every test runs, and screenshots are left to `test:vrt`.
const shared = sel.all || sharedFile !== undefined;
Expand Down
13 changes: 4 additions & 9 deletions site/tests/pages.visual.spec.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import { VISUAL_ROUTES } from "../../scripts/route-impact";
import { expect, settle, test, waitIslands } from "./fixtures";

// The pages whose own composition is what a screenshot can show: the landing, the templates and the theme
// editor, at the visible viewport (the first screen a visitor sees). Every docs page is a stack of component
// demos that the component baselines (packages/ui `*.vrt.test.ts`) already compare one by one, and the layout
// audit (routes.spec.ts) checks their geometry on every route, so a tall full-page docs shot added only the
// slowest and flakiest copy of both.
const PAGES = [
"/",
"/templates/",
"/templates/app/dashboard/",
"/templates/auth/sign-in/",
"/theme/",
];
// slowest and flakiest copy of both. The list is `VISUAL_ROUTES` (scripts/route-impact.ts), which the land gate
// also reads to rebuild these pages.

// Per-test timeout: a viewport shot is taken twice and compared (and written when updating); the
// 5 s expect and 30 s test defaults are enough on a native machine, so only the shot itself is bounded.
Expand All @@ -31,7 +26,7 @@ for (const scheme of ["dark", "light"] as const) {
test.describe(`visual ${scheme}`, () => {
test.use({ theme: { scheme }, colorScheme: scheme });

for (const route of PAGES) {
for (const route of VISUAL_ROUTES) {
test(route, async ({ page }) => {
await prepare(page, route);
// Visible viewport only: no `fullPage`, so no layout-height rounding between the two compared
Expand Down