test(cli): isolate process exit coverage (#114903)

This commit is contained in:
Peter Steinberger
2026-07-28 00:41:49 -04:00
committed by GitHub
parent 852120e724
commit 258cc84965
12 changed files with 108 additions and 3 deletions
+1 -1
View File
@@ -1167,7 +1167,7 @@ const SPLIT_NODE_SHARDS = new Map([
...createGatewayServerSplitShards(),
{
shardName: "agentic-cli",
configs: ["test/vitest/vitest.cli.config.ts"],
configs: ["test/vitest/vitest.cli.config.ts", "test/vitest/vitest.cli-process.config.ts"],
requiresDist: false,
},
{
+26
View File
@@ -11,6 +11,10 @@ import {
isAgentsCoreIsolatedTestFile,
} from "../test/vitest/vitest.agents-paths.mjs";
import { isChannelSurfaceTestFile } from "../test/vitest/vitest.channel-paths.mjs";
import {
cliProcessTestFiles,
isCliProcessTestFile,
} from "../test/vitest/vitest.cli-process-paths.mjs";
import {
commandsLightTestFiles,
isCommandsLightTarget,
@@ -98,6 +102,7 @@ const AUTO_REPLY_TOP_LEVEL_VITEST_CONFIG = "test/vitest/vitest.auto-reply-top-le
const BOUNDARY_VITEST_CONFIG = "test/vitest/vitest.boundary.config.ts";
const BUNDLED_VITEST_CONFIG = "test/vitest/vitest.bundled.config.ts";
const CHANNEL_VITEST_CONFIG = "test/vitest/vitest.channels.config.ts";
const CLI_PROCESS_VITEST_CONFIG = "test/vitest/vitest.cli-process.config.ts";
const CLI_VITEST_CONFIG = "test/vitest/vitest.cli.config.ts";
const COMMANDS_LIGHT_VITEST_CONFIG = "test/vitest/vitest.commands-light.config.ts";
const COMMANDS_VITEST_CONFIG = "test/vitest/vitest.commands.config.ts";
@@ -225,6 +230,7 @@ const FULL_SUITE_CONFIG_WEIGHT = new Map([
[EXTENSION_TELEGRAM_VITEST_CONFIG, 94],
[EXTENSION_WHATSAPP_VITEST_CONFIG, 92],
[AUTO_REPLY_CORE_VITEST_CONFIG, 90],
[CLI_PROCESS_VITEST_CONFIG, 87],
[CLI_VITEST_CONFIG, 86],
[MEDIA_VITEST_CONFIG, 84],
[PLUGINS_VITEST_CONFIG, 82],
@@ -343,6 +349,7 @@ const VITEST_CONFIG_BY_KIND = {
boundary: BOUNDARY_VITEST_CONFIG,
bundled: BUNDLED_VITEST_CONFIG,
channel: CHANNEL_VITEST_CONFIG,
cliProcess: CLI_PROCESS_VITEST_CONFIG,
cli: CLI_VITEST_CONFIG,
command: COMMANDS_VITEST_CONFIG,
commandLight: COMMANDS_LIGHT_VITEST_CONFIG,
@@ -4215,6 +4222,9 @@ function classifyTarget(arg, cwd) {
if (isPathAtOrUnder(relative, "src/acp")) {
return "acp";
}
if (isCliProcessTestFile(relative)) {
return "cliProcess";
}
if (isPathAtOrUnder(relative, "src/cli")) {
return "cli";
}
@@ -4438,6 +4448,21 @@ export function buildVitestRunPlans(
}
groupedTargets.set("uiIsolated", current);
}
const cliTargets = groupedTargets.get("cli") ?? [];
const impliedCliProcessTargets = cliProcessTestFiles.filter((file) =>
cliTargets.some((targetArg) =>
includePatternMatchesAnyFile(toScopedIncludePattern(targetArg, cwd), [file]),
),
);
if (impliedCliProcessTargets.length > 0) {
const current = groupedTargets.get("cliProcess") ?? [];
for (const target of impliedCliProcessTargets) {
if (!current.includes(target)) {
current.push(target);
}
}
groupedTargets.set("cliProcess", current);
}
if (watchMode && groupedTargets.size > 1) {
throw new Error(
@@ -4482,6 +4507,7 @@ export function buildVitestRunPlans(
"tuiPty",
"mediaUnderstanding",
"acp",
"cliProcess",
"cli",
"commandLight",
"command",
+1 -1
View File
@@ -842,7 +842,7 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => {
expect(cliShard).toEqual({
checkName: "checks-node-agentic-cli",
shardName: "agentic-cli",
configs: ["test/vitest/vitest.cli.config.ts"],
configs: ["test/vitest/vitest.cli.config.ts", "test/vitest/vitest.cli-process.config.ts"],
requiresDist: false,
runner: DEFAULT_NODE_TEST_RUNNER,
});
+29 -1
View File
@@ -2902,7 +2902,6 @@ describe("scripts/test-projects changed-target routing", () => {
["src/agents", "test/vitest/vitest.agents.config.ts"],
["src/auto-reply", "test/vitest/vitest.auto-reply.config.ts"],
["src/channels", "test/vitest/vitest.channels.config.ts"],
["src/cli", "test/vitest/vitest.cli.config.ts"],
["src/config", "test/vitest/vitest.runtime-config.config.ts"],
["src/cron", "test/vitest/vitest.cron.config.ts"],
["src/daemon", "test/vitest/vitest.daemon.config.ts"],
@@ -2986,6 +2985,34 @@ describe("scripts/test-projects changed-target routing", () => {
]);
});
it("routes CLI process tests through their isolated project", () => {
expect(buildVitestRunPlans(["src/cli/help-exit.process.test.ts"])).toEqual([
{
config: "test/vitest/vitest.cli-process.config.ts",
forwardedArgs: [],
includePatterns: ["src/cli/help-exit.process.test.ts"],
watchMode: false,
},
]);
});
it("adds the CLI process project for broad CLI targets", () => {
const plans = buildVitestRunPlans(["src/cli"]);
expect(plans.map((plan) => plan.config)).toEqual([
"test/vitest/vitest.unit-fast.config.ts",
"test/vitest/vitest.cli-process.config.ts",
"test/vitest/vitest.cli.config.ts",
]);
expect(plans[1]?.includePatterns).toContain("src/cli/help-exit.process.test.ts");
});
it("rejects broad CLI watch targets that cross shared and process projects", () => {
expect(() => buildVitestRunPlans(["--watch", "src/cli"])).toThrow(
"watch mode with mixed test suites is not supported",
);
});
it("chunks broad shell helper globs after isolated targets", () => {
const plans = buildVitestRunPlans(["test/scripts/*.test.ts"], process.cwd());
expect(plans.slice(0, 4)).toEqual([
@@ -4778,6 +4805,7 @@ describe("scripts/test-projects full-suite sharding", () => {
gatewayServerConfig,
gatewayServerConfig,
gatewayServerConfig,
"test/vitest/vitest.cli-process.config.ts",
"test/vitest/vitest.cli.config.ts",
"test/vitest/vitest.commands-light.config.ts",
"test/vitest/vitest.commands.config.ts",
+12
View File
@@ -17,6 +17,8 @@ import { createAutoReplyTopLevelVitestConfig } from "./vitest/vitest.auto-reply-
import { createAutoReplyVitestConfig } from "./vitest/vitest.auto-reply.config.ts";
import bundledVitestConfig from "./vitest/vitest.bundled.config.ts";
import { createChannelsVitestConfig } from "./vitest/vitest.channels.config.ts";
import { cliProcessTestFiles } from "./vitest/vitest.cli-process-paths.mjs";
import { createCliProcessVitestConfig } from "./vitest/vitest.cli-process.config.ts";
import { createCliVitestConfig } from "./vitest/vitest.cli.config.ts";
import { createCommandsLightVitestConfig } from "./vitest/vitest.commands-light.config.ts";
import { createCommandsVitestConfig } from "./vitest/vitest.commands.config.ts";
@@ -521,6 +523,7 @@ describe("createScopedVitestConfig", () => {
describe("scoped vitest configs", () => {
const defaultChannelsConfig = createChannelsVitestConfig({});
const defaultAcpConfig = createAcpVitestConfig({});
const defaultCliProcessConfig = createCliProcessVitestConfig({});
const defaultCliConfig = createCliVitestConfig({});
const defaultExtensionsConfig = createExtensionsVitestConfig({});
const defaultExtensionAcpxConfig = createExtensionAcpxVitestConfig({});
@@ -611,6 +614,15 @@ describe("scoped vitest configs", () => {
expectThreadedIsolatedRunner(defaultExtensionMemoryConfig);
expectThreadedIsolatedRunner(defaultExtensionProvidersConfig);
expectForkedIsolatedRunner(defaultInfraConfig);
expectForkedIsolatedRunner(defaultCliProcessConfig);
});
it("keeps process-launching CLI files out of the shared CLI graph", () => {
expect(requireTestConfig(defaultCliConfig).exclude).toEqual(
expect.arrayContaining(cliProcessTestFiles.map((file) => file.replace("src/cli/", ""))),
);
expect(requireTestConfig(defaultCliProcessConfig).include).toEqual(cliProcessTestFiles);
expect(requireTestConfig(defaultCliProcessConfig).fileParallelism).toBe(false);
});
it("keeps native SQLite runtime config tests in forked workers", () => {
@@ -0,0 +1,2 @@
export const cliProcessTestFiles: string[];
export function isCliProcessTestFile(file: string): boolean;
+14
View File
@@ -0,0 +1,14 @@
// CLI process tests launch real Node+tsx children and must not contend with the
// shared CLI module graph. Keep the owned list explicit so full and focused runs agree.
export const cliProcessTestFiles = [
"src/cli/acp-cli-exit.process.test.ts",
"src/cli/gateway-backed-exit.process.test.ts",
"src/cli/help-exit.process.test.ts",
"src/cli/hooks-cli.process.test.ts",
];
const cliProcessTestFileSet = new Set(cliProcessTestFiles);
export function isCliProcessTestFile(value) {
return cliProcessTestFileSet.has(value.replaceAll("\\", "/"));
}
+18
View File
@@ -0,0 +1,18 @@
import { cliProcessTestFiles } from "./vitest.cli-process-paths.mjs";
// CLI process tests run serially in isolated forks so child startup deadlines
// measure the CLI rather than contention from the shared CLI test graph.
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export function createCliProcessVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(cliProcessTestFiles, {
env,
fileParallelism: false,
isolate: true,
name: "cli-process",
passWithNoTests: true,
pool: "forks",
useNonIsolatedRunner: false,
});
}
export default createCliProcessVitestConfig();
+2
View File
@@ -1,3 +1,4 @@
import { cliProcessTestFiles } from "./vitest.cli-process-paths.mjs";
// Vitest cli config wires the cli test shard.
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
@@ -5,6 +6,7 @@ export function createCliVitestConfig(env?: Record<string, string | undefined>)
return createScopedVitestConfig(["src/cli/**/*.test.ts"], {
dir: "src/cli",
env,
exclude: cliProcessTestFiles,
name: "cli",
passWithNoTests: true,
});
+1
View File
@@ -28,6 +28,7 @@ export const rootVitestProjects = [
"test/vitest/vitest.acp.config.ts",
"test/vitest/vitest.runtime-config.config.ts",
"test/vitest/vitest.secrets.config.ts",
"test/vitest/vitest.cli-process.config.ts",
"test/vitest/vitest.cli.config.ts",
"test/vitest/vitest.commands-light.config.ts",
"test/vitest/vitest.commands.config.ts",
+1
View File
@@ -107,6 +107,7 @@ const SCOPED_PROJECT_GROUP_ORDER_BY_NAME = new Map(
"boundary",
"bundled",
"channels",
"cli-process",
"cli",
"commands",
"commands-light",
+1
View File
@@ -97,6 +97,7 @@ export const fullSuiteVitestShards = [
"test/vitest/vitest.gateway-client.config.ts",
"test/vitest/vitest.gateway-methods.config.ts",
"test/vitest/vitest.gateway-server.config.ts",
"test/vitest/vitest.cli-process.config.ts",
"test/vitest/vitest.cli.config.ts",
"test/vitest/vitest.commands-light.config.ts",
"test/vitest/vitest.commands.config.ts",