Public: anyone can read this; the crew can change it.
The Files page's cold-view timing test stops flaking: its ceiling comes from a measured median, not one run #4098
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/4096-the-files-page-s-cold-view-timing-test-s → main 1 commit fork 1 thread · 1 unresolved
1 file
changed +37
−0
test/pull-timing.test.ts +37
| @@ -8,6 +8,8 @@ import { openPull } from "../src/actions/pulls.ts"; | ||
| 8 | 8 | import { commitToBranch, createRepo } from "../src/actions/repos.ts"; |
| 9 | 9 | import { createRun } from "../src/core/runs.ts"; |
| 10 | 10 | import { createSession } from "../src/core/sessions.ts"; |
| 11 | import type { Repo } from "../src/core/repos.ts"; | |
| 12 | import type { User } from "../src/core/users.ts"; | |
| 11 | 13 | import { createUser } from "../src/core/users.ts"; |
| 12 | 14 | import { serve, type Servers } from "../src/http/server.ts"; |
| 13 | 15 | import { quietLogs } from "./helpers/globals.ts"; |
| @@ -19,6 +21,8 @@ let app: App; | ||
| 19 | 21 | let servers: Servers; |
| 20 | 22 | let cookie = ""; |
| 21 | 23 | let number = 0; |
| 24 | let owner: User; | |
| 25 | let repoRow: Repo; | |
| 22 | 26 | const cells = process.env["FORGE_CELLS"]; |
| 23 | 27 | |
| 24 | 28 | beforeAll(async () => { |
| @@ -36,9 +40,11 @@ beforeAll(async () => { | ||
| 36 | 40 | }); |
| 37 | 41 | if (!made.ok) throw new Error(String(made.error)); |
| 38 | 42 | const alice = made.value; |
| 43 | owner = alice; | |
| 39 | 44 | cookie = `forge_session=${createSession(app.db, alice.id).token}`; |
| 40 | 45 | const repo = await createRepo(app, alice, { name: "r", visibility: "public" }); |
| 41 | 46 | if (!repo.ok) throw new Error(String(repo.error)); |
| 47 | repoRow = repo.value; | |
| 42 | 48 | for (const [branch, file] of [[undefined, "forge.json"], ["topic", "t.txt"]] as const) { |
| 43 | 49 | const done = await commitToBranch(app, alice, repo.value, { |
| 44 | 50 | ...(branch === undefined ? {} : { branch }), |
| @@ -87,3 +93,34 @@ test("a pull names session, diff, checks, reviews and render after app, summing | ||
| 87 | 93 | expect(ms("diff")).toBeGreaterThan(0); |
| 88 | 94 | expect(ms("checks")).toBeGreaterThan(0); |
| 89 | 95 | }); |
| 96 | ||
| 97 | /** The `app` duration of one Files-page view, in ms. */ | |
| 98 | async function filesApp(): Promise<number> { | |
| 99 | const res = await fetch(`${servers.url}/alice/r/pulls/${number}/files`, { headers: { cookie } }); | |
| 100 | expect(res.status).toBe(200); | |
| 101 | await res.arrayBuffer(); | |
| 102 | const app = (res.headers.get("server-timing") ?? "").match(/(?:^|, )app;dur=([\d.]+)/); | |
| 103 | return Number(app![1]); | |
| 104 | } | |
| 105 | ||
| 106 | test("the Files page's cold first view of a fresh head: median of 3 under a ceiling beside its measurement", async () => { | |
| 107 | const runs: number[] = []; | |
| 108 | for (let i = 0; i < 3; i++) { | |
| 109 | // A new head each time, so nothing rendered before is reused. | |
| 110 | const done = await commitToBranch(app, owner, repoRow, { | |
| 111 | branch: "topic", | |
| 112 | message: `head ${i}`, | |
| 113 | files: Array.from({ length: 20 }, (_, f) => ({ | |
| 114 | path: `d/f${f}.ts`, | |
| 115 | content: Array.from({ length: 50 }, (_, l) => `export const v${i}_${f}_${l} = ${l};`).join("\n"), | |
| 116 | })), | |
| 117 | }); | |
| 118 | if (!done.ok) throw new Error(JSON.stringify(done.error)); | |
| 119 | runs.push(await filesApp()); | |
| 120 | } | |
| 121 | const median = runs.sort((a, b) => a - b)[1]!; | |
| 122 | // Measured over 10 runs of this file: the median of 3 was 76-95 ms (typically ~85), a single | |
| 123 | // render up to 147 ms. 170 ms is 2x the typical median: loose enough for a slow machine, tight | |
| 124 | // enough to catch a return to per-line highlighting. | |
| 125 | expect(median).toBeLessThan(170); | |
| 126 | }); |
new above
offline
app![1] throws an opaque TypeError if the header lacks app;dur. Use expect(app).not.toBeNull() first so a missing phase reads as a missing phase.