import assert from "node:assert/strict"; import { execFileSync, spawnSync } from "node:child_process"; import { mkdtempSync, readFileSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import test from "node:test"; import { fileURLToPath } from "node:url"; import { chooseRust, classify, cratePackage, dartDefine, hunkRanges, ITERATIONS, listPlaywright, MAX_PLAYWRIGHT_JOURNEYS, nodeTestArgs, parseDartReport, parseJunit, playwrightRepetitions, playwrightShards, runners, rustFilterset, rustGroups, rustImporters, rustIncludes, rustModulePath, rustTarget, rustTests, rustWorkspaces, selectRust, selectTests, testBodies, testCalls, } from "./flake-check.mjs"; const read = (path) => readFileSync(new URL(path, import.meta.url), "utf8"); const root = fileURLToPath(new URL("../", import.meta.url)); const git = (args, env = {}) => execFileSync("git", ["-c", "core.hooksPath=/dev/null", ...args], { cwd: root, encoding: "utf8", env: { ...process.env, ...env }, }); // `select` over a synthetic head tree: HEAD's tree with a comment appended to // each given file, so only those files differ and no test body changes. The // outputs are keyed per runner as the workflow reads them. function selectAppending(...files) { const dir = mkdtempSync(join(tmpdir(), "flake-select-")); try { const env = { GIT_INDEX_FILE: join(dir, "index") }; git(["read-tree", "HEAD"], env); for (const file of files) { const blob = execFileSync("git", ["hash-object", "-w", "--stdin"], { cwd: root, encoding: "utf8", input: `${git(["show", `HEAD:${file}`])}// flake-check probe\n`, }).trim(); git(["update-index", "--cacheinfo", `100644,${blob},${file}`], env); } const tree = git(["write-tree"], env).trim(); const result = spawnSync( process.execPath, [join(root, "scripts/flake-check.mjs"), "select", "HEAD", tree], { cwd: root, encoding: "utf8" }, ); assert.equal(result.status, 0, result.stderr); const outputs = Object.fromEntries( [...result.stdout.matchAll(/^(\w+)=(.*)$/gm)].map(([, key, value]) => [ key, value.split(" ").filter(Boolean), ]), ); return { summary: result.stdout, outputs }; } finally { rmSync(dir, { recursive: true, force: true }); } } // A hunk writing new-side lines start..end; by default it removed nothing. const hunk = (start, end, removed = { start: start + 1, end: start }) => ({ start, end, removed, }); // A -U0 diff of (old start, old count, new start, new count) hunks. const diff = (...hunks) => hunks.map(([o, oc, n, nc]) => `@@ -${o},${oc} +${n},${nc} @@`).join("\n"); test("classification follows each runner's test file layout", () => { for (const [file, runner] of [ ["crates/buzz-core/src/filter.rs", "rust"], ["crates/buzz-test-client/tests/e2e_relay.rs", "rust"], ["desktop/src-tauri/src/lib.rs", "tauri"], ["desktop/src-tauri/tests/rodio_mixer_diagnostic.rs", "tauri"], ["desktop/src-tauri/crates/buzz-terminal/src/lib.rs", "tauri"], ["desktop/src-tauri/crates/buzz-terminal/tests/latency.rs", "tauri"], ["desktop/src/features/channels/lib/channelDescription.test.mjs", "node"], ["desktop/src/shared/ui/thing.jsdom-test.mjs", "node"], ["desktop/scripts/demo-build-config.test.mjs", "node"], ["desktop/tests/e2e/channels.spec.ts", "playwright"], ["mobile/test/features/invites/invite_join_provider_test.dart", "dart"], ]) assert.equal(classify(file), runner, file); for (const file of [ "crates/buzz-core/Cargo.toml", "crates/buzz-feature-flags/tests/fixtures/relay-feature-selection/src/main.rs", "desktop/src-tauri/build.rs", "desktop/src-tauri/tests/fixtures/x.rs", "desktop/src-tauri/crates/buzz-terminal/Cargo.toml", "desktop/src/features/channels/lib/channelDescription.ts", "desktop/tests/e2e/helpers/animations.ts", "desktop/tests/e2e/typing-latency.perf.ts", "desktop/tests/e2e/fixtures/x.spec.ts", "mobile/lib/main.dart", "mobile/test/helpers.dart", "scripts/flake-check.test.mjs", "web/src/x.test.mjs", // Selections are shell-split downstream; refuse unusual names. "desktop/tests/e2e/odd name.spec.ts", "crates/buzz-core/src/$(id).rs", ]) assert.equal(classify(file), undefined, file); // Each Rust runner names the cargo workspace its lane repeats. assert.deepEqual(Object.keys(rustWorkspaces), ["rust", "tauri"]); assert.ok(runners.includes("tauri")); }); test("-U0 hunks map to new-side ranges, with deletions attached to the preceding line and their old-side lines kept", () => { const text = [ "diff --git a/x.spec.ts b/x.spec.ts", "--- a/x.spec.ts", "+++ b/x.spec.ts", "@@ -1 +1 @@", '-import { test } from "@playwright/test";', '+import { expect, test } from "@playwright/test";', "@@ -12,0 +13,3 @@ test('a', async () => {", "+ const x = 1;", "+ const y = 2;", "+ expect(x).toBe(y - 1);", "@@ -30,2 +33,0 @@ test('b', async () => {", "- removed();", "- alsoRemoved();", "@@ -1,3 +0,0 @@", "-gone", "", ].join("\n"); assert.deepEqual(hunkRanges(text), [ { start: 1, end: 1, removed: { start: 1, end: 1 } }, { start: 13, end: 15, removed: { start: 12, end: 11 } }, { start: 33, end: 33, removed: { start: 30, end: 31 } }, { start: 0, end: 0, removed: { start: 1, end: 3 } }, ]); assert.deepEqual(hunkRanges(""), []); }); test("Playwright test calls span the declaration; groups, hooks and configuration are outside", () => { const spec = [ 'import { expect, test } from "@playwright/test";', "test.use({ viewport: { width: 800, height: 600 } });", "const seed = 1;", 'test.describe("suite", () => {', " test.beforeEach(async ({ page }) => {", ' await page.goto("/");', " });", ' test("journey", async ({ page }) => {', ' test.skip(seed === 2, "not here");', ' await expect(page.getByText("Go")).toBeVisible();', " });", ' for (const mode of ["mouse", "keyboard"]) {', ' test.fixme(mode + " later", async () => {', " await Promise.resolve();", " });", " }", "});", 'test.describe.configure({ mode: "serial" });', 'test.fail("known broken", async () => {', " await Promise.resolve();", "});", "", ].join("\n"); const calls = testCalls(spec, "x.spec.ts"); assert.deepEqual(calls, [ { start: 8, end: 11 }, { start: 13, end: 15 }, { start: 19, end: 21 }, ]); // Playwright lists a looped declaration once per iteration, at one line. assert.deepEqual(testBodies(calls, [13, 13, 8]), [ { start: 8, end: 11, line: 8 }, { start: 13, end: 15, line: 13 }, ]); // A listed line outside every call (a hook) has no body. assert.deepEqual(testBodies(calls, [5]), []); }); const rustSource = [ "//! Module docs mentioning #[test] in prose.", "use std::fmt;", "", "pub fn code_under_test(input: &str) -> String {", " let brace = '{';", ' let raw = r"\\";', ' format!("{brace}{raw}{input}")', "}", "", "#[cfg(test)]", "mod tests {", " use super::*;", "", " fn helper() -> &'static str {", ' "}"', " }", "", " /// Docs for the first test.", " #[test]", " fn plain() {", ' assert_eq!(code_under_test("x"), "{\\\\x");', " }", "", ' #[tokio::test(flavor = "multi_thread")]', ' #[ignore = "requires Postgres }"]', " async fn needs_infra() {", " /* a block comment with a } brace", " and #[test] inside */", " helper();", " }", "", " #[ignore]", " #[test]", " pub(crate) fn also_ignored() {}", "", " mod postgres_tests {", " #[sqlx::test]", " async fn in_nested_module(pool: Pool) -> Result<(), E> {", " Ok(())", " }", " }", "}", "", ].join("\n"); test("Rust test functions span their attribute block to the closing brace, through strings, chars and comments, named by their inline module path", () => { assert.deepEqual(rustTests(rustSource), [ { name: "tests::plain", start: 19, end: 22, ignored: false }, { name: "tests::needs_infra", start: 24, end: 30, ignored: true }, { name: "tests::also_ignored", start: 32, end: 34, ignored: true }, { name: "tests::postgres_tests::in_nested_module", start: 37, end: 40, ignored: false, }, ]); assert.deepEqual(rustTests("fn main() {}\n"), []); }); test("same-named Rust tests in different modules are distinct, and a hunk selects only its own", () => { const source = [ "mod alpha {", " #[test]", " fn same() {}", "}", "pub(crate) mod beta {", " mod tests {", " #[test]", " fn same() { let _ = 1; }", " }", "}", "", ].join("\n"); assert.deepEqual( rustTests(source).map((test) => test.name), ["alpha::same", "beta::tests::same"], ); assert.deepEqual( selectRust(diff([8, 1, 8, 1]), source, { previous: source }), { lines: [7], names: ["beta::tests::same"], }, ); // The file's path predicts the rest of the name; cargo's layout rules. for (const [file, modules] of [ ["crates/buzz-relay/src/lib.rs", []], ["crates/buzz-relay/src/main.rs", []], ["crates/buzz-relay/src/api/mod.rs", ["api"]], ["crates/buzz-relay/src/handlers/auth.rs", ["handlers", "auth"]], ["crates/buzz-test-client/src/bin/mention.rs", []], ["crates/buzz-test-client/tests/e2e_relay.rs", []], ["crates/x/tests/suite/main.rs", []], ["crates/x/tests/suite/helpers.rs", ["helpers"]], ["desktop/src-tauri/src/app_state.rs", ["app_state"]], ["desktop/src-tauri/tests/rodio_mixer_diagnostic.rs", []], [ "desktop/src-tauri/crates/buzz-terminal/src/grid/cell.rs", ["grid", "cell"], ], ]) assert.deepEqual(rustModulePath(file), modules, file); // Listed candidates: the predicted name wins; without it every suffix // match is kept rather than nothing. const candidates = [ { binary: "buzz-relay", name: "api::relay_members::tests::same" }, { binary: "buzz-relay", name: "handlers::auth::tests::same" }, { binary: "buzz-relay", name: "handlers::auth::tests::other" }, { binary: "buzz-relay::bin/buzz-relay", name: "handlers::auth::tests::same", }, ]; assert.deepEqual( chooseRust( [{ path: "tests::same", exact: "handlers::auth::tests::same" }], candidates, ), [candidates[1], candidates[3]], ); assert.deepEqual( chooseRust( [ { path: "tests::same", exact: "elsewhere::tests::same" }, { path: "tests::other", exact: "handlers::auth::tests::other" }, ], candidates, ), [candidates[0], candidates[1], candidates[3], candidates[2]], ); }); test("Rust files build only the targets they can be part of, merged per package one whole flag each", () => { for (const [file, flags] of [ ["crates/buzz-relay/src/api/mod.rs", [["--lib"], ["--bins"]]], ["crates/buzz-admin/src/main.rs", [["--bins"]]], ["crates/buzz-test-client/tests/e2e_relay.rs", [["--test", "e2e_relay"]]], ["crates/buzz-agent/tests/common/mod.rs", []], ["desktop/src-tauri/src/lib.rs", [["--lib"], ["--bins"]]], [ "desktop/src-tauri/tests/rodio_mixer_diagnostic.rs", [["--test", "rodio_mixer_diagnostic"]], ], [ "desktop/src-tauri/crates/buzz-terminal/tests/latency.rs", [["--test", "latency"]], ], ]) assert.deepEqual(rustTarget(file), flags, file); // Two integration tests keep two `--test` flags: `--test codec connection` // would make nextest filter on a test named "connection" and repeat nothing. const args = (...entries) => [...rustGroups(entries).groups.values()].map((group) => group.args); assert.deepEqual( args( "crates/buzz-audio-client/tests/codec.rs::roundtrip", "crates/buzz-audio-client/tests/connection.rs::connects", ), [["-p", "buzz-audio-client", "--test", "codec", "--test", "connection"]], ); assert.deepEqual( args( "crates/buzz-audio-client/src/wire.rs::tests::frame", "crates/buzz-audio-client/src/jitter.rs::tests::order", "crates/buzz-audio-client/tests/codec.rs::roundtrip", ), [["-p", "buzz-audio-client", "--lib", "--bins", "--test", "codec"]], ); // A custom-path file builds every target of its package; packages stay apart. assert.deepEqual( args( "crates/buzz-agent/tests/regressions.rs::replay", "crates/buzz-agent/tests/common/mod.rs::helper", "crates/buzz-admin/src/main.rs::tests::parses", ), [ ["-p", "buzz-agent"], ["-p", "buzz-admin", "--bins"], ], ); // The Tauri workspace's packages are addressed by its manifest, and never // mixed into a root-workspace invocation. const tauri = rustGroups([ "desktop/src-tauri/tests/rodio_mixer_diagnostic.rs::single_queue_serializes_sources", "desktop/src-tauri/crates/buzz-terminal/tests/latency.rs::g3_renderer_acquire_stays_within_frame_budget", ]); assert.equal(tauri.runner, "tauri"); assert.equal(rustWorkspaces[tauri.runner], "desktop/src-tauri/Cargo.toml"); assert.deepEqual( [...tauri.groups.values()].map((group) => group.args), [ ["-p", "buzz-desktop", "--test", "rodio_mixer_diagnostic"], ["-p", "buzz-terminal", "--test", "latency"], ], ); assert.equal( rustGroups(["crates/buzz-core/src/filter.rs::tests::a"]).runner, "rust", ); assert.throws( () => rustGroups([ "crates/buzz-core/src/filter.rs::tests::a", "desktop/src-tauri/src/lib.rs::tests::b", ]), /span workspaces/, ); assert.throws( () => rustGroups(["desktop/src/x.rs::tests::a"]), /rust entry must be/, ); // The root workspace's listing excludes its Postgres-backed tests by name // and binary; nextest rejects `binary(/^postgres_/)` in the Tauri // workspace, where no such binary exists, so that listing carries no // exclusion. assert.equal( rustFilterset("rust", ["tests::a", "b", "tests::a"]), "(test(/(^|::)tests::a$/) | test(/(^|::)b$/)) & !(test(/postgres_tests::/) | binary(/^postgres_/) | test(/(^|::)external_infra[^:]*::/))", ); assert.equal(rustFilterset("tauri", ["a"]), "(test(/(^|::)a$/))"); assert.doesNotMatch(rustFilterset("tauri", ["a"]), /binary\(/); }); test("a helper under tests/ selects the integration binaries that include it", () => { const helper = "crates/x/tests/common/mod.rs"; const includes = (target, ...lines) => rustIncludes(target, `${lines.join("\n")}\n`, helper); // `mod common;` in a crate root, in any form; not in a comment or string. assert.ok( includes("crates/x/tests/a.rs", "mod common;", "#[test] fn t() {}"), ); assert.ok(includes("crates/x/tests/a.rs", "pub(crate) mod common ;")); assert.ok(!includes("crates/x/tests/a.rs", "// uses mod common; elsewhere")); assert.ok(!includes("crates/x/tests/a.rs", 'const S: &str = "mod common;";')); assert.ok(!includes("crates/x/tests/a.rs", "mod commonplace;", "mod other;")); // `#[path]` reaching the file itself or its directory's mod.rs. assert.ok( includes("crates/x/tests/a.rs", '#[path = "common/mod.rs"]', "mod shared;"), ); assert.ok( includes( "crates/x/tests/a.rs", '#[path="../tests/common/mod.rs"] mod shared;', ), ); assert.ok( !includes("crates/x/tests/a.rs", '#[path = "other/mod.rs"]', "mod shared;"), ); assert.ok( rustIncludes( "crates/x/tests/a.rs", '#[path = "common/mod.rs"] mod shared;\n', "crates/x/tests/common/util.rs", ), ); // A tests/