From bb0c0d8ee329059b12e7c28860e4cf1aae15487c Mon Sep 17 00:00:00 2001 From: Tommaso Sciortino Date: Mon, 15 Dec 2025 13:18:04 -0800 Subject: [PATCH] Simplify method signature. (#15114) --- integration-tests/extensions-reload.test.ts | 2 +- integration-tests/file-system.test.ts | 28 +++--- integration-tests/google_web_search.test.ts | 2 +- integration-tests/hooks-system.test.ts | 85 ++++++++-------- integration-tests/json-output.test.ts | 28 +++--- integration-tests/list_directory.test.ts | 2 +- integration-tests/mixed-input-crash.test.ts | 19 ++-- integration-tests/read_many_files.test.ts | 2 +- integration-tests/replace.test.ts | 18 ++-- integration-tests/run_shell_command.test.ts | 106 +++++++++----------- integration-tests/save_memory.test.ts | 2 +- integration-tests/simple-mcp-server.test.ts | 6 +- integration-tests/stdin-context.test.ts | 2 +- integration-tests/telemetry.test.ts | 2 +- integration-tests/test-helper.ts | 87 ++++++---------- integration-tests/utf-bom-encoding.test.ts | 4 +- integration-tests/write_file.test.ts | 2 +- 17 files changed, 184 insertions(+), 213 deletions(-) diff --git a/integration-tests/extensions-reload.test.ts b/integration-tests/extensions-reload.test.ts index 5e37777573..29db8522ad 100644 --- a/integration-tests/extensions-reload.test.ts +++ b/integration-tests/extensions-reload.test.ts @@ -82,7 +82,7 @@ describe('extension reloading', () => { writeFileSync(testServerPath, safeJsonStringify(extension, 2)); // Start the CLI. - const run = await rig.runInteractive('--debug'); + const run = await rig.runInteractive({ args: '--debug' }); await run.expectText('You have 1 extension with an update available'); // See the outdated extension await run.sendText('/extensions list'); diff --git a/integration-tests/file-system.test.ts b/integration-tests/file-system.test.ts index 72cdd2f4ff..a1041acfcd 100644 --- a/integration-tests/file-system.test.ts +++ b/integration-tests/file-system.test.ts @@ -24,9 +24,9 @@ describe('file-system', () => { }); rig.createFile('test.txt', 'hello world'); - const result = await rig.run( - `read the file test.txt and show me its contents`, - ); + const result = await rig.run({ + args: `read the file test.txt and show me its contents`, + }); const foundToolCall = await rig.waitForToolCall('read_file'); @@ -53,7 +53,9 @@ describe('file-system', () => { }); rig.createFile('test.txt', ''); - const result = await rig.run(`edit test.txt to have a hello world message`); + const result = await rig.run({ + args: `edit test.txt to have a hello world message`, + }); // Accept multiple valid tools for editing files const foundToolCall = await rig.waitForAnyToolCall([ @@ -109,9 +111,9 @@ describe('file-system', () => { }); const fileName = 'my test file.txt'; - const result = await rig.run( - `write "hello" to "${fileName}" and then stop. Do not perform any other actions.`, - ); + const result = await rig.run({ + args: `write "hello" to "${fileName}" and then stop. Do not perform any other actions.`, + }); const foundToolCall = await rig.waitForToolCall('write_file'); if (!foundToolCall) { @@ -134,7 +136,7 @@ describe('file-system', () => { rig.createFile(fileName, '1.0.0'); const prompt = `Read the version from ${fileName} and write the next version 1.0.1 back to the file.`; - const result = await rig.run(prompt); + const result = await rig.run({ args: prompt }); await rig.waitForTelemetryReady(); const toolLogs = rig.readToolLogs(); @@ -169,9 +171,9 @@ describe('file-system', () => { const expectedContent = 'Hey there, \nnew line\nnew line'; rig.createFile(fileName, fileContent); - const result = await rig.run( - `rewrite the file ${fileName} to replace all instances of "test line" with "new line"`, - ); + const result = await rig.run({ + args: `rewrite the file ${fileName} to replace all instances of "test line" with "new line"`, + }); const validTools = ['write_file', 'edit']; const foundToolCall = await rig.waitForAnyToolCall(validTools); @@ -220,7 +222,9 @@ describe('file-system', () => { ); const fileName = 'non_existent.txt'; - const result = await rig.run(`In ${fileName}, replace "a" with "b"`); + const result = await rig.run({ + args: `In ${fileName}, replace "a" with "b"`, + }); await rig.waitForTelemetryReady(); const toolLogs = rig.readToolLogs(); diff --git a/integration-tests/google_web_search.test.ts b/integration-tests/google_web_search.test.ts index 3053c01492..391d4a7ec4 100644 --- a/integration-tests/google_web_search.test.ts +++ b/integration-tests/google_web_search.test.ts @@ -24,7 +24,7 @@ describe('web search tool', () => { let result; try { - result = await rig.run(`what is the weather in London`); + result = await rig.run({ args: `what is the weather in London` }); } catch (error) { // Network errors can occur in CI environments if ( diff --git a/integration-tests/hooks-system.test.ts b/integration-tests/hooks-system.test.ts index 4b9ba03e59..46b0c88359 100644 --- a/integration-tests/hooks-system.test.ts +++ b/integration-tests/hooks-system.test.ts @@ -55,8 +55,9 @@ describe('Hooks System Integration', () => { }, ); - const prompt = 'Create a file called test.txt with content "Hello World"'; - const result = await rig.run(prompt); + const result = await rig.run({ + args: 'Create a file called test.txt with content "Hello World"', + }); // The hook should block the write_file tool const toolLogs = rig.readToolLogs(); @@ -107,9 +108,9 @@ describe('Hooks System Integration', () => { }, ); - const prompt = - 'Create a file called approved.txt with content "Approved content"'; - await rig.run(prompt); + await rig.run({ + args: 'Create a file called approved.txt with content "Approved content"', + }); // The hook should allow the write_file tool const foundWriteFile = await rig.waitForToolCall('write_file'); @@ -158,9 +159,9 @@ describe('Hooks System Integration', () => { // Create a test file to read rig.createFile('test-file.txt', 'This is test content'); - const prompt = - 'Read the contents of test-file.txt and tell me what it contains'; - await rig.run(prompt); + await rig.run({ + args: 'Read the contents of test-file.txt and tell me what it contains', + }); // Should find read_file tool call const foundReadFile = await rig.waitForToolCall('read_file'); @@ -232,8 +233,7 @@ echo '{ }, }); - const prompt = 'Tell me a story'; - const result = await rig.run(prompt); + const result = await rig.run({ args: 'Tell me a story' }); // The hook should have replaced the request entirely // Verify that the model responded to the modified request, not the original @@ -316,8 +316,7 @@ echo '{ }, }); - const prompt = 'What is 2 + 2?'; - const result = await rig.run(prompt); + const result = await rig.run({ args: 'What is 2 + 2?' }); // The hook should have replaced the model response expect(result).toContain( @@ -374,9 +373,9 @@ echo '{ // Create a test file rig.createFile('new_file_data.txt', 'test data'); - const prompt = - 'Check the content of new_file_data.txt, after that run echo command to see the content'; - await rig.run(prompt); + await rig.run({ + args: 'Check the content of new_file_data.txt, after that run echo command to see the content', + }); // Should use read_file (allowed) but not run_shell_command (not in allowed list) const foundReadFile = await rig.waitForToolCall('read_file'); @@ -440,8 +439,7 @@ echo '{ }, }); - const prompt = 'Hello, how are you?'; - const result = await rig.run(prompt); + const result = await rig.run({ args: 'Hello, how are you?' }); // The hook should have added security context, which should influence the response expect(result).toContain('security'); @@ -585,8 +583,7 @@ echo '{ }, }); - const prompt = 'Hello, please help me with a task'; - await rig.run(prompt); + await rig.run({ args: 'Hello, please help me with a task' }); // Should generate hook telemetry const hookTelemetryFound = await rig.waitForTelemetryEvent('hook_call'); @@ -663,8 +660,9 @@ fi`; }, }); - const prompt = 'Create a file called input-test.txt with content "test"'; - await rig.run(prompt); + await rig.run({ + args: 'Create a file called input-test.txt with content "test"', + }); // Hook should validate input format successfully const foundWriteFile = await rig.waitForToolCall('write_file'); @@ -739,11 +737,12 @@ fi`; }, }); - const prompt = - 'Create a file called multi-event-test.txt with content ' + - '"testing multiple events", and then please reply with ' + - 'everything I say just after this:"'; - const result = await rig.run(prompt); + const result = await rig.run({ + args: + 'Create a file called multi-event-test.txt with content ' + + '"testing multiple events", and then please reply with ' + + 'everything I say just after this:"', + }); // Should execute write_file tool const foundWriteFile = await rig.waitForToolCall('write_file'); @@ -834,9 +833,9 @@ fi`; }, }); - const prompt = - 'Create a file called error-test.txt with content "testing error handling"'; - await rig.run(prompt); + await rig.run({ + args: 'Create a file called error-test.txt with content "testing error handling"', + }); // Despite one hook failing, the working hook should still allow the operation const foundWriteFile = await rig.waitForToolCall('write_file'); @@ -883,8 +882,7 @@ fi`; }, }); - const prompt = 'Create a file called telemetry-test.txt'; - await rig.run(prompt); + await rig.run({ args: 'Create a file called telemetry-test.txt' }); // Should execute the tool const foundWriteFile = await rig.waitForToolCall('write_file'); @@ -929,8 +927,7 @@ fi`; }); // Run a simple query - the SessionStart hook will fire during app initialization - const prompt = 'Say hello'; - await rig.run(prompt); + await rig.run({ args: 'Say hello' }); // Verify hook executed with correct parameters const hookLogs = rig.readHookLogs(); @@ -1174,8 +1171,7 @@ fi`; }); // Run a simple query that will trigger automatic compression - const prompt = 'Say hello in exactly 5 words'; - await rig.run(prompt); + await rig.run({ args: 'Say hello in exactly 5 words' }); // Verify hook executed with correct parameters const hookLogs = rig.readHookLogs(); @@ -1236,8 +1232,7 @@ fi`; }); // Run in non-interactive mode with a simple prompt - const prompt = 'Hello'; - await rig.run(prompt); + await rig.run({ args: 'Hello' }); // The process should exit gracefully, firing the SessionEnd hook // Wait for telemetry to be written to disk @@ -1344,9 +1339,9 @@ echo '{"decision": "block", "systemMessage": "Disabled hook should not execute", }, }); - const prompt = - 'Create a file called disabled-test.txt with content "test"'; - const result = await rig.run(prompt); + const result = await rig.run({ + args: 'Create a file called disabled-test.txt with content "test"', + }); // Tool should execute (enabled hook allows it) const foundWriteFile = await rig.waitForToolCall('write_file'); @@ -1431,8 +1426,9 @@ echo '{"decision": "block", "systemMessage": "Disabled hook should not execute", ); // First run - only active hook should execute - const prompt1 = 'Create a file called first-run.txt with "test1"'; - const result1 = await rig.run(prompt1); + const result1 = await rig.run({ + args: 'Create a file called first-run.txt with "test1"', + }); // Tool should execute (active hook allows it) const foundWriteFile1 = await rig.waitForToolCall('write_file'); @@ -1455,8 +1451,9 @@ echo '{"decision": "block", "systemMessage": "Disabled hook should not execute", expect(disabledHookLog1).toBeUndefined(); // Second run - verify disabled hook stays disabled - const prompt2 = 'Create a file called second-run.txt with "test2"'; - const result2 = await rig.run(prompt2); + const result2 = await rig.run({ + args: 'Create a file called second-run.txt with "test2"', + }); const foundWriteFile2 = await rig.waitForToolCall('write_file'); expect(foundWriteFile2).toBeTruthy(); diff --git a/integration-tests/json-output.test.ts b/integration-tests/json-output.test.ts index 1892cf67a3..7d364d8c6c 100644 --- a/integration-tests/json-output.test.ts +++ b/integration-tests/json-output.test.ts @@ -22,11 +22,9 @@ describe('JSON output', () => { }); it('should return a valid JSON with response and stats', async () => { - const result = await rig.run( - 'What is the capital of France?', - '--output-format', - 'json', - ); + const result = await rig.run({ + args: ['What is the capital of France?', '--output-format', 'json'], + }); const parsed = JSON.parse(result); expect(parsed).toHaveProperty('response'); @@ -38,7 +36,9 @@ describe('JSON output', () => { }); it('should return a valid JSON with a session ID', async () => { - const result = await rig.run('Hello', '--output-format', 'json'); + const result = await rig.run({ + args: ['Hello', '--output-format', 'json'], + }); const parsed = JSON.parse(result); expect(parsed).toHaveProperty('session_id'); @@ -58,7 +58,7 @@ describe('JSON output', () => { let thrown: Error | undefined; try { - await rig.run('Hello', '--output-format', 'json'); + await rig.run({ args: ['Hello', '--output-format', 'json'] }); expect.fail('Expected process to exit with error'); } catch (e) { thrown = e as Error; @@ -108,12 +108,14 @@ describe('JSON output', () => { 'json-output.error.responses', ), }); - const result = await rig.run( - `Read the contents of ${rig.testDir}/path/to/nonexistent/file.txt and tell me what it says. ` + - 'On error, respond to the user with exactly the text "File not found".', - '--output-format', - 'json', - ); + const result = await rig.run({ + args: [ + `Read the contents of ${rig.testDir}/path/to/nonexistent/file.txt and tell me what it says. ` + + 'On error, respond to the user with exactly the text "File not found".', + '--output-format', + 'json', + ], + }); const parsed = JSON.parse(result); diff --git a/integration-tests/list_directory.test.ts b/integration-tests/list_directory.test.ts index c3827e4bf4..2a9b34fee1 100644 --- a/integration-tests/list_directory.test.ts +++ b/integration-tests/list_directory.test.ts @@ -45,7 +45,7 @@ describe('list_directory', () => { const prompt = `Can you list the files in the current directory.`; - const result = await rig.run(prompt); + const result = await rig.run({ args: prompt }); try { await rig.expectToolCallSuccess(['list_directory']); diff --git a/integration-tests/mixed-input-crash.test.ts b/integration-tests/mixed-input-crash.test.ts index 76a0bb99e7..2f862e8a48 100644 --- a/integration-tests/mixed-input-crash.test.ts +++ b/integration-tests/mixed-input-crash.test.ts @@ -23,12 +23,10 @@ describe('mixed input crash prevention', () => { const stdinContent = "say '1'."; try { - await rig.run( - { stdin: stdinContent }, - '--prompt-interactive', - "say '2'.", - "say '3'.", - ); + await rig.run({ + args: ['--prompt-interactive', "say '2'.", "say '3'."], + stdin: stdinContent, + }); throw new Error('Expected the command to fail, but it succeeded'); } catch (error: unknown) { expect(error).toBeInstanceOf(Error); @@ -50,11 +48,10 @@ describe('mixed input crash prevention', () => { rig.setup('should provide clear error message for mixed input'); try { - await rig.run( - { stdin: 'test input' }, - '--prompt-interactive', - 'test prompt', - ); + await rig.run({ + args: ['--prompt-interactive', 'test prompt'], + stdin: 'test input', + }); throw new Error('Expected the command to fail, but it succeeded'); } catch (error: unknown) { expect(error).toBeInstanceOf(Error); diff --git a/integration-tests/read_many_files.test.ts b/integration-tests/read_many_files.test.ts index 223f12e298..cd1c096f65 100644 --- a/integration-tests/read_many_files.test.ts +++ b/integration-tests/read_many_files.test.ts @@ -25,7 +25,7 @@ describe('read_many_files', () => { const prompt = `Use the read_many_files tool to read the contents of file1.txt and file2.txt and then print the contents of each file.`; - const result = await rig.run(prompt); + const result = await rig.run({ args: prompt }); // Check for either read_many_files or multiple read_file calls const allTools = rig.readToolLogs(); diff --git a/integration-tests/replace.test.ts b/integration-tests/replace.test.ts index 587bc21dd7..9bafa67d11 100644 --- a/integration-tests/replace.test.ts +++ b/integration-tests/replace.test.ts @@ -26,7 +26,9 @@ describe('replace', () => { rig.createFile(fileName, originalContent); - await rig.run(`Replace 'foo' with 'bar' in the file 'file_to_replace.txt'`); + await rig.run({ + args: `Replace 'foo' with 'bar' in the file 'file_to_replace.txt'`, + }); const foundToolCall = await rig.waitForToolCall('replace'); expect(foundToolCall, 'Expected to find a replace tool call').toBeTruthy(); @@ -46,9 +48,9 @@ describe('replace', () => { rig.createFile(fileName, originalContent); - await rig.run( - "Open regex.yml and append ' # updated' after the line containing ^[sv]d[a-z]$ without breaking the $ character.", - ); + await rig.run({ + args: "Open regex.yml and append ' # updated' after the line containing ^[sv]d[a-z]$ without breaking the $ character.", + }); const foundToolCall = await rig.waitForToolCall('replace'); expect(foundToolCall, 'Expected to find a replace tool call').toBeTruthy(); @@ -68,7 +70,7 @@ describe('replace', () => { rig.createFile(fileName, originalContent); const prompt = `In ${fileName}, replace "" with:\n${newBlock}. Use unix style line endings.`; - await rig.run(prompt); + await rig.run({ args: prompt }); const foundToolCall = await rig.waitForToolCall('replace'); expect(foundToolCall, 'Expected to find a replace tool call').toBeTruthy(); @@ -87,9 +89,9 @@ describe('replace', () => { const expectedContent = 'Hello\nWorld'; rig.createFile(fileName, originalContent); - await rig.run( - `In ${fileName}, delete the entire block from "## DELETE THIS ##" to "## END DELETE ##" including the markers and the newline that follows it.`, - ); + await rig.run({ + args: `In ${fileName}, delete the entire block from "## DELETE THIS ##" to "## END DELETE ##" including the markers and the newline that follows it.`, + }); const foundToolCall = await rig.waitForToolCall('replace'); expect(foundToolCall, 'Expected to find a replace tool call').toBeTruthy(); diff --git a/integration-tests/run_shell_command.test.ts b/integration-tests/run_shell_command.test.ts index 9508656f2e..9ac0cf0533 100644 --- a/integration-tests/run_shell_command.test.ts +++ b/integration-tests/run_shell_command.test.ts @@ -98,7 +98,7 @@ describe('run_shell_command', () => { const prompt = `Please run the command "echo hello-world" and show me the output`; - const result = await rig.run(prompt); + const result = await rig.run({ args: prompt }); const foundToolCall = await rig.waitForToolCall('run_shell_command'); @@ -161,13 +161,11 @@ describe('run_shell_command', () => { const prompt = `use ${command} to tell me how many lines there are in ${testFile}`; // Provide the prompt via stdin to simulate non-interactive mode - const result = await rig.run( - { - stdin: prompt, - yolo: false, - }, - `--allowed-tools=run_shell_command(${tool})`, - ); + const result = await rig.run({ + args: [`--allowed-tools=run_shell_command(${tool})`], + stdin: prompt, + yolo: false, + }); const foundToolCall = await rig.waitForToolCall('run_shell_command', 15000); @@ -206,13 +204,11 @@ describe('run_shell_command', () => { const { command } = getLineCountCommand(); const prompt = `use ${command} to tell me how many lines there are in ${testFile}`; - const result = await rig.run( - { - stdin: prompt, - yolo: false, - }, - '--allowed-tools=run_shell_command', - ); + const result = await rig.run({ + args: '--allowed-tools=run_shell_command', + stdin: prompt, + yolo: false, + }); const foundToolCall = await rig.waitForToolCall('run_shell_command', 15000); @@ -245,7 +241,7 @@ describe('run_shell_command', () => { const prompt = `use ${command} to tell me how many lines there are in ${testFile}`; const result = await rig.run({ - prompt: prompt, + args: prompt, yolo: true, }); @@ -277,13 +273,11 @@ describe('run_shell_command', () => { const { tool, command } = getLineCountCommand(); const prompt = `use ${command} to tell me how many lines there are in ${testFile}`; - const result = await rig.run( - { - stdin: prompt, - yolo: false, - }, - `--allowed-tools=ShellTool(${tool})`, - ); + const result = await rig.run({ + args: `--allowed-tools=ShellTool(${tool})`, + stdin: prompt, + yolo: false, + }); const foundToolCall = await rig.waitForToolCall('run_shell_command', 15000); @@ -325,14 +319,14 @@ describe('run_shell_command', () => { `use both ${command} and ls to count the number of lines in files in this ` + `directory. Do not pipe these commands into each other, run them separately.`; - const result = await rig.run( - { - stdin: prompt, - yolo: false, - }, - `--allowed-tools=run_shell_command(${tool})`, - '--allowed-tools=run_shell_command(ls)', - ); + const result = await rig.run({ + args: [ + `--allowed-tools=run_shell_command(${tool})`, + '--allowed-tools=run_shell_command(ls)', + ], + stdin: prompt, + yolo: false, + }); for (const expected in ['ls', tool]) { const foundToolCall = await rig.waitForToolCall( @@ -380,13 +374,11 @@ describe('run_shell_command', () => { `If the command fails because it is not permitted, respond with the single word FAIL. ` + `If it succeeds, respond with SUCCESS.`; - const result = await rig.run( - { - stdin: prompt, - yolo: false, - }, - `--allowed-tools=run_shell_command(${allowedCommand})`, - ); + const result = await rig.run({ + args: `--allowed-tools=run_shell_command(${allowedCommand})`, + stdin: prompt, + yolo: false, + }); if (!result.toLowerCase().includes('fail')) { printDebugInfo(rig, result, { @@ -443,13 +435,11 @@ describe('run_shell_command', () => { const chained = getChainedEchoCommand(); const shellInjection = `!{${chained.command}}`; - await rig.run( - { - stdin: `${shellInjection}\n`, - yolo: false, - }, - `--allowed-tools=ShellTool(${chained.allowPattern})`, - ); + await rig.run({ + args: `--allowed-tools=ShellTool(${chained.allowPattern})`, + stdin: `${shellInjection}\n`, + yolo: false, + }); // CLI should refuse to execute the chained command without scheduling run_shell_command. const toolLogs = rig @@ -474,14 +464,14 @@ describe('run_shell_command', () => { const { tool } = getLineCountCommand(); const prompt = `Please run the command "echo test-allow-all" and show me the output`; - const result = await rig.run( - { - stdin: prompt, - yolo: false, - }, - `--allowed-tools=run_shell_command(${tool})`, - '--allowed-tools=run_shell_command', - ); + const result = await rig.run({ + args: [ + `--allowed-tools=run_shell_command(${tool})`, + '--allowed-tools=run_shell_command', + ], + stdin: prompt, + yolo: false, + }); const foundToolCall = await rig.waitForToolCall('run_shell_command', 15000); @@ -523,7 +513,7 @@ describe('run_shell_command', () => { try { const prompt = `Use echo to learn the value of the environment variable named ${varName} and tell me what it is.`; - const result = await rig.run(prompt); + const result = await rig.run({ args: prompt }); const foundToolCall = await rig.waitForToolCall('run_shell_command'); @@ -551,7 +541,7 @@ describe('run_shell_command', () => { rig.createFile(fileName, 'test content'); const prompt = `Run a shell command to list the files in the current directory and tell me what they are.`; - const result = await rig.run(prompt); + const result = await rig.run({ args: prompt }); const foundToolCall = await rig.waitForToolCall('run_shell_command'); @@ -577,9 +567,9 @@ describe('run_shell_command', () => { settings: { tools: { core: ['run_shell_command'] } }, }); const invalidCommand = getInvalidCommand(); - const result = await rig.run( - `I am testing the error handling of the run_shell_command tool. Please attempt to run the following command, which I know has invalid syntax: \`${invalidCommand}\`. If the command fails as expected, please return the word FAIL, otherwise return the word SUCCESS.`, - ); + const result = await rig.run({ + args: `I am testing the error handling of the run_shell_command tool. Please attempt to run the following command, which I know has invalid syntax: \`${invalidCommand}\`. If the command fails as expected, please return the word FAIL, otherwise return the word SUCCESS.`, + }); expect(result).toContain('FAIL'); const escapedInvalidCommand = JSON.stringify(invalidCommand).slice(1, -1); diff --git a/integration-tests/save_memory.test.ts b/integration-tests/save_memory.test.ts index 6c0a310b58..38b4d060fa 100644 --- a/integration-tests/save_memory.test.ts +++ b/integration-tests/save_memory.test.ts @@ -24,7 +24,7 @@ describe('save_memory', () => { const prompt = `remember that my favorite color is blue. what is my favorite color? tell me that and surround it with $ symbol`; - const result = await rig.run(prompt); + const result = await rig.run({ args: prompt }); const foundToolCall = await rig.waitForToolCall('save_memory'); diff --git a/integration-tests/simple-mcp-server.test.ts b/integration-tests/simple-mcp-server.test.ts index 456b2910b1..1de8007810 100644 --- a/integration-tests/simple-mcp-server.test.ts +++ b/integration-tests/simple-mcp-server.test.ts @@ -218,9 +218,9 @@ describe('simple-mcp-server', () => { // Test directory is already set up in before hook // Just run the command - MCP server config is in settings.json - const output = await rig.run( - 'Use the `add` tool to calculate 5+10 and output only the resulting number.', - ); + const output = await rig.run({ + args: 'Use the `add` tool to calculate 5+10 and output only the resulting number.', + }); const foundToolCall = await rig.waitForToolCall('add'); diff --git a/integration-tests/stdin-context.test.ts b/integration-tests/stdin-context.test.ts index 7319d8cc2d..41d1e7772b 100644 --- a/integration-tests/stdin-context.test.ts +++ b/integration-tests/stdin-context.test.ts @@ -23,7 +23,7 @@ describe.skip('stdin context', () => { const stdinContent = `When I ask you for a token respond with ${randomString}`; const prompt = 'Can I please have a token?'; - const result = await rig.run({ prompt, stdin: stdinContent }); + const result = await rig.run({ args: prompt, stdin: stdinContent }); await rig.waitForTelemetryEvent('api_request'); const lastRequest = rig.readLastApiRequest(); diff --git a/integration-tests/telemetry.test.ts b/integration-tests/telemetry.test.ts index 6b6ce18234..1ecfb51a0d 100644 --- a/integration-tests/telemetry.test.ts +++ b/integration-tests/telemetry.test.ts @@ -20,7 +20,7 @@ describe('telemetry', () => { rig.setup('should emit a metric and a log event'); // Run a simple command that should trigger telemetry - await rig.run('just saying hi'); + await rig.run({ args: 'just saying hi' }); // Verify that a user_prompt event was logged const hasUserPromptEvent = await rig.waitForTelemetryEvent('user_prompt'); diff --git a/integration-tests/test-helper.ts b/integration-tests/test-helper.ts index fa9098a7f0..7ff1aac4ad 100644 --- a/integration-tests/test-helper.ts +++ b/integration-tests/test-helper.ts @@ -18,6 +18,7 @@ import * as os from 'node:os'; import { GEMINI_DIR } from '../packages/core/src/utils/paths.js'; const __dirname = dirname(fileURLToPath(import.meta.url)); +const BUNDLE_PATH = join(__dirname, '..', 'bundle/gemini.js'); // Get timeout based on environment function getDefaultTimeout() { @@ -266,8 +267,7 @@ export class InteractiveRun { } export class TestRig { - bundlePath: string; - testDir: string | null; + testDir: string | null = null; testName?: string; _lastRunStdout?: string; // Path to the copied fake responses file for this test. @@ -276,11 +276,6 @@ export class TestRig { originalFakeResponsesPath?: string; private _interactiveRuns: InteractiveRun[] = []; - constructor() { - this.bundlePath = join(__dirname, '..', 'bundle/gemini.js'); - this.testDir = null; - } - setup( testName: string, options: { @@ -370,7 +365,7 @@ export class TestRig { const command = isNpmReleaseTest ? 'gemini' : 'node'; const initialArgs = isNpmReleaseTest ? extraInitialArgs - : [this.bundlePath, ...extraInitialArgs]; + : [BUNDLE_PATH, ...extraInitialArgs]; if (this.fakeResponsesPath) { if (process.env['REGENERATE_MODEL_GOLDENS'] === 'true') { initialArgs.push('--record-responses', this.fakeResponsesPath); @@ -381,19 +376,13 @@ export class TestRig { return { command, initialArgs }; } - run( - promptOrOptions: - | string - | { - prompt?: string; - stdin?: string; - stdinDoesNotEnd?: boolean; - yolo?: boolean; - }, - ...args: string[] - ): Promise { - const yolo = - typeof promptOrOptions === 'string' || promptOrOptions.yolo !== false; + run(options: { + args?: string | string[]; + stdin?: string; + stdinDoesNotEnd?: boolean; + yolo?: boolean; + }): Promise { + const yolo = options.yolo !== false; const { command, initialArgs } = this._getCommandAndArgs( yolo ? ['--yolo'] : [], ); @@ -407,21 +396,17 @@ export class TestRig { encoding: 'utf-8', }; - if (typeof promptOrOptions === 'string') { - commandArgs.push(promptOrOptions); - } else if ( - typeof promptOrOptions === 'object' && - promptOrOptions !== null - ) { - if (promptOrOptions.prompt) { - commandArgs.push(promptOrOptions.prompt); - } - if (promptOrOptions.stdin) { - execOptions.input = promptOrOptions.stdin; + if (options.args) { + if (Array.isArray(options.args)) { + commandArgs.push(...options.args); + } else { + commandArgs.push(options.args); } } - commandArgs.push(...args); + if (options.stdin) { + execOptions.input = options.stdin; + } const child = spawn(command, commandArgs, { cwd: this.testDir!, @@ -437,10 +422,7 @@ export class TestRig { child.stdin!.write(execOptions.input); } - if ( - typeof promptOrOptions === 'object' && - !promptOrOptions.stdinDoesNotEnd - ) { + if (!options.stdinDoesNotEnd) { child.stdin!.end(); } @@ -1032,26 +1014,23 @@ export class TestRig { return null; } - async runInteractive( - options?: { yolo?: boolean } | string, - ...args: string[] - ): Promise { - // Handle backward compatibility: if first param is a string, treat as arg - let yolo = true; // Default to YOLO mode - let additionalArgs: string[] = args; - - if (typeof options === 'string') { - // Old-style call: runInteractive('--debug') - additionalArgs = [options, ...args]; - } else if (typeof options === 'object' && options !== null) { - // New-style call: runInteractive({ yolo: false }) - yolo = options.yolo !== false; - } - + async runInteractive(options?: { + args?: string | string[]; + yolo?: boolean; + }): Promise { + const yolo = options?.yolo !== false; const { command, initialArgs } = this._getCommandAndArgs( yolo ? ['--yolo'] : [], ); - const commandArgs = [...initialArgs, ...additionalArgs]; + const commandArgs = [...initialArgs]; + + if (options?.args) { + if (Array.isArray(options.args)) { + commandArgs.push(...options.args); + } else { + commandArgs.push(options.args); + } + } const ptyOptions: pty.IPtyForkOptions = { name: 'xterm-color', diff --git a/integration-tests/utf-bom-encoding.test.ts b/integration-tests/utf-bom-encoding.test.ts index a46952dd79..5ecc1e53c7 100644 --- a/integration-tests/utf-bom-encoding.test.ts +++ b/integration-tests/utf-bom-encoding.test.ts @@ -66,7 +66,7 @@ describe('BOM end-to-end integraion', () => { ) { writeFileSync(join(rig.testDir!, filename), content); const prompt = `read the file ${filename} and output its exact contents`; - const output = await rig.run(prompt); + const output = await rig.run({ args: prompt }); await rig.waitForToolCall('read_file'); const lower = output.toLowerCase(); if (expectedText === null) { @@ -126,7 +126,7 @@ describe('BOM end-to-end integraion', () => { const filename = 'gemini-screenshot.png'; writeFileSync(join(rig.testDir!, filename), imageContent); const prompt = `What is shown in the image ${filename}?`; - const output = await rig.run(prompt); + const output = await rig.run({ args: prompt }); await rig.waitForToolCall('read_file'); const lower = output.toLowerCase(); // The response is non-deterministic, so we just check for some diff --git a/integration-tests/write_file.test.ts b/integration-tests/write_file.test.ts index 3c6bdcd047..209f098add 100644 --- a/integration-tests/write_file.test.ts +++ b/integration-tests/write_file.test.ts @@ -27,7 +27,7 @@ describe('write_file', () => { }); const prompt = `show me an example of using the write tool. put a dad joke in dad.txt`; - const result = await rig.run(prompt); + const result = await rig.run({ args: prompt }); const foundToolCall = await rig.waitForToolCall('write_file');