diff --git a/index.js b/index.js index 0610a581cc..a64dce3d68 100644 --- a/index.js +++ b/index.js @@ -316,6 +316,10 @@ module.exports = (command, args, options) => { spawned.then = (onfulfilled, onrejected) => handlePromise().then(onfulfilled, onrejected); spawned.catch = onrejected => handlePromise().catch(onrejected); + // eslint-disable-next-line no-use-extend-native/no-use-extend-native + if (Promise.prototype.finally) { + spawned.finally = onfinally => handlePromise().finally(onfinally); + } return spawned; }; diff --git a/test.js b/test.js index 05ad533cc5..1c11ada3b6 100644 --- a/test.js +++ b/test.js @@ -519,3 +519,39 @@ test('removes exit handler on exit', async t => { const included = ee.listeners('exit').includes(listener); t.false(included); }); + +// eslint-disable-next-line no-use-extend-native/no-use-extend-native +if (Promise.prototype.finally) { + test('finally function is executed on success', async t => { + let called = false; + const {stdout} = await m('noop', ['foo']).finally(() => { + called = true; + }); + t.is(called, true); + t.is(stdout, 'foo'); + }); + + test('finally function is executed on failure', async t => { + let called = false; + const err = await t.throws(m('exit', ['2']).finally(() => { + called = true; + })); + t.is(called, true); + t.is(typeof err.stdout, 'string'); + t.is(typeof err.stderr, 'string'); + }); + + test('throw in finally function bubbles up on success', async t => { + const result = await t.throws(m('noop', ['foo']).finally(() => { + throw new Error('called'); + })); + t.is(result.message, 'called'); + }); + + test('throw in finally bubbles up on error', async t => { + const result = await t.throws(m('exit', ['2']).finally(() => { + throw new Error('called'); + })); + t.is(result.message, 'called'); + }); +}