Hooks are used for setup and teardown the environment before and after each scenario. See the API reference for the specification of the first argument passed to hooks. Multiple Before hooks are executed in the order that they were defined. Multiple After hooks are executed in the reverse order that they were defined.
Note that your hook functions cannot reference the world as this
if you use
arrow functions. See FAQ for details.
const {After, Before} = require('@cucumber/cucumber');
// Synchronous
Before(function () {
this.count = 0;
});
// Asynchronous Callback
Before(function (testCase, callback) {
var world = this;
tmp.dir({unsafeCleanup: true}, function(error, dir) {
if (error) {
callback(error);
} else {
world.tmpDir = dir;
callback();
}
});
});
// Asynchronous Promise
After(function () {
// Assuming this.driver is a selenium webdriver
return this.driver.quit();
});
ℹ️ Added in v8.1.0
Hooks can optionally be named:
const {Before} = require('@cucumber/cucumber');
Before({name: "Set up some test state"}, function () {
// do stuff here
});
Such hooks will then be referenced by name in formatter output, which can be useful to help you understand what's happening with your tests.
Hooks can be conditionally selected for execution based on the tags of the scenario.
const {After, Before} = require('@cucumber/cucumber');
Before(function () {
// This hook will be executed before all scenarios
});
Before({tags: "@foo"}, function () {
// This hook will be executed before scenarios tagged with @foo
});
Before({tags: "@foo and @bar"}, function () {
// This hook will be executed before scenarios tagged with @foo and @bar
});
Before({tags: "@foo or @bar"}, function () {
// This hook will be executed before scenarios tagged with @foo or @bar
});
// You can use the following shorthand when only specifying tags
Before("@foo", function () {
// This hook will be executed before scenarios tagged with @foo
});
See more documentation on tag expressions
If you need to imperatively skip a test using a Before
hook, this can be done using any of the constructs defined in skipped steps
This includes using: a synchronous return, an asynchronous callback, or an asynchronous promise
// Synchronous
Before(function() {
// perform some runtime check to decide whether to skip the proceeding scenario
return 'skipped'
});
If you have some setup / teardown that needs to be done before or after all scenarios, use BeforeAll
/ AfterAll
. Like hooks and steps, these can be synchronous, accept a callback, or return a promise.
Unlike Before
/ After
these methods will not have a world instance as this
. This is because each scenario gets its own world instance and these hooks run before / after all scenarios.
const {AfterAll, BeforeAll} = require('@cucumber/cucumber');
// Synchronous
BeforeAll(function () {
// perform some shared setup
});
// Asynchronous Callback
BeforeAll(function (callback) {
// perform some shared setup
// execute the callback (optionally passing an error when done)
});
// Asynchronous Promise
AfterAll(function () {
// perform some shared teardown
return Promise.resolve()
});
If you have some code execution that needs to be done before or after all steps, use BeforeStep
/ AfterStep
. Like the Before
/ After
hooks, these also have a world instance as 'this', and can be conditionally selected for execution based on the tags of the scenario.
const {AfterStep, BeforeStep} = require('@cucumber/cucumber');
BeforeStep({tags: "@foo"}, function () {
// This hook will be executed before all steps in a scenario with tag @foo
});
AfterStep( function ({result}) {
// This hook will be executed after all steps, and take a screenshot on step failure
if (result.status === Status.FAILED) {
this.driver.takeScreenshot();
}
});