diff --git a/src/run.test.ts b/src/run.test.ts index 472c265..cc25e31 100644 --- a/src/run.test.ts +++ b/src/run.test.ts @@ -62,6 +62,19 @@ describe("runFile", () => { } }) + test("strips ANSI color codes from output", async () => { + const file = makeFile([ + { command: `printf '\\033[31mred\\033[0m and \\033[1;32mbold green\\033[0m'` }, + ]) + const result = await runFile(file, defaultOpts) + try { + expect(result.results[0]?.actual).toEqual(["red and bold green"]) + expect(result.results[0]?.exitCode).toBe(0) + } finally { + await cleanupTmpDir(result.tmpDir) + } + }) + test("background process output does not leak into subsequent commands", async () => { const file = makeFile([ // Start a background process that writes to stdout after a delay diff --git a/src/run.ts b/src/run.ts index a1da05a..74a61dd 100644 --- a/src/run.ts +++ b/src/run.ts @@ -145,6 +145,13 @@ function parseSentinelOutput( return { outputs, exitCodes } } +// eslint-disable-next-line no-control-regex +const ANSI_REGEX = /[\u001b\u009b][\[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g + +function stripAnsi(line: string): string { + return line.replace(ANSI_REGEX, "") +} + function trimTrailingEmpty(lines: string[]): string[] { let end = lines.length while (end > 0 && lines[end - 1] === "") end-- @@ -253,7 +260,7 @@ export async function runFile( const results: CommandResult[] = file.commands.map((cmd, i) => ({ command: cmd, - actual: outputs[i] ?? [], + actual: (outputs[i] ?? []).map(stripAnsi), exitCode: exitCodes[i] ?? 1, }))