--- model: google/gemini-3.1-pro-preview --- # Plan: Lightweight Testing for `multi-model.ts` ## Overview To test `.opencode/tools/multi-model.ts` without executing actual commands on your filesystem or Git repository, we will use **`bun:test`**. Since your project is already utilizing Bun (evident from `Bun.$`), `bun:test` is the perfect built-in, zero-dependency, and lightweight testing framework. It comes with Jest-compatible mocking out of the box. ## Mocking Strategy The tool interacts with the system via three main avenues, all of which we will mock: 1. **Filesystem checks (`node:fs`)**: The tool only uses `fs.existsSync`. We will mock this using `spyOn(fs, 'existsSync')`. 2. **OS details (`node:os`)**: We will mock `os.homedir()` using `spyOn(os, 'homedir')` to return a safe, fake path. 3. **Shell commands (`Bun.$`)**: The tool extensively executes `git`, `tmux`, and `opencode` commands via `Bun.$`${parts}`.quiet().nothrow()`. We can override `globalThis.Bun.$` with a custom mock function that inspects the command parts and returns simulated deterministic outputs (exit code, stdout, stderr). ## Implementation Details Create a new file `.opencode/tools/multi-model.test.ts` and set up the mocks as follows: ```typescript import { expect, test, mock, spyOn, beforeEach, afterEach } from "bun:test"; import * as fs from "node:fs"; import * as os from "node:os"; import multiModelTool from "./multi-model"; // 1. Mock OS and FS spyOn(os, "homedir").mockReturnValue("/mock/home"); const existsSyncMock = spyOn(fs, "existsSync").mockReturnValue(false); // 2. Mock Bun.$ const originalBun$ = Bun.$; let mockCommandResponses: Record = {}; function setupMockBun$() { (globalThis as any).Bun.$ = mock((strings: TemplateStringsArray, ...values: any[]) => { // In Bun.$`${parts}`, parts is an array passed as the first value const parts = values[0] as string[]; const commandSignature = parts.join(" "); return { quiet: () => ({ nothrow: async () => { // You can define specific responses for specific commands if (mockCommandResponses[commandSignature]) { return mockCommandResponses[commandSignature]; } // Default successful response return { exitCode: 0, stdout: { toString: () => "" }, stderr: { toString: () => "" }, }; }, }), }; }); } beforeEach(() => { setupMockBun$(); existsSyncMock.mockClear(); mockCommandResponses = { // Provide a default opencode models list for tests "opencode models": { exitCode: 0, stdout: { toString: () => "openai/gpt-4\nanthropic/claude-3" }, stderr: { toString: () => "" } }, // Mock that session does not exist by default "tmux has-session -t test-session": { exitCode: 1, // 1 means session does not exist in tmux stdout: { toString: () => "" }, stderr: { toString: () => "session not found" } } }; }); afterEach(() => { // Restore original Bun.$ (globalThis as any).Bun.$ = originalBun$; }); // 3. Write Tests test("fails if duplicate models are provided", async () => { const result = await multiModelTool.execute( { sessionName: "test-session", models: ["openai/gpt-4", "openai/gpt-4"] }, { metadata: mock() } as any ); expect(result).toContain("Duplicate model names are not allowed"); }); test("successfully plans and executes tmux launch", async () => { const result = await multiModelTool.execute( { sessionName: "test-session", models: ["openai/gpt-4", "anthropic/claude-3"] }, { metadata: mock() } as any ); expect(result).toContain("Use `tmux attach -t test-session` to join session"); // You can also assert that Bun.$ was called with specific commands // by inspecting (globalThis as any).Bun$.mock.calls }); ``` ## Verification You can verify and run these tests safely without any system side-effects by running: ```bash bun test .opencode/tools/multi-model.test.ts ```