Skip to main content

Hooks

The following hooks are supported:

  • Before
  • After
  • setup
  • Teardown

Hooks can be defined in files with the following extensions, and should be located under the stepDefinitionsRoot

  • *.hooks.ts
  • *.before.ts
  • *.after.ts
  • *.setup.ts
  • *.teardown.ts

Setup

The setup hook is executed before any tests are run. It is useful for bootstrapping the environment. The setup call back recieves a special copy of the app which is shared between all Setup and TearDown calls but not tests or other hooks.

import { Setup } from "@autometa/runner";

Setup("Setup the services 'foo'", (app) => {
app.world.foo = 2;
});

Before

The before hook is executed before each test. It is useful for setting up the world in advance of a test, setting up data from the service or preparing data base entries.

Before recieves the same copy of the App that the test it preceeds will have.

import { Before } from "@autometa/runner";
import { setupFooObject } from "../objects";

Before("Setup the services 'foo'", (app) => {
return app.myHttpClient.post("/foo", setupFooObject);
});

After

The after hook is executed after each test. It is useful for cleaning up data from the service or database, or resetting the environment to a known state.

After recieves the same copy of the App that the test it succeeds will have.

import { After } from "@autometa/runner";

After("Reset the services 'foo'", (app) => {
return app.myHttpClient.delete("/foo", app.world.someId);
});

Teardown

The teardown hook is executed after all tests have run. It is useful for cleaning up the environment after all tests have run. It shares the same copy of the App as the Setup hook.

import { Teardown } from "@autometa/runner";

Teardown("Reset the services 'foo'", (app) => {
return app.myHttpClient.delete("/foo?type=testType");
});

Order Of Execution

Hooks are executed according to 2 orders:

The order in which the hooks files are loaded.

Hooks will be loaded in filesystem order. Consider the following directory, which will be in test/steps:

  test/steps
├── common.hooks.ts
├── cleanup.hooks.ts
├── products/
│ ├── products.hooks.ts

Hooks will be executed in the following file order:

  1. common.hooks.ts
  2. cleanup.hooks.ts
  3. products/products.hooks.ts

The order in which the hooks are defined in the file.

Hooks will be executed in the order they are defined in the file. Consider the following file:

// common.hooks.ts
import { Before, After } from "@autometa/runner";

Before("Setup the services 'foo'", (app) => {
return app.myHttpClient.post("/foo", setupFooObject);
});

Before("Setup the services 'bar'", (app) => {
return app.myHttpClient.post("/bar", setupBarObject);
});

The Setup the services 'foo' hook will be executed before the Setup the services 'bar' hook. So the first before hook that will be executed is Setup the services 'foo' and the second will be Setup the services 'bar, followed by the Before hooks in the next file and so on.

Grouped Hooks

available in version >0.5.8

Specific hooks exist for group types in Cucumber, such as Features, Rules, Scenario Outlines and Examples. Each grouping has a Before and After hook which can be filtered using cucumber tags.

Hook names:

  • BeforeFeature
  • AfterFeature
  • BeforeRule
  • AfterRule
  • BeforeScenarioOutline
  • AfterScenarioOutline
  • BeforeExamples
  • AfterExamples

Filtering

Hooks can be filtered using a cucumber expression, or a custom filter function which accepts a list of the current tests tags.

import { BeforeFeature } from "@autometa/runner";

BeforeFeature("Setup the services 'foo'", (app) => {
return app.myHttpClient.post("/foo", setupFooObject);
}).tagFilter("@foo and not @bar");

BeforeFeature("Setup the services 'bar'", (app) => {
return app.myHttpClient.post("/bar", setupBarObject);
}).customFilter((tags) => tags.includes("@bar=2"));

Note: CustomFilters take priority over TagFilters.

Ordering

By default, hooks are executed in file order, so files in a higher directory will be executed before files in a lower directory, while hooks in the same file will be executed in the order they are defined.

The default ordering can be overridden by setting the order property on the hook.

import { BeforeFeature } from "@autometa/runner";

BeforeFeature("Setup the services 'foo'", (app) => {
return app.myHttpClient.post("/foo", setupFooObject);
}).order(1);

By default, all hooks have an order of 5. Lower orders have higher priority. So an order of 1 will execute before the same hook type with an order of 5.

Timeouts

Hooks can have a timeout set on them, which will cause the hook to fail if it takes longer than the specified time to execute.

import { BeforeFeature } from "@autometa/runner";

BeforeFeature("Setup the services 'foo'", (app) => {
return app.myHttpClient.post("/foo", setupFooObject);
}).timeout(5000);

Timeouts can also be specified with a time unit:

import { BeforeFeature } from "@autometa/runner";

BeforeFeature("Setup the services 'foo'", (app) => {
return app.myHttpClient.post("/foo", setupFooObject);
}).timeout(5, 's');

Chaining

Options can be chained together to create a more complex hook.

import { BeforeFeature } from "@autometa/runner";

BeforeFeature("Setup the services 'foo'", (app) => {
return app.myHttpClient.post("/foo", setupFooObject);
}).tagFilter("@foo and not @bar")
.order(1)
.timeout(5000);