diff --git a/integration-tests/hooks-system.test.ts b/integration-tests/hooks-system.test.ts index 265f77428a..48ded5df8b 100644 --- a/integration-tests/hooks-system.test.ts +++ b/integration-tests/hooks-system.test.ts @@ -87,7 +87,7 @@ describe('Hooks System Integration', () => { expect(hookTelemetryFound).toBeTruthy(); }); - it('should block tool execution and use stderr as reason when hook exits with code 2', async () => { + it.only('should block tool execution and use stderr as reason when hook exits with code 2', async () => { rig.setup( 'should block tool execution and use stderr as reason when hook exits with code 2', { @@ -103,6 +103,9 @@ describe('Hooks System Integration', () => { "process.stderr.write('File writing blocked by security policy'); process.exit(2);", ); + const normalizedCmd = normalizePath(`node "${scriptPath}"`); + console.log(`[Test] normalizedCmd: ${normalizedCmd}`); + rig.setup( 'should block tool execution and use stderr as reason when hook exits with code 2', { @@ -119,7 +122,7 @@ describe('Hooks System Integration', () => { { type: 'command', // Exit with code 2 and write reason to stderr - command: normalizePath(`node "${scriptPath}"`), + command: normalizedCmd!, timeout: 5000, }, ], @@ -1885,7 +1888,7 @@ console.log(JSON.stringify({decision: "block", systemMessage: "Disabled hook sho expect(disabledHookLog).toBeUndefined(); }); - it('should respect disabled hooks across multiple operations', async () => { + it.only('should respect disabled hooks across multiple operations', async () => { rig.setup('should respect disabled hooks across multiple operations', { fakeResponsesPath: join( import.meta.dirname, @@ -1910,7 +1913,7 @@ console.log(JSON.stringify({decision: "block", systemMessage: "Disabled hook sho settings: { hooksConfig: { enabled: true, - disabled: [`node "${disabledPath}"`], // Disable the second hook, + disabled: [normalizePath(`node "${disabledPath}"`)!], // Disable the second hook, }, hooks: { BeforeTool: [ diff --git a/packages/test-utils/src/test-rig.ts b/packages/test-utils/src/test-rig.ts index a6fdfda1a2..273c22d5ac 100644 --- a/packages/test-utils/src/test-rig.ts +++ b/packages/test-utils/src/test-rig.ts @@ -377,22 +377,35 @@ export class TestRig { if (!this._initialized) { // Clean up existing directories from previous runs (e.g. retries) - if (fs.existsSync(this.testDir)) { - if (env['VERBOSE'] === 'true' || env['CI'] === 'true') { - console.log( - `[TestRig] Cleaning up existing testDir: ${this.testDir}`, - ); + const cleanDir = (dir: string, name: string) => { + if (fs.existsSync(dir)) { + if (env['VERBOSE'] === 'true' || env['CI'] === 'true') { + console.log(`[TestRig] Cleaning up existing ${name}: ${dir}`); + } + for (let i = 0; i < 5; i++) { + try { + fs.rmSync(dir, { recursive: true, force: true }); + return; + } catch (err) { + if (i === 4) throw err; + if (env['VERBOSE'] === 'true' || env['CI'] === 'true') { + console.log( + `[TestRig] Failed to clean ${name} (attempt ${i + 1}): ${err}`, + ); + } + // Use timeout on windows, sleep on others + const sleepCmd = + process.platform === 'win32' ? 'timeout /t 1' : 'sleep 1'; + try { + execSync(sleepCmd); + } catch {} + } + } } - fs.rmSync(this.testDir, { recursive: true, force: true }); - } - if (fs.existsSync(this.homeDir)) { - if (env['VERBOSE'] === 'true' || env['CI'] === 'true') { - console.log( - `[TestRig] Cleaning up existing homeDir: ${this.homeDir}`, - ); - } - fs.rmSync(this.homeDir, { recursive: true, force: true }); - } + }; + + cleanDir(this.testDir, 'testDir'); + cleanDir(this.homeDir, 'homeDir'); this._initialized = true; } @@ -592,6 +605,11 @@ export class TestRig { }); this._spawnedProcesses.push(child); + if (env['VERBOSE'] === 'true' || env['CI'] === 'true') { + console.log(`[TestRig] Running: ${command} ${commandArgs.join(' ')}`); + console.log(`[TestRig] CWD: ${this.testDir}`); + } + let stdout = ''; let stderr = '';