Skip to content

Commit b4e0c53

Browse files
committed
test(scripts): replace brittle temp-dir importer inventory with structural routing assertions
The 'routes top-level test helpers to importing repo tests' test froze the full list of tests importing test/helpers/temp-dir.ts; any new importer broke main's checks shard (twice on 2026-07-05). Assert routing structure instead: scan-derived direct-importer lower bound, partition invariants, and per-file consistency with single-target routing.
1 parent 2b7003d commit b4e0c53

1 file changed

Lines changed: 63 additions & 161 deletions

File tree

src/scripts/test-projects.test.ts

Lines changed: 63 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// Test project script tests cover fixture project discovery and validation.
2+
import { spawnSync } from "node:child_process";
23
import fs from "node:fs";
34
import os from "node:os";
45
import path from "node:path";
@@ -854,167 +855,68 @@ describe("test-projects args", () => {
854855
});
855856

856857
it("routes top-level test helpers to importing repo tests", () => {
857-
expect(buildVitestRunPlans(["test/helpers/temp-dir.ts"])).toEqual([
858-
{
859-
config: "test/vitest/vitest.unit-fast.config.ts",
860-
forwardedArgs: [],
861-
includePatterns: [
862-
"src/agents/command/attempt-execution.shared.test.ts",
863-
"src/auto-reply/reply/session-entry-persistence.test.ts",
864-
"src/crestodian/operations.test.ts",
865-
"src/install-sh-version.test.ts",
866-
"src/proxy-capture/store.sqlite.test.ts",
867-
"test/scripts/android-version.test.ts",
868-
"test/scripts/resolve-openclaw-ref.test.ts",
869-
],
870-
watchMode: false,
871-
},
872-
{
873-
config: "test/vitest/vitest.unit-fast-fake-timers.config.ts",
874-
forwardedArgs: [],
875-
includePatterns: ["src/entry.compile-cache.test.ts"],
876-
watchMode: false,
877-
},
878-
{
879-
config: "test/vitest/vitest.unit.config.ts",
880-
forwardedArgs: [
881-
"src/state/openclaw-agent-db.test.ts",
882-
"src/state/openclaw-state-db.test.ts",
883-
"src/state/sqlite-query-plan.test.ts",
884-
"src/transcripts/store.test.ts",
885-
],
886-
includePatterns: null,
887-
watchMode: false,
888-
},
889-
{
890-
config: "test/vitest/vitest.tooling.config.ts",
891-
forwardedArgs: [],
892-
includePatterns: [
893-
"src/scripts/docs-link-audit.test.ts",
894-
"src/scripts/sync-plugin-versions.test.ts",
895-
"test/e2e/qa-lab/runtime/gateway-mcp-real-transports.test.ts",
896-
"test/helpers/temp-dir.test.ts",
897-
"test/scripts/android-pin-version.test.ts",
898-
"test/scripts/bench-cli-startup.test.ts",
899-
"test/scripts/check-package-dist-imports.test.ts",
900-
"test/scripts/check-workflows.test.ts",
901-
"test/scripts/ci-hydrate-testbox-env.test.ts",
902-
"test/scripts/clawhub-fixture-server.test.ts",
903-
"test/scripts/codex-install-assertions.test.ts",
904-
"test/scripts/config-reload-mutate-metadata.test.ts",
905-
"test/scripts/control-ui-i18n.test.ts",
906-
"test/scripts/docs-list.test.ts",
907-
"test/scripts/doctor-install-switch-wrapper.test.ts",
908-
"test/scripts/e2e-shell-tempfiles.test.ts",
909-
"test/scripts/e2e-text-file-utils.test.ts",
910-
"test/scripts/fixture-common.test.ts",
911-
"test/scripts/fixture-plugin-commands.test.ts",
912-
"test/scripts/incremental-line-reader.test.ts",
913-
"test/scripts/ios-configure-signing.test.ts",
914-
"test/scripts/ios-team-id.test.ts",
915-
"test/scripts/ios-version.test.ts",
916-
"test/scripts/kitchen-sink-rpc-walk.test.ts",
917-
"test/scripts/native-app-i18n.test.ts",
918-
"test/scripts/onboard-config-fixtures.test.ts",
919-
"test/scripts/package-git-fixture.test.ts",
920-
"test/scripts/parallels-lib-helpers.test.ts",
921-
"test/scripts/parallels-package-log-progress-extract.test.ts",
922-
"test/scripts/parallels-smoke-model.test.ts",
923-
"test/scripts/plugin-package-dependencies.test.ts",
924-
"test/scripts/plugins-assertions.test.ts",
925-
"test/scripts/prepare-extension-package-boundary-artifacts.test.ts",
926-
"test/scripts/proxy-install-ca.test.ts",
927-
"test/scripts/release-preflight.test.ts",
928-
"test/scripts/render-maturity-docs.test.ts",
929-
"test/scripts/report-test-temp-creations.test.ts",
930-
"test/scripts/runtime-postbuild-stamp.test.ts",
931-
"test/scripts/test-install-sh-docker.test.ts",
932-
"test/scripts/test-projects.test.ts",
933-
"test/test-env.test.ts",
934-
"test/vitest-scoped-config.test.ts",
935-
],
936-
watchMode: false,
937-
},
938-
{
939-
config: "test/vitest/vitest.gateway.config.ts",
940-
forwardedArgs: [],
941-
includePatterns: [
942-
"src/gateway/hooks-mapping.test.ts",
943-
"src/gateway/server-methods/chat.abort-persistence.test.ts",
944-
"src/gateway/server.agent.gateway-server-agent-b.test.ts",
945-
"src/gateway/server.chat.gateway-server-chat-b.test.ts",
946-
"src/gateway/server.sessions.permissions-hooks.test.ts",
947-
"src/gateway/terminal/launch.test.ts",
948-
],
949-
watchMode: false,
950-
},
951-
{
952-
config: "test/vitest/vitest.runtime-config.config.ts",
953-
forwardedArgs: [],
954-
includePatterns: ["src/config/sessions/entry-freshness.test.ts"],
955-
watchMode: false,
956-
},
957-
{
958-
config: "test/vitest/vitest.cron.config.ts",
959-
forwardedArgs: [],
960-
includePatterns: [
961-
"src/cron/isolated-agent/run-session-state.test.ts",
962-
"src/cron/run-log.error-reason.test.ts",
963-
],
964-
watchMode: false,
965-
},
966-
{
967-
config: "test/vitest/vitest.commands.config.ts",
968-
forwardedArgs: [],
969-
includePatterns: [
970-
"src/commands/doctor-completion.test.ts",
971-
"src/commands/status.scan.shared.test.ts",
972-
],
973-
watchMode: false,
974-
},
975-
{
976-
config: "test/vitest/vitest.auto-reply.config.ts",
977-
forwardedArgs: [],
978-
includePatterns: [
979-
"src/auto-reply/reply/get-reply-native-slash-fast-path.test.ts",
980-
"src/auto-reply/reply/get-reply.auto-fallback.test.ts",
981-
"src/auto-reply/reply/reply-turn-admission.test.ts",
982-
"src/auto-reply/reply/session-updates.test.ts",
983-
],
984-
watchMode: false,
985-
},
986-
{
987-
config: "test/vitest/vitest.agents.config.ts",
988-
forwardedArgs: [],
989-
includePatterns: [
990-
"src/agents/agent-bundle-mcp-runtime.test.ts",
991-
"src/agents/agent-tools-agent-config.exec.test.ts",
992-
"src/agents/bash-tools.exec-foreground-failures.test.ts",
993-
"src/agents/cli-runner.reliability.test.ts",
994-
"src/agents/models-config.file-mode.test.ts",
995-
"src/agents/sandbox/ssh.test.ts",
996-
"src/agents/sessions/tools/find.fd.test.ts",
997-
"src/agents/sessions/tools/read.test.ts",
998-
],
999-
watchMode: false,
1000-
},
1001-
{
1002-
config: "test/vitest/vitest.plugins.config.ts",
1003-
forwardedArgs: [],
1004-
includePatterns: ["src/plugins/git-install.test.ts"],
1005-
watchMode: false,
1006-
},
1007-
{
1008-
config: "test/vitest/vitest.e2e.config.ts",
1009-
forwardedArgs: [
1010-
"test/e2e/qa-lab/plugins/plugin-lifecycle-probe.e2e.test.ts",
1011-
"test/e2e/qa-lab/runtime/openai-compatible-chat-tools.e2e.test.ts",
1012-
"test/openclaw-launcher.e2e.test.ts",
1013-
],
1014-
includePatterns: null,
1015-
watchMode: false,
1016-
},
1017-
]);
858+
// The importer inventory of test/helpers/temp-dir.ts churns with every new
859+
// test using the helper; frozen full lists broke main on unrelated test
860+
// additions. Assert the routing structure instead of the inventory.
861+
const plans = buildVitestRunPlans(["test/helpers/temp-dir.ts"]);
862+
const planFiles = plans.map((plan) => plan.includePatterns ?? plan.forwardedArgs);
863+
const expandedFiles = planFiles.flat();
864+
865+
// Helper targets expand to importing test files; the helper itself never
866+
// reaches Vitest as a raw target.
867+
expect(expandedFiles).toContain("test/helpers/temp-dir.test.ts");
868+
expect(expandedFiles).not.toContain("test/helpers/temp-dir.ts");
869+
expect(expandedFiles.filter((file) => !file.endsWith(".test.ts"))).toEqual([]);
870+
871+
// Lower bound derived from the repo itself: every tracked test file that
872+
// directly imports the helper must be picked up by the expansion scan, so
873+
// dropped importers still fail without freezing the full inventory.
874+
const scanRoots = ["src", "test", "ui", "extensions", "packages"];
875+
const grep = spawnSync(
876+
"git",
877+
["grep", "-l", "--fixed-strings", "helpers/temp-dir", "--", ...scanRoots],
878+
{ encoding: "utf8" },
879+
);
880+
expect(grep.status).toBe(0);
881+
const directImporterTests = grep.stdout
882+
.split("\n")
883+
.map((line) => line.trim())
884+
.filter((file) => file.endsWith(".test.ts") && !file.endsWith(".live.test.ts"))
885+
.filter((file) => {
886+
const source = fs.readFileSync(file, "utf8");
887+
return [...source.matchAll(/from\s+["'](\.[^"']+)["']/gu)].some((match) => {
888+
const importerDir = path.posix.dirname(file);
889+
const resolved = path.posix.normalize(path.posix.join(importerDir, match[1]));
890+
return resolved.replace(/\.(?:js|ts)$/u, "") === "test/helpers/temp-dir";
891+
});
892+
});
893+
expect(directImporterTests.length).toBeGreaterThan(0);
894+
expect(directImporterTests.filter((file) => !expandedFiles.includes(file))).toEqual([]);
895+
896+
// Importers partition across configs: each file lands in exactly one plan,
897+
// in deterministic sorted order.
898+
expect(plans.length).toBeGreaterThan(1);
899+
expect(new Set(expandedFiles).size).toBe(expandedFiles.length);
900+
for (const files of planFiles) {
901+
expect(files).toEqual([...files].toSorted((left, right) => left.localeCompare(right)));
902+
}
903+
904+
// Each importer must route to the same config and include-vs-forwarded
905+
// shape as targeting it directly, so this test fails on real routing
906+
// regressions but not on new importers of the helper.
907+
for (const plan of plans) {
908+
expect(plan.watchMode).toBe(false);
909+
for (const file of plan.includePatterns ?? plan.forwardedArgs) {
910+
expect(buildVitestRunPlans([file])).toEqual([
911+
{
912+
config: plan.config,
913+
forwardedArgs: plan.includePatterns ? [] : [file],
914+
includePatterns: plan.includePatterns ? [file] : null,
915+
watchMode: false,
916+
},
917+
]);
918+
}
919+
}
1018920
});
1019921

1020922
it("routes e2e targets straight to the e2e config", () => {

0 commit comments

Comments
 (0)