|
1 | 1 | import assert from 'node:assert/strict'; |
| 2 | +import fs from 'node:fs'; |
| 3 | +import path from 'node:path'; |
2 | 4 | import { test } from 'vitest'; |
3 | 5 | import { AppError } from '@agent-device/kernel/errors'; |
4 | | -import { withCapturedStderrAsync } from '@agent-device/test-kit'; |
| 6 | +import { mkdtempForTestSync, withCapturedStderrAsync } from '@agent-device/test-kit'; |
5 | 7 | import { printHumanError } from './failure-output.ts'; |
6 | 8 |
|
7 | 9 | test('printHumanError writes a body-less failure as its one summary line', async () => { |
@@ -32,3 +34,58 @@ test('printHumanError closes a multi-line failure with the same summary line', a |
32 | 34 | 'Error (COMMAND_FAILED): boom. May have reached the device. Next: Run snapshot to check the screen before you retry. Read the diagnostics log for the failing step.', |
33 | 35 | ]); |
34 | 36 | }); |
| 37 | + |
| 38 | +test.each(['.', '..'])( |
| 39 | + 'printHumanError preserves the command failure for invalid remote session %s', |
| 40 | + async (session) => { |
| 41 | + const stateDir = mkdtempForTestSync('failure-output-invalid-record-'); |
| 42 | + const outside = path.join( |
| 43 | + stateDir, |
| 44 | + ...(session === '.' ? ['remote-diagnostics'] : []), |
| 45 | + 'requests', |
| 46 | + 'abc123.ndjson', |
| 47 | + ); |
| 48 | + fs.mkdirSync(path.dirname(outside), { recursive: true }); |
| 49 | + fs.writeFileSync(outside, 'private outside record'); |
| 50 | + const stderr = await withCapturedStderrAsync(async () => { |
| 51 | + await printHumanError(new AppError('COMMAND_FAILED', 'Original command failed'), { |
| 52 | + debugTier: true, |
| 53 | + logTail: { |
| 54 | + daemonBaseUrl: 'https://remote.example.test', |
| 55 | + daemonPaths: { baseDir: stateDir, logPath: path.join(stateDir, 'daemon.log') }, |
| 56 | + record: { session, requestId: 'abc123' }, |
| 57 | + }, |
| 58 | + }); |
| 59 | + }); |
| 60 | + assert.ok(stderr.startsWith('Error (COMMAND_FAILED): Original command failed')); |
| 61 | + assert.equal(stderr.includes('private outside record'), false); |
| 62 | + assert.equal(stderr.includes('[remote diagnostics]'), false); |
| 63 | + }, |
| 64 | +); |
| 65 | + |
| 66 | +test.each(['local', 'remote'] as const)( |
| 67 | + 'printHumanError includes available %s diagnostics', |
| 68 | + async (source) => { |
| 69 | + const stateDir = mkdtempForTestSync('failure-output-valid-record-'); |
| 70 | + const logPath = path.join(stateDir, 'daemon.log'); |
| 71 | + const recordPath = |
| 72 | + source === 'local' |
| 73 | + ? logPath |
| 74 | + : path.join(stateDir, 'remote-diagnostics', 'valid-session', 'requests', 'abc123.ndjson'); |
| 75 | + fs.mkdirSync(path.dirname(recordPath), { recursive: true }); |
| 76 | + fs.writeFileSync(recordPath, 'original failure evidence\n'); |
| 77 | + const stderr = await withCapturedStderrAsync(async () => { |
| 78 | + await printHumanError(new AppError('COMMAND_FAILED', 'Original command failed'), { |
| 79 | + debugTier: true, |
| 80 | + logTail: { |
| 81 | + daemonBaseUrl: source === 'remote' ? 'https://remote.example.test' : undefined, |
| 82 | + daemonPaths: { baseDir: stateDir, logPath }, |
| 83 | + record: { session: 'valid-session', requestId: 'abc123' }, |
| 84 | + }, |
| 85 | + }); |
| 86 | + }); |
| 87 | + assert.ok(stderr.startsWith('Error (COMMAND_FAILED): Original command failed')); |
| 88 | + assert.ok(stderr.includes(`[${source === 'local' ? 'daemon log' : 'remote diagnostics'}]`)); |
| 89 | + assert.ok(stderr.includes('original failure evidence')); |
| 90 | + }, |
| 91 | +); |
0 commit comments