mirror of
https://github.com/agentclientprotocol/claude-agent-acp.git
synced 2026-10-27 04:30:59 +00:00
test: fix integration-run failures in provider, model and session-index tests (#1439)
## Summary Fixes the 23 failures seen with `RUN_INTEGRATION_TESTS=true`. All are test-side; no adapter changes. - **Provider tests (20 failures):** since #1340, `providers/set` lists the gateway's models with `fetch` in the test process. `vitest.config.ts` only loaded `setup-no-network.ts` outside integration runs, so tests that point at `https://gateway.example.com` made real requests and failed with `fetch failed`. The stub now loads in every run. `gateway-models.ts` is the only in-process `fetch` caller, and no integration test targets a real gateway. - **"the real SDK exposes one plain Opus row":** the CLI catalogue now also lists pinned older models (`claude-opus-5`, `claude-opus-4-8`, …), and the alias row's display name is "Opus 5.5". The check now covers only alias rows (`value` starting with `opus`) and still asserts there is a single row with no 1M variant. - **session-index `ENOTEMPTY` in teardown:** integration runs leave `CLAUDE_CODE_EXECUTABLE` unset, so initialize ran the real `claude auth status` in the background. It wrote into the temp `CLAUDE_CONFIG_DIR` while `afterEach` removed it. The file now stubs the executable to `/usr/bin/false`, as the scenario tests do. - **session-index relocation test:** the wait ended on any removal from the old path's subscription. That removal can name the other path's session, so the test now waits for the relocated session's own id. ## Testing - The six previously failing files pass with `RUN_INTEGRATION_TESTS=true` (454 tests). - `session-index.test.ts` passed 3× with integration on and 1× without (173 tests). Those failures were intermittent, so a few clean runs don't fully prove the fix. - `npx vitest run` (3360 tests) and `npm run check` pass. - The full integration suite was not rerun end to end. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -238,19 +238,18 @@ it.skipIf(!process.env.RUN_INTEGRATION_TESTS)(
|
|||||||
const q = query({ prompt: input(), options: { persistSession: false, abortController } });
|
const q = query({ prompt: input(), options: { persistSession: false, abortController } });
|
||||||
try {
|
try {
|
||||||
const { models } = await q.initializationResult();
|
const { models } = await q.initializationResult();
|
||||||
const opusModels = models.filter(
|
// Only alias rows ("opus", "opus[1m]"). The catalogue also lists pinned
|
||||||
(model) =>
|
// older versions such as "claude-opus-4-8"; those are separate models.
|
||||||
model.value !== "default" &&
|
const opusModels = models.filter((model) => /^opus\b/i.test(model.value));
|
||||||
/\bopus\b/i.test(`${model.value} ${model.resolvedModel} ${model.displayName}`),
|
|
||||||
);
|
|
||||||
expect(opusModels).toHaveLength(1);
|
expect(opusModels).toHaveLength(1);
|
||||||
// CLI 2.1.283 dropped the "[1m]" / "(1M context)" spelling from the Opus
|
// CLI 2.1.283 dropped the "[1m]" / "(1M context)" spelling from the Opus
|
||||||
// row: Opus is natively 1M, so the row names the plain model.
|
// row: Opus is natively 1M, so the row names the plain model.
|
||||||
expect(opusModels[0]).toMatchObject({
|
expect(opusModels[0]).toMatchObject({
|
||||||
value: "opus",
|
value: "opus",
|
||||||
displayName: "Opus",
|
displayName: expect.stringMatching(/^Opus\b/),
|
||||||
resolvedModel: expect.stringMatching(/^claude-opus-[\d-]+$/),
|
resolvedModel: expect.stringMatching(/^claude-opus-[\d-]+$/),
|
||||||
});
|
});
|
||||||
|
expect(opusModels[0].displayName).not.toMatch(/\b1m\b/i);
|
||||||
expect(opusModels[0].description).not.toMatch(/\b1m\b/i);
|
expect(opusModels[0].description).not.toMatch(/\b1m\b/i);
|
||||||
} finally {
|
} finally {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
|
|||||||
@@ -69,10 +69,15 @@ beforeEach(async () => {
|
|||||||
configDir = fsSync.realpathSync(await fs.mkdtemp(path.join(os.tmpdir(), "session-index-cfg-")));
|
configDir = fsSync.realpathSync(await fs.mkdtemp(path.join(os.tmpdir(), "session-index-cfg-")));
|
||||||
workspace = fsSync.realpathSync(await fs.mkdtemp(path.join(os.tmpdir(), "session-index-ws-")));
|
workspace = fsSync.realpathSync(await fs.mkdtemp(path.join(os.tmpdir(), "session-index-ws-")));
|
||||||
process.env.CLAUDE_CONFIG_DIR = configDir;
|
process.env.CLAUDE_CONFIG_DIR = configDir;
|
||||||
|
// Integration runs leave CLAUDE_CODE_EXECUTABLE unset, so initialize would run
|
||||||
|
// the real `claude auth status` in the background. It writes into configDir
|
||||||
|
// while afterEach removes it, and the rm fails with ENOTEMPTY.
|
||||||
|
vi.stubEnv("CLAUDE_CODE_EXECUTABLE", "/usr/bin/false");
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
|
vi.unstubAllEnvs();
|
||||||
if (previousConfigDir === undefined) delete process.env.CLAUDE_CONFIG_DIR;
|
if (previousConfigDir === undefined) delete process.env.CLAUDE_CONFIG_DIR;
|
||||||
else process.env.CLAUDE_CONFIG_DIR = previousConfigDir;
|
else process.env.CLAUDE_CONFIG_DIR = previousConfigDir;
|
||||||
await fs.rm(configDir, { recursive: true, force: true });
|
await fs.rm(configDir, { recursive: true, force: true });
|
||||||
@@ -3528,7 +3533,8 @@ describe("paths that share a project directory", () => {
|
|||||||
.filter((s) => s.sessionId === mine.id);
|
.filter((s) => s.sessionId === mine.id);
|
||||||
const removed = () =>
|
const removed = () =>
|
||||||
changesFor(notifications, fromDotted.subscriptionId).flatMap((c) => c.removed);
|
changesFor(notifications, fromDotted.subscriptionId).flatMap((c) => c.removed);
|
||||||
expect(await waitFor(() => added().length > 0 && removed().length > 0)).toBe(true);
|
// Wait for mine.id itself: the other path's session can be removed first.
|
||||||
|
expect(await waitFor(() => added().length > 0 && removed().includes(mine.id))).toBe(true);
|
||||||
expect(added().map((s) => [s.sessionId, s.cwd])).toEqual([[mine.id, dashed]]);
|
expect(added().map((s) => [s.sessionId, s.cwd])).toEqual([[mine.id, dashed]]);
|
||||||
// It may also name the other path's session, never listed here.
|
// It may also name the other path's session, never listed here.
|
||||||
expect(removed()).toContain(mine.id);
|
expect(removed()).toContain(mine.id);
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ export default defineConfig({
|
|||||||
// tests off the machine's real CLI and Claude config, and stops a run
|
// tests off the machine's real CLI and Claude config, and stops a run
|
||||||
// from outliving its test (it wrote into temp config dirs being deleted).
|
// from outliving its test (it wrote into temp config dirs being deleted).
|
||||||
env: usesRealCli ? {} : { CLAUDE_CODE_EXECUTABLE: "/usr/bin/false" },
|
env: usesRealCli ? {} : { CLAUDE_CODE_EXECUTABLE: "/usr/bin/false" },
|
||||||
// Real-CLI runs may want a real gateway listing.
|
// Applies to real-CLI runs too: the gateway listing runs in the test process,
|
||||||
setupFiles: usesRealCli ? [] : ["src/tests/setup-no-network.ts"],
|
// and tests point `providers/set` at fake URLs like gateway.example.com.
|
||||||
|
setupFiles: ["src/tests/setup-no-network.ts"],
|
||||||
include: [
|
include: [
|
||||||
"src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
|
"src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
|
||||||
// Release tooling lives in scripts/ rather than src/ so it stays outside tsc's
|
// Release tooling lives in scripts/ rather than src/ so it stays outside tsc's
|
||||||
|
|||||||
Reference in New Issue
Block a user