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.
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()
});
ℹ️ Added in v10.1.0
BeforeAll
/AfterAll
hooks aren't given a World instance bound to this
like other hooks and steps. But they can access World parameters via this.parameters
in order to:
- Use the parameters as configuration to drive automation
- Update the parameters with extra context which will then be available to other hooks and steps
Here's a fictional example of obtaining an auth token that can then be used by all tests:
const {AfterAll, BeforeAll} = require('@cucumber/cucumber');
BeforeAll(async function () {
this.parameters.accessToken = await getAccessToken(this.parameters.oauth)
});
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();
}
});