diff --git a/lib/runner.js b/lib/runner.js index 18af02f7a..f54a9af7f 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -266,13 +266,11 @@ class Runner extends Emittery { return result; } - async runHooks(tasks, contextRef, titleSuffix) { + async runHooks(tasks, contextRef, testArgs = [], titleSuffix) { const hooks = tasks.map(task => new Runnable({ contextRef, failWithoutAssertions: false, - fn: task.args.length === 0 ? - task.implementation : - t => task.implementation.apply(null, [t].concat(task.args)), + fn: t => task.implementation.call(null, t, ...task.args, ...testArgs), compareTestSnapshot: this.boundCompareTestSnapshot, updateSnapshots: this.updateSnapshots, metadata: task.metadata, @@ -303,9 +301,14 @@ class Runner extends Emittery { async runTest(task, contextRef) { let hooksAndTestOk = false; - const hookSuffix = ` for ${task.title}`; - if (await this.runHooks(this.tasks.beforeEach, contextRef, hookSuffix)) { + let testArgs = task.args || []; + // Is it a macro? Then skip its args + if (task.implementation && task.implementation.title) { + testArgs = testArgs.slice(2); + } + + if (await this.runHooks(this.tasks.beforeEach, contextRef, testArgs, hookSuffix)) { // Only run the test if all `beforeEach` hooks passed. const test = new Runnable({ contextRef, @@ -328,7 +331,7 @@ class Runner extends Emittery { knownFailing: result.metadata.failing, logs: result.logs }); - hooksAndTestOk = await this.runHooks(this.tasks.afterEach, contextRef, hookSuffix); + hooksAndTestOk = await this.runHooks(this.tasks.afterEach, contextRef, testArgs, hookSuffix); } else { this.emit('stateChange', { type: 'test-failed', @@ -342,7 +345,7 @@ class Runner extends Emittery { } } - const alwaysOk = await this.runHooks(this.tasks.afterEachAlways, contextRef, hookSuffix); + const alwaysOk = await this.runHooks(this.tasks.afterEachAlways, contextRef, testArgs, hookSuffix); return hooksAndTestOk && alwaysOk; } diff --git a/test/runner.js b/test/runner.js index 1c1b1f63e..9b1c70488 100644 --- a/test/runner.js +++ b/test/runner.js @@ -592,6 +592,66 @@ test('macros: Additional args will be spread as additional args on implementatio }); }); +test('Test\'s additional args will be spread and passed down to beforeEach, afterEach implementation functions', t => { + t.plan(5); + + return promiseEnd(new Runner(), runner => { + runner.on('stateChange', evt => { + if (evt.type === 'test-passed') { + t.pass(); + } + }); + + runner.chain.beforeEach((a, ...rest) => { + t.deepEqual(rest, ['foo', 'bar']); + a.pass(); + }); + runner.chain.afterEach((a, ...rest) => { + t.deepEqual(rest, ['foo', 'bar']); + a.pass(); + }); + runner.chain.afterEach.always((a, ...rest) => { + t.deepEqual(rest, ['foo', 'bar']); + a.pass(); + }); + + runner.chain('test1', (a, ...rest) => { + t.deepEqual(rest, ['foo', 'bar']); + a.pass(); + }, 'foo', 'bar'); + }); +}); + +test('Test\'s additional args will be concatenated with args of beforeEach, afterEach args', t => { + t.plan(5); + + return promiseEnd(new Runner(), runner => { + runner.on('stateChange', evt => { + if (evt.type === 'test-passed') { + t.pass(); + } + }); + + runner.chain.beforeEach((a, ...rest) => { + t.deepEqual(rest, ['baz', 'foo', 'bar']); + a.pass(); + }, 'baz'); + runner.chain.afterEach((a, ...rest) => { + t.deepEqual(rest, ['baz', 'foo', 'bar']); + a.pass(); + }, 'baz'); + runner.chain.afterEach.always((a, ...rest) => { + t.deepEqual(rest, ['baz', 'foo', 'bar']); + a.pass(); + }, 'baz'); + + runner.chain('test1', (a, ...rest) => { + t.deepEqual(rest, ['foo', 'bar']); + a.pass(); + }, 'foo', 'bar'); + }); +}); + test('macros: Customize test names attaching a `title` function', t => { t.plan(6);