test: share fs scan assertions

This commit is contained in:
Vincent Koc
2026-05-16 19:18:52 +08:00
parent c277138959
commit cb313d5378
38 changed files with 384 additions and 588 deletions

View File

@@ -1,4 +1,3 @@
import { execFileSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { describe, expect, it } from "vitest";
@@ -7,6 +6,7 @@ import {
listBundledPluginBuildEntries,
listBundledPluginPackArtifacts,
} from "../../scripts/lib/bundled-plugin-build-entries.mjs";
import { expectNoNodeFsScans } from "../../src/test-utils/fs-scan-assertions.js";
function expectNoPrefixMatches(values: string[], prefix: string) {
expect(values.filter((value) => value.startsWith(prefix))).toEqual([]);
@@ -76,45 +76,24 @@ describe("bundled plugin build entries", () => {
});
it("discovers repo plugin build entries without directory scans", () => {
const output = execFileSync(
process.execPath,
[
"--input-type=module",
"--eval",
`
import fs from "node:fs";
import { syncBuiltinESMExports } from "node:module";
const counts = { readdirSync: 0 };
const originalReaddirSync = fs.readdirSync;
fs.readdirSync = (...args) => {
counts.readdirSync += 1;
return originalReaddirSync(...args);
};
syncBuiltinESMExports();
const build = await import("./scripts/lib/bundled-plugin-build-entries.mjs");
const entries = build.listBundledPluginBuildEntries();
const artifacts = build.listBundledPluginPackArtifacts();
console.log(JSON.stringify({
artifacts: artifacts.length,
counts,
entries: Object.keys(entries).length,
}));
`,
],
{
cwd: process.cwd(),
encoding: "utf8",
},
);
const payload = JSON.parse(output) as {
const payload = expectNoNodeFsScans<{
artifacts: number;
counts: { readdirSync: number };
entries: number;
};
}>(
`
const build = await import("./scripts/lib/bundled-plugin-build-entries.mjs");
const entries = build.listBundledPluginBuildEntries();
const artifacts = build.listBundledPluginPackArtifacts();
return {
artifacts: artifacts.length,
entries: Object.keys(entries).length,
};
`,
{ counters: ["readdirSync"] },
);
expect(payload.entries).toBeGreaterThan(0);
expect(payload.artifacts).toBeGreaterThan(0);
expect(payload.counts.readdirSync).toBe(0);
});
it("packs runtime core support packages without requiring plugin manifests", () => {

View File

@@ -1,6 +1,6 @@
import { execFileSync } from "node:child_process";
import { describe, expect, it } from "vitest";
import { collectBundledPluginSources } from "../../scripts/lib/bundled-plugin-source-utils.mjs";
import { expectNoNodeFsScans } from "../../src/test-utils/fs-scan-assertions.js";
describe("scripts/lib/bundled-plugin-source-utils.mjs", () => {
it("collects bundled plugin sources with package metadata", () => {
@@ -17,51 +17,23 @@ describe("scripts/lib/bundled-plugin-source-utils.mjs", () => {
});
it("discovers repo bundled plugin sources without scanning extension directories", () => {
const output = execFileSync(
process.execPath,
[
"--input-type=module",
"--eval",
`
import fs from "node:fs";
import { syncBuiltinESMExports } from "node:module";
const counts = { existsSync: 0, readdirSync: 0 };
const originalExistsSync = fs.existsSync;
const originalReaddirSync = fs.readdirSync;
fs.existsSync = (...args) => {
counts.existsSync += 1;
return originalExistsSync(...args);
};
fs.readdirSync = (...args) => {
counts.readdirSync += 1;
return originalReaddirSync(...args);
};
syncBuiltinESMExports();
const utils = await import("./scripts/lib/bundled-plugin-source-utils.mjs");
const sources = utils.collectBundledPluginSources({
repoRoot: process.cwd(),
requirePackageJson: true,
});
console.log(JSON.stringify({
channels: sources.filter((source) => Array.isArray(source.manifest?.channels) && source.manifest.channels.length > 0).length,
counts,
sources: sources.length,
}));
`,
],
{
cwd: process.cwd(),
encoding: "utf8",
},
);
const payload = JSON.parse(output) as {
const payload = expectNoNodeFsScans<{
channels: number;
counts: { existsSync: number; readdirSync: number };
sources: number;
};
}>(`
const utils = await import("./scripts/lib/bundled-plugin-source-utils.mjs");
const sources = utils.collectBundledPluginSources({
repoRoot: process.cwd(),
requirePackageJson: true,
});
return {
channels: sources.filter(
(source) => Array.isArray(source.manifest?.channels) && source.manifest.channels.length > 0,
).length,
sources: sources.length,
};
`);
expect(payload.sources).toBeGreaterThan(0);
expect(payload.channels).toBeGreaterThan(0);
expect(payload.counts).toEqual({ existsSync: 0, readdirSync: 0 });
});
});

View File

@@ -1,6 +1,7 @@
import { spawnSync } from "node:child_process";
import { describe, expect, it } from "vitest";
import { createChannelContractTestShards } from "../../scripts/lib/channel-contract-test-plan.mjs";
import { expectNoNodeFsScans } from "../../src/test-utils/fs-scan-assertions.js";
function listContractTests(rootDir = "src/channels/plugins/contracts"): string[] {
const result = spawnSync("git", ["ls-files", "--", rootDir], {
@@ -45,51 +46,19 @@ describe("scripts/lib/channel-contract-test-plan.mjs", () => {
});
it("uses git-tracked files without walking contract directories", () => {
const result = spawnSync(
process.execPath,
[
"--input-type=module",
"--eval",
`
import fs from "node:fs";
import { syncBuiltinESMExports } from "node:module";
const counts = { existsSync: 0, readdirSync: 0 };
const originalExistsSync = fs.existsSync;
const originalReaddirSync = fs.readdirSync;
fs.existsSync = (...args) => {
counts.existsSync += 1;
return originalExistsSync(...args);
};
fs.readdirSync = (...args) => {
counts.readdirSync += 1;
return originalReaddirSync(...args);
};
syncBuiltinESMExports();
const { createChannelContractTestShards } = await import("./scripts/lib/channel-contract-test-plan.mjs");
const shards = createChannelContractTestShards();
console.log(JSON.stringify({
counts,
files: shards.reduce((total, shard) => total + shard.includePatterns.length, 0),
shards: shards.length,
}));
`,
],
{
cwd: process.cwd(),
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
},
);
expect(result.status, result.stderr).toBe(0);
const payload = JSON.parse(result.stdout) as {
counts: { existsSync: number; readdirSync: number };
const payload = expectNoNodeFsScans<{
files: number;
shards: number;
};
}>(`
const { createChannelContractTestShards } = await import("./scripts/lib/channel-contract-test-plan.mjs");
const shards = createChannelContractTestShards();
return {
files: shards.reduce((total, shard) => total + shard.includePatterns.length, 0),
shards: shards.length,
};
`);
expect(payload.shards).toBe(3);
expect(payload.files).toBeGreaterThan(0);
expect(payload.counts).toEqual({ existsSync: 0, readdirSync: 0 });
});
it("keeps registry-backed surface shards spread across checks", () => {

View File

@@ -4,6 +4,7 @@ import { join, relative, resolve } from "node:path";
import fg from "fast-glob";
import { describe, expect, it } from "vitest";
import { createNodeTestShards } from "../../scripts/lib/ci-node-test-plan.mjs";
import { expectNoNodeFsScans } from "../../src/test-utils/fs-scan-assertions.js";
import { commandsLightTestFiles } from "../vitest/vitest.commands-light-paths.mjs";
import { createPluginsVitestConfig } from "../vitest/vitest.plugins.config.ts";
@@ -94,51 +95,22 @@ function isGatewayServerTestFile(file: string): boolean {
describe("scripts/lib/ci-node-test-plan.mjs", () => {
it("creates split shards without walking test roots", () => {
const result = spawnSync(
process.execPath,
[
"--input-type=module",
"--eval",
`
import fs from "node:fs";
import { syncBuiltinESMExports } from "node:module";
const counts = { existsSync: 0, readdirSync: 0 };
const originalExistsSync = fs.existsSync;
const originalReaddirSync = fs.readdirSync;
fs.existsSync = (...args) => {
counts.existsSync += 1;
return originalExistsSync(...args);
};
fs.readdirSync = (...args) => {
counts.readdirSync += 1;
return originalReaddirSync(...args);
};
syncBuiltinESMExports();
const { createNodeTestShards } = await import("./scripts/lib/ci-node-test-plan.mjs");
const shards = createNodeTestShards();
console.log(JSON.stringify({
counts,
includePatterns: shards.reduce((total, shard) => total + (shard.includePatterns?.length ?? 0), 0),
shards: shards.length,
}));
`,
],
{
cwd: process.cwd(),
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
},
);
expect(result.status, result.stderr).toBe(0);
const payload = JSON.parse(result.stdout) as {
counts: { existsSync: number; readdirSync: number };
const payload = expectNoNodeFsScans<{
includePatterns: number;
shards: number;
};
}>(`
const { createNodeTestShards } = await import("./scripts/lib/ci-node-test-plan.mjs");
const shards = createNodeTestShards();
return {
includePatterns: shards.reduce(
(total, shard) => total + (shard.includePatterns?.length ?? 0),
0,
),
shards: shards.length,
};
`);
expect(payload.shards).toBeGreaterThan(0);
expect(payload.includePatterns).toBeGreaterThan(0);
expect(payload.counts).toEqual({ existsSync: 0, readdirSync: 0 });
});
it("splits the slow core unit shards while keeping paired source/security coverage", () => {

View File

@@ -1,7 +1,8 @@
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { describe, expect, it, vi } from "vitest";
import { describe, expect, it } from "vitest";
import { expectNoReaddirSyncDuring } from "../../src/test-utils/fs-scan-assertions.js";
const repoRoot = path.resolve(import.meta.dirname, "../..");
const CODE_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
@@ -107,16 +108,12 @@ function summarizeSuppressions(entries: readonly SuppressionEntry[]): string[] {
describe("production lint suppressions", () => {
it("lists production files from git without walking source roots", () => {
const readdirSync = vi.spyOn(fs, "readdirSync");
try {
expectNoReaddirSyncDuring(() => {
const files = ROOTS.flatMap((root) => walkCodeFiles(path.join(repoRoot, root))).toSorted();
expect(files.length).toBeGreaterThan(0);
expect(files.some((file) => file.endsWith(".test.ts"))).toBe(false);
expect(readdirSync).not.toHaveBeenCalled();
} finally {
readdirSync.mockRestore();
}
});
});
it("keeps the intentional production suppression tail on an explicit allowlist", () => {

View File

@@ -2,6 +2,7 @@ import { spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
import { createPluginContractTestShards } from "../../scripts/lib/plugin-contract-test-plan.mjs";
import { expectNoNodeFsScans } from "../../src/test-utils/fs-scan-assertions.js";
function listContractTests(rootDir = "src/plugins/contracts"): string[] {
const result = spawnSync("git", ["ls-files", "--", rootDir], {
@@ -58,51 +59,19 @@ describe("scripts/lib/plugin-contract-test-plan.mjs", () => {
});
it("uses git-tracked files without walking contract directories", () => {
const result = spawnSync(
process.execPath,
[
"--input-type=module",
"--eval",
`
import fs from "node:fs";
import { syncBuiltinESMExports } from "node:module";
const counts = { existsSync: 0, readdirSync: 0 };
const originalExistsSync = fs.existsSync;
const originalReaddirSync = fs.readdirSync;
fs.existsSync = (...args) => {
counts.existsSync += 1;
return originalExistsSync(...args);
};
fs.readdirSync = (...args) => {
counts.readdirSync += 1;
return originalReaddirSync(...args);
};
syncBuiltinESMExports();
const { createPluginContractTestShards } = await import("./scripts/lib/plugin-contract-test-plan.mjs");
const shards = createPluginContractTestShards();
console.log(JSON.stringify({
counts,
files: shards.reduce((total, shard) => total + shard.includePatterns.length, 0),
shards: shards.length,
}));
`,
],
{
cwd: process.cwd(),
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
},
);
expect(result.status, result.stderr).toBe(0);
const payload = JSON.parse(result.stdout) as {
counts: { existsSync: number; readdirSync: number };
const payload = expectNoNodeFsScans<{
files: number;
shards: number;
};
}>(`
const { createPluginContractTestShards } = await import("./scripts/lib/plugin-contract-test-plan.mjs");
const shards = createPluginContractTestShards();
return {
files: shards.reduce((total, shard) => total + shard.includePatterns.length, 0),
shards: shards.length,
};
`);
expect(payload.shards).toBe(4);
expect(payload.files).toBeGreaterThan(0);
expect(payload.counts).toEqual({ existsSync: 0, readdirSync: 0 });
});
it("keeps plugin registration contract files spread across checks", () => {

View File

@@ -2,7 +2,7 @@ import { spawnSync } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { beforeAll, describe, expect, it, vi } from "vitest";
import { beforeAll, describe, expect, it } from "vitest";
import {
createFormattedPromptSnapshotFiles,
deleteStalePromptSnapshotFiles,
@@ -13,6 +13,7 @@ import {
renderCodexModelInstructions,
runCodexModelPromptFixtureSync,
} from "../../scripts/sync-codex-model-prompt-fixture.js";
import { expectNoReaddirSyncDuring } from "../../src/test-utils/fs-scan-assertions.js";
import {
CODEX_MODEL_PROMPT_FIXTURE_DIR,
CODEX_RUNTIME_HAPPY_PATH_PROMPT_SNAPSHOT_DIR,
@@ -118,16 +119,12 @@ describe("happy path prompt snapshots", () => {
}, 300_000);
it("lists committed Codex prompt snapshot artifacts without scanning directories in-process", () => {
const readDir = vi.spyOn(fs, "readdirSync");
try {
expectNoReaddirSyncDuring(() => {
const committed = listCommittedPromptSnapshotFiles();
expect(committed.length).toBeGreaterThan(0);
expect(committed.every((file) => file.endsWith(".md") || file.endsWith(".json"))).toBe(true);
expect(readDir).not.toHaveBeenCalled();
} finally {
readDir.mockRestore();
}
});
});
it("matches the committed Codex prompt snapshot artifacts", async () => {

View File

@@ -1,4 +1,3 @@
import { execFileSync } from "node:child_process";
import fs from "node:fs/promises";
import path from "node:path";
import { describe, expect, it, vi } from "vitest";
@@ -15,6 +14,7 @@ import {
writeLegacyRootRuntimeCompatAliases,
writeStableRootRuntimeAliases,
} from "../../scripts/runtime-postbuild.mjs";
import { expectNoNodeFsScans } from "../../src/test-utils/fs-scan-assertions.js";
import { createScriptTestHarness } from "./test-helpers.js";
const { createTempDir } = createScriptTestHarness();
@@ -44,44 +44,16 @@ describe("runtime postbuild static assets", () => {
});
it("discovers repo static asset metadata without scanning extension directories", () => {
const output = execFileSync(
process.execPath,
[
"--input-type=module",
"--eval",
`
import fs from "node:fs";
import { syncBuiltinESMExports } from "node:module";
const counts = { existsSync: 0, readdirSync: 0 };
const originalExistsSync = fs.existsSync;
const originalReaddirSync = fs.readdirSync;
fs.existsSync = (...args) => {
counts.existsSync += 1;
return originalExistsSync(...args);
};
fs.readdirSync = (...args) => {
counts.readdirSync += 1;
return originalReaddirSync(...args);
};
syncBuiltinESMExports();
const assets = await import("./scripts/lib/static-extension-assets.mjs");
console.log(JSON.stringify({
counts,
outputs: assets.listStaticExtensionAssetOutputs(),
sources: assets.listStaticExtensionAssetSources(),
}));
`,
],
{
cwd: process.cwd(),
encoding: "utf8",
},
);
const payload = JSON.parse(output) as {
counts: { existsSync: number; readdirSync: number };
const payload = expectNoNodeFsScans<{
outputs: string[];
sources: string[];
};
}>(`
const assets = await import("./scripts/lib/static-extension-assets.mjs");
return {
outputs: assets.listStaticExtensionAssetOutputs(),
sources: assets.listStaticExtensionAssetSources(),
};
`);
expect(payload.outputs).toEqual([
"dist/extensions/acpx/error-format.mjs",
@@ -90,7 +62,6 @@ describe("runtime postbuild static assets", () => {
"dist/extensions/diffs/assets/viewer-runtime.js",
]);
expect(payload.sources).toContain("extensions/diffs/assets/viewer-runtime.js");
expect(payload.counts).toEqual({ existsSync: 0, readdirSync: 0 });
});
it("discovers static assets from plugin package metadata", async () => {

View File

@@ -1,8 +1,9 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import { afterEach, describe, expect, it } from "vitest";
import { findBuiltStatusMessageRuntimePath } from "../../scripts/test-built-status-message-runtime.mjs";
import { expectNoReaddirSyncDuring } from "../../src/test-utils/fs-scan-assertions.js";
const tempDirs: string[] = [];
@@ -27,14 +28,10 @@ describe("test-built-status-message-runtime", () => {
fs.writeFileSync(path.join(distDir, "status-message.runtime-abc123.js"), "export {}\n");
fs.writeFileSync(path.join(distDir, "other.js"), "export {}\n");
const readDir = vi.spyOn(fs, "readdirSync");
try {
expectNoReaddirSyncDuring(() => {
expect(findBuiltStatusMessageRuntimePath(distDir)).toBe(
path.join(distDir, "status-message.runtime-abc123.js"),
);
expect(readDir).not.toHaveBeenCalled();
} finally {
readDir.mockRestore();
}
});
});
});

View File

@@ -17,6 +17,7 @@ import {
resolveExtensionBatchParallelism,
runExtensionBatchPlan,
} from "../../scripts/test-extension-batch.mjs";
import { expectNoNodeFsScans } from "../../src/test-utils/fs-scan-assertions.js";
const scriptPath = path.join(process.cwd(), "scripts", "test-extension.mjs");
@@ -253,50 +254,22 @@ describe("scripts/test-extension.mjs", () => {
});
it("lists available extension ids from git without reading extension directories", () => {
const output = execFileSync(
process.execPath,
[
"--input-type=module",
"--eval",
`
import fs from "node:fs";
import { syncBuiltinESMExports } from "node:module";
const counts = { existsSync: 0, readdirSync: 0 };
const originalExistsSync = fs.existsSync;
const originalReaddirSync = fs.readdirSync;
fs.existsSync = (...args) => {
counts.existsSync += 1;
return originalExistsSync(...args);
};
fs.readdirSync = (...args) => {
counts.readdirSync += 1;
return originalReaddirSync(...args);
};
syncBuiltinESMExports();
const { detectChangedExtensionIds, listAvailableExtensionIds } = await import("./scripts/lib/changed-extensions.mjs");
const ids = listAvailableExtensionIds();
const changed = detectChangedExtensionIds([
"extensions/slack/src/channel.ts",
"src/line/message.test.ts",
"extensions/not-real/package.json",
]);
console.log(JSON.stringify({ changed, counts, ids: ids.length }));
`,
],
{
cwd: process.cwd(),
encoding: "utf8",
},
);
const payload = JSON.parse(output) as {
const payload = expectNoNodeFsScans<{
changed: string[];
counts: { existsSync: number; readdirSync: number };
ids: number;
};
}>(`
const { detectChangedExtensionIds, listAvailableExtensionIds } =
await import("./scripts/lib/changed-extensions.mjs");
const ids = listAvailableExtensionIds();
const changed = detectChangedExtensionIds([
"extensions/slack/src/channel.ts",
"src/line/message.test.ts",
"extensions/not-real/package.json",
]);
return { changed, ids: ids.length };
`);
expect(payload.changed).toEqual(["line", "slack"]);
expect(payload.ids).toBeGreaterThan(0);
expect(payload.counts).toEqual({ existsSync: 0, readdirSync: 0 });
});
it("can fail safe to all extensions when the base revision is unavailable", () => {
@@ -472,49 +445,28 @@ describe("scripts/test-extension.mjs", () => {
});
it("counts tracked extension tests without walking extension directories", () => {
const output = execFileSync(
process.execPath,
[
"--input-type=module",
"--eval",
`
import fs from "node:fs";
import { syncBuiltinESMExports } from "node:module";
const counts = { readdirSync: 0 };
const originalReaddirSync = fs.readdirSync;
fs.readdirSync = (...args) => {
counts.readdirSync += 1;
return originalReaddirSync(...args);
};
syncBuiltinESMExports();
const { createExtensionTestShards, resolveExtensionBatchPlan } = await import("./scripts/lib/extension-test-plan.mjs");
const extensionIds = ["matrix", "openai", "slack", "telegram"];
const batch = resolveExtensionBatchPlan({ cwd: process.cwd(), extensionIds });
const shards = createExtensionTestShards({ cwd: process.cwd(), extensionIds, shardCount: 2 });
console.log(JSON.stringify({
batchTests: batch.testFileCount,
counts,
shards: shards.length,
shardTests: shards.reduce((total, shard) => total + shard.testFileCount, 0),
}));
`,
],
{
cwd: process.cwd(),
encoding: "utf8",
},
);
const payload = JSON.parse(output) as {
const payload = expectNoNodeFsScans<{
batchTests: number;
counts: { readdirSync: number };
shards: number;
shardTests: number;
};
}>(
`
const { createExtensionTestShards, resolveExtensionBatchPlan } =
await import("./scripts/lib/extension-test-plan.mjs");
const extensionIds = ["matrix", "openai", "slack", "telegram"];
const batch = resolveExtensionBatchPlan({ cwd: process.cwd(), extensionIds });
const shards = createExtensionTestShards({ cwd: process.cwd(), extensionIds, shardCount: 2 });
return {
batchTests: batch.testFileCount,
shards: shards.length,
shardTests: shards.reduce((total, shard) => total + shard.testFileCount, 0),
};
`,
{ counters: ["readdirSync"] },
);
expect(payload.batchTests).toBeGreaterThan(0);
expect(payload.shards).toBe(2);
expect(payload.shardTests).toBe(payload.batchTests);
expect(payload.counts.readdirSync).toBe(0);
});
it("balances extension test shards by estimated CI cost", () => {

View File

@@ -1,26 +1,23 @@
import fs, { readFileSync } from "node:fs";
import { describe, expect, it, vi } from "vitest";
import { describe, expect, it } from "vitest";
import {
LIVE_TEST_SHARDS,
RELEASE_LIVE_TEST_SHARDS,
collectAllLiveTestFiles,
selectLiveShardFiles,
} from "../../scripts/test-live-shard.mjs";
import { expectNoReaddirSyncDuring } from "../../src/test-utils/fs-scan-assertions.js";
describe("scripts/test-live-shard", () => {
const allFiles = collectAllLiveTestFiles();
it("discovers live tests without scanning source roots in-process", () => {
const readDir = vi.spyOn(fs, "readdirSync");
try {
expectNoReaddirSyncDuring(() => {
const files = collectAllLiveTestFiles();
expect(files.length).toBeGreaterThan(0);
expect(files.every((file) => file.endsWith(".live.test.ts"))).toBe(true);
expect(readDir).not.toHaveBeenCalled();
} finally {
readDir.mockRestore();
}
});
});
it("covers every native live test and tracks provider-filtered release fanout", () => {

View File

@@ -17,6 +17,7 @@ import {
resolveParallelFullSuiteConcurrency,
shouldRetryVitestNoOutputTimeout,
} from "../../scripts/test-projects.test-support.mjs";
import { captureReaddirSyncCallsDuring } from "../../src/test-utils/fs-scan-assertions.js";
import { fullSuiteVitestShards } from "../vitest/vitest.test-shards.mjs";
const normalizeRepoPath = (value: string) => value.replaceAll("\\", "/");
@@ -1172,20 +1173,16 @@ describe("scripts/test-projects full-suite sharding", () => {
const gatewayServerConfig = "test/vitest/vitest.gateway-server.config.ts";
process.env.OPENCLAW_TEST_PROJECTS_LEAF_SHARDS = "1";
let plans: ReturnType<typeof buildFullSuiteVitestRunPlans>;
const readdirSync = vi.spyOn(fs, "readdirSync");
const before = readdirSync.mock.calls.length;
let gatewayTreeReads: unknown[][] = [];
try {
plans = buildFullSuiteVitestRunPlans([], process.cwd());
gatewayTreeReads = readdirSync.mock.calls
.slice(before)
.filter(([target]) =>
typeof target === "string"
? normalizeRepoPath(target).includes("src/gateway")
: false,
);
const captured = captureReaddirSyncCallsDuring(() =>
buildFullSuiteVitestRunPlans([], process.cwd()),
);
plans = captured.result;
gatewayTreeReads = captured.calls.filter(([target]) =>
typeof target === "string" ? normalizeRepoPath(target).includes("src/gateway") : false,
);
} finally {
readdirSync.mockRestore();
if (previous === undefined) {
delete process.env.OPENCLAW_TEST_PROJECTS_LEAF_SHARDS;
} else {