commit aa1235a876fe636063170e14ecc07afa9d7f33fe
parent cc5519b774316ade318349542bfc24fd1e4d706d
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Thu, 8 Oct 2026 23:35:57 -0400
umtool e2e: the article specs compile their routes before the first test
A cold next-dev compile of the article page has taken over 30 s on a loaded
machine, a whole test's budget.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
4 files changed, 38 insertions(+), 0 deletions(-)
diff --git a/umtool/e2e/article-evidence.spec.ts b/umtool/e2e/article-evidence.spec.ts
@@ -2,6 +2,7 @@ import { test, expect } from "@playwright/test";
import { rmSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
+import { WARM_TIMEOUT, warm } from "./warm";
// ---------------------------------------------------------------------------
// A citation's evidence: the transcript around it, the window that plays it,
@@ -15,6 +16,12 @@ import { fileURLToPath } from "node:url";
const HERE = path.dirname(fileURLToPath(import.meta.url));
const NOTES = path.join(HERE, "..", ".e2e-song", "sites", "priv", "reports", "polemic-alpha", "notes.json");
+
+test.beforeAll(async ({ playwright }) => {
+ test.setTimeout(WARM_TIMEOUT);
+ await warm(playwright, ["/sites/priv/polemic-alpha", "/sites/priv/polemic-alpha/evidence", "/api/sites/evidence?site=priv&report=polemic-alpha&cite=c1", "/api/notes?article=priv/polemic-alpha"]);
+});
+
test.beforeEach(() => rmSync(NOTES, { force: true }));
test.afterAll(() => rmSync(NOTES, { force: true }));
diff --git a/umtool/e2e/article-notes.spec.ts b/umtool/e2e/article-notes.spec.ts
@@ -2,6 +2,7 @@ import { test, expect, type Page } from "@playwright/test";
import { existsSync, readFileSync, rmSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
+import { WARM_TIMEOUT, warm } from "./warm";
// ---------------------------------------------------------------------------
// Notes on an article: written beside report.json (the one corpus file umtool
@@ -15,6 +16,12 @@ const HERE = path.dirname(fileURLToPath(import.meta.url));
const NOTES = path.join(HERE, "..", ".e2e-song", "sites", "priv", "reports", "polemic-alpha", "notes.json");
const PAGE = "/sites/priv/polemic-alpha";
+
+test.beforeAll(async ({ playwright }) => {
+ test.setTimeout(WARM_TIMEOUT);
+ await warm(playwright, ["/sites/priv/polemic-alpha", "/api/notes?article=priv/polemic-alpha", "/sites", "/browse/decisions?kind=open-note", "/api/sites/evidence?site=priv&report=polemic-alpha&cite=c1"]);
+});
+
test.beforeEach(() => rmSync(NOTES, { force: true }));
test.afterAll(() => rmSync(NOTES, { force: true }));
diff --git a/umtool/e2e/sites.spec.ts b/umtool/e2e/sites.spec.ts
@@ -1,4 +1,5 @@
import { test, expect } from "@playwright/test";
+import { WARM_TIMEOUT, warm } from "./warm";
// ---------------------------------------------------------------------------
// /sites: every site's articles, a site's page, its media and workspace files.
@@ -10,6 +11,12 @@ import { test, expect } from "@playwright/test";
// (e2e/fixtures/sites-fixture.mjs)
// ---------------------------------------------------------------------------
+
+test.beforeAll(async ({ playwright }) => {
+ test.setTimeout(WARM_TIMEOUT);
+ await warm(playwright, ["/sites", "/sites/priv", "/sites/priv/polemic-alpha", "/api/sites/media?site=priv&report=polemic-alpha&file=poster.jpg", "/api/sites/workspace?ws=sitews&rel=NOTES.md"]);
+});
+
test("/sites lists every site, private first, with published and draft articles", async ({ page }) => {
const res = await page.goto("/sites");
expect(res?.status()).toBe(200);
diff --git a/umtool/e2e/warm.ts b/umtool/e2e/warm.ts
@@ -0,0 +1,17 @@
+import { test, type PlaywrightWorkerArgs } from "@playwright/test";
+
+// The e2e server is `next dev`: the first request to a route COMPILES it, and
+// the article page pulls in a large graph (common's report views, markdown,
+// the evidence resolver). On a loaded machine that first compile alone has
+// taken over 30 s -- a test's whole budget -- so each spec file that visits
+// these routes compiles them first, in a beforeAll with its own timeout.
+export const WARM_TIMEOUT = 180_000;
+
+export async function warm(playwright: PlaywrightWorkerArgs["playwright"], urls: string[]) {
+ const ctx = await playwright.request.newContext({ baseURL: test.info().project.use.baseURL });
+ try {
+ for (const u of urls) await ctx.get(u, { timeout: 170_000 });
+ } finally {
+ await ctx.dispose();
+ }
+}