diff --git a/src/shell.ts b/src/shell.ts index a8ff989..46efe5f 100644 --- a/src/shell.ts +++ b/src/shell.ts @@ -175,7 +175,17 @@ sh.mock = () => { throw new Error(`No mock found for command: ${command}`); } if (mock.exitCode !== 0) { - throw new Error(`Command failed: ${command}\n${mock.stderr}`); + const error = new Error(`Command failed: ${command}\n${mock.stderr}`); + Object.assign(error, { + cmd: command, + code: mock.exitCode, + stdout: mock.stdout, + stderr: mock.stderr, + // not mocked but included for completeness + killed: false, + signal: null, + }); + throw error; } return { stdout: mock.stdout, stderr: mock.stderr }; }; diff --git a/tests/shell.spec.ts b/tests/shell.spec.ts index 2bf0a41..9296bb9 100644 --- a/tests/shell.spec.ts +++ b/tests/shell.spec.ts @@ -21,7 +21,15 @@ describe('sh', () => { }); it('should throw if the command fails', async () => { - await expect(sh('false')).to.eventually.be.rejected; + const promise = sh('echo "output" && echo "errors" >&2 && false'); + await expect(promise).to.eventually.be.rejectedWith( + 'Command failed: echo "output" && echo "errors" >&2 && false\nerrors', + ).and.to.include({ + cmd: 'echo "output" && echo "errors" >&2 && false', + code: 1, + stdout: 'output\n', + stderr: 'errors\n', + }); }); describe('options.trim', () => { @@ -114,7 +122,12 @@ describe('sh mock mode', () => { await expect(sh('fail')).to.eventually.be.rejectedWith( 'Command failed: fail\nsomething went wrong', - ); + ).and.to.include({ + cmd: 'fail', + code: 1, + stdout: 'here is some output', + stderr: 'something went wrong', + }); }); }); @@ -168,7 +181,12 @@ describe('sh mock mode', () => { await expect(sh('fail')).to.eventually.be.rejectedWith( 'Command failed: fail\nsomething went wrong', - ); + ).and.to.include({ + cmd: 'fail', + code: 1, + stdout: 'here is some output', + stderr: 'something went wrong', + }); }); });