Public: anyone can read this; the crew can change it.
A test fails when a flow reading under src/flow/ reads the wall clock instead of taking `now` #6509
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/6504-a-test-fails-when-a-flow-reading-under-s → main 1 commit fork
1 file
changed +37
−0
test/flow-clock.test.ts added +37
| @@ -0,0 +1,37 @@ | ||
| 1 | import { expect, test } from "bun:test"; | |
| 2 | import { readdirSync, readFileSync } from "node:fs"; | |
| 3 | import { join } from "node:path"; | |
| 4 | ||
| 5 | // A flow read takes `now`; reading the wall clock inside the body makes it flaky by the hour. | |
| 6 | const dir = join(import.meta.dir, "..", "src", "flow"); | |
| 7 | const clock = /Date\.now\(\)|new Date\(\)/g; | |
| 8 | // `now = new Date()` / `now: Date | number = Date.now()` as a parameter default. | |
| 9 | const paramDefault = /(?:^\s*|[(,]\s*)\w+\s*(?::[^=()]+)?=\s*$/; | |
| 10 | ||
| 11 | export function wallClockReads(file: string, text: string): string[] { | |
| 12 | const hits: string[] = []; | |
| 13 | text.split("\n").forEach((line, i) => { | |
| 14 | const code = line.replace(/\/\/.*$/, ""); | |
| 15 | for (const m of code.matchAll(clock)) { | |
| 16 | if (paramDefault.test(code.slice(0, m.index))) continue; | |
| 17 | hits.push(`${file}:${i + 1}: ${line.trim()}`); | |
| 18 | } | |
| 19 | }); | |
| 20 | return hits; | |
| 21 | } | |
| 22 | ||
| 23 | test("no src/flow file reads the wall clock outside a default parameter", () => { | |
| 24 | const hits = readdirSync(dir) | |
| 25 | .filter((f) => f.endsWith(".ts")) | |
| 26 | .flatMap((f) => wallClockReads(`src/flow/${f}`, readFileSync(join(dir, f), "utf8"))); | |
| 27 | expect(hits).toEqual([]); | |
| 28 | }); | |
| 29 | ||
| 30 | test("the scan catches a body read and allows a default", () => { | |
| 31 | expect(wallClockReads("x.ts", "const t = Date.now();")).toHaveLength(1); | |
| 32 | expect(wallClockReads("x.ts", " return new Date().getTime();")).toHaveLength(1); | |
| 33 | expect(wallClockReads("x.ts", "const d = x ?? new Date();")).toHaveLength(1); | |
| 34 | expect(wallClockReads("x.ts", "export function f(db: D, now = new Date(), p = false) {")).toEqual([]); | |
| 35 | expect(wallClockReads("x.ts", "export async function f(a: A, now: Date | number = Date.now()) {")).toEqual([]); | |
| 36 | expect(wallClockReads("x.ts", " now = Date.now(),")).toEqual([]); | |
| 37 | }); |
new above
offline