Cucumber-js: add BeforeStep / AfterStep hooks

Created on 4 Jan 2018  ·  33Comments  ·  Source: cucumber/cucumber-js

Useful for validations after every step ends. this should be the world instance

Most helpful comment

Hi All,

Any update on Step hooks? Or any work around for running some code before and/or after each step execution?

All 33 comments

@charlierudolph I would like to help here, but need some pointer on the appropriate way implement it. I believe there was syntactic sugar AfterStep for registerHandler which was removed recently. I looked at support_code_library_builder/define_helpers.js. But need some pointers on how to implement these hooks.
thanks
Ali
P.S. Thanks for reverting the result json format.

A question here though is how does this effect the workflow? Can this edit the step result status or does it act as another step that can pass / fail?

The use case that I have seen in one of the comments and which I also want to use is to create a screenshot after the step. In cucumber ruby I have used the AfterStep which provides access to the Scenario object.
IMHO the afterstep hook should only be used for use cases where user want to introspect the step result but should not be able to change the result. I also think that it should not another step which can pass/fail.

@charlierudolph I'm looking for a similar solution as well.
Before the registerHandler became deprecated, i used this code to take screenshot after failed steps.:

```
this.registerHandler('StepResult', function (event, callback) {
var stepResult = event.getPayloadItem('stepResult');

if (stepResult.getStatus() == 'failed') {
  takeScreenshot()
    .then(function () {
      callback();
    });
} else {
  callback();
}});

````

Now I don't have solution for this.

Hi,

I have seen in most threads i read regarding BeforeStep/AfterStep hook that the use-case is taking a printscreen. This is not my use-case and I just want to voice other use cases for these hooks:

My project have used this.AfterStep hook in cucumber 1.x for:

  • collecting data - such as all external links:
    element.all(by.css('a')).each(function(link) { link.getAttribute('href').then(function(href) { ... }); });

All external links are then tested in a separate test-suit.

  • Checking for element ID duplicates (purpose is to make sure all ID's are unique to comply with HTML standard and also makes creating tests easier)
  • Checking for script error's (AfterStep would set a variable for After hook to actually fail scenario).
  • Disregarding browser alerts. A few test-scenarios makes web-browser open alert window which we may want to disregard. This especially applies when there are form and input elements, browser will alert ("You have unsaved changes...")

Currently using Cucumber 4.0.0 and Protractor 4.0.14

Side-note: Our use cases did not work properly with this.AfterStep() in Cucumber 1.x.x because it was not designed to have this type of code in it and we saw problems with race-conditions. So we have upgraded to Cucumber 4.0.0 and disabled AfterStep logic until there is proper support for it.

Hi,

any updates regarding this before/after step hooks?
Is there any workaround for AfterStep hook? I would like to take a screenshot if the particular test had failed.

"attach" is not available for me because we have overridden the default World constructor https://github.com/cucumber/cucumber-js/blob/master/docs/support_files/world.md

Thnx

Hi @gajo4256,

I'm using cucumber 4.0.0 and this snippet:

After(function (scenario) {
  if (scenario.result.status === Status.FAILED) {
    const World = this;

    return browser.takeScreenshot().then(function (buffer) {
      return World.attach(buffer, 'image/png');
    });
  }});

This will take a screenshot after every failed scenario. ( It works for me, because with cucumber, whenever a step fail, the whole scenario will fail, so it is almost identical with "after step fail".

Hope it helps.

Hi @mracz,

thnx, I actually tried this (although after each step would it would be more suitable for me).
Since I have overridden the default World constructor, how can I have attach again available for me as it is in normal case?

Thnx

Hi @gajo4256,

This is what i have in my Custom world implementation:

const { setWorldConstructor } = require('cucumber');

function CustomWorld( { attach } ) {
  this.attach = attach;
}

setWorldConstructor(CustomWorld);

@mracz, I currently do this for each step:

    When('I do something', function () {
        return takeScreenshot(this, () => {
            return $(...).click();
        });
    });

Where the screenshot taking function is this:

export function takeScreenshot(world, stepToExecute: () => promise.Promise<any>): promise.Promise<any> {
    return stepToExecute().then(() => {
        return doTakeScreenshot(world);
    }).catch((err) => {
        return doTakeScreenshot(world).then(() => {
            throw err;
        });
    });
}

function doTakeScreenshot(world) {
    return browser.takeScreenshot().then((screenshot) => {
        world.attach(screenshot, 'image/png');
    }).catch((err) => {
        console.warn('Could not create screenshot', err);
    });
}

I may have been too defensive about exceptions, but I did my best that the extra code does not interfere with the real test results. Best I can do right now, a working AfterStep hook would make me add less boilerplate.

However, what the hook would probably not do is skipping screenshots when I'm making assertions that do not change the screen (thus the screenshot would be useless), e.g. Then some element is not shown. I guess an extendable world object could help out there.

Here is another use case for AfterStep hooks: Wait for peers to synchronise (using vector clocks or lamport timestamps). /cc @tooky @jbpros

Hello everyone.
I'm actually working on this issue.

We are looking for a way to take screenshot from all our different steps.
Right now, we are thinking about overriding StepDefinitions function from cucumber.

Don't know if it is the best possible way so please, don't hesitate to give your opinion about it !

For anyone struggling here's a way to do this with definition function wrapper: https://github.com/PeerioTechnologies/peerio-icebear/blob/dev/test/e2e/code/hooks.js#L28

Our main use case would be like others here: screenshots, but using it as more of a debugging tool so that we can see the output of each step if we turn on debugging mode in our configuration.

Another use: we have a few modals that may appear after certain lengths of time on our website. If we run through a scenario, we would want to have checks in place for those modals being on the page after every step to ensure our tests aren't fragile because of these modals.

Another use case: if someone wanted to create a reporting tool complete with dashboard (currently running test statuses, test cases that have been previously ran, etc), cucumber could post to the tool in the step hooks for an update on progress. It's an unusual example, I know, but it's something that I'm interested in looking into now that I've thought about it.

KyleFairns, I need AfterStep for dashboard as you mentioned

Hello,

We want to check if there is any javascript error after each step. Not only the failed steps.
(Bit the same as @markus-lundin-86)
Now we can only do that after each scenario.
So is this on the road map, or has anyone has other solutions?

I just discovered that WebDriverIO has beforeStep and afterStep hooks for cucumber which solves my problem.

Hope that helps...

Hi All,

Any update on Step hooks? Or any work around for running some code before and/or after each step execution?

Hi all,
In the same situation as @Prasant-Sutaria.
Any update on step hooks or workaround?
Thanks in advance.

No updates. Still waiting for someone to submit a pull request for this.

Is there any roadmap or anything to this? As this is one major painpoint to have this feature, maybe an official statement would be nice.

@aslakhellesoy is there a checklist or something what a pull-request needs to implement? AFAIK #1058 and #1121 try to bring this feature, or some ways to workaround.

Hey guys,
I just created a PR regarding this issue: https://github.com/cucumber/cucumber-js/pull/1198.
Let me know if you find it useful.

@aslakhellesoy, I've created the above PR (#1198) to address this issue/feature request. Can you please take a look at it, or point me to someone I should contact?
cc: @charlierudolph

any updates? looking forward to have it as well :)

I see 2 PRs @leonardonelson91
I think they didn't find the best way to implement this feature
https://github.com/cucumber/cucumber-js/pull/1198
https://github.com/cucumber/cucumber-js/pull/1058

@charlierudolph do you have a view on whether the functions registered against BeforeStep and AfterStep should still be run if the step times out?

Like a few others here, I'm using setDefinitionFunctionWrapper to achieve the screenshots thing, which works great except I have no way in for when test steps time out - the best I can do is provide a shorter timeout to the browser instrumentation so it will throw whilst the step is still active. I am hoping to work on a fix for setDefinitionFunctionWrapper but wanted to know what the intent was here too.

I would expect that BeforeStep / AfterStep will run no matter what regardless of whether a step passes / fails (due to a timeout or otherwise)

Just to add an additional use case to this which is not about screenshots. I am testing an event driven system and the tests cause events to be generated. Those events are then read and create changes to the system.

The steps which follow validate the system is in the expected state which requires all events to have been processed. I would like the ability to ensure the queue has been fully processed and there is nothing in pending state before moving to the next step.

Currently I am doing some polling of the event stream in validation steps, but it would be nice to just put it into a hook. As it is a ubiquitous requirement that the system is stable state before going to next step.

@davidjgoss @charlierudolph Please can you help me with a sample example code of setDefinitionFunctionWrapper for to achieve the screenshots thing BeforeStep/AfterStep?, I am trying with Nightwatch JS

Hi @RArkasali here's a snippet from a project I work on:

import {setDefinitionFunctionWrapper} from "cucumber";

setDefinitionFunctionWrapper(function(fn) {
    return async function(...args) {
        try {
            return await fn.apply(this, args);
        } catch (ex) {
            await this.takeScreenshot();
            throw ex;
        }
    };
});

(Where takeScreenshot is a method on your custom World that does the actual screenshot-taking stuff. I'm not familiar enough with nightwatch to know what that looks like but I'm sure you will be.)

So this will take a screenshot if there is an error (like an assertion failure) from within the step function. The fact that we return the result of a non-error one is important - I was confused for a while while a step with return "pending" wasn't being handled, until I realised I was swallowing the return value.

Hope this helps

Hi all,
what is the status of this issue? Does it still needs help?
I am interested in BeforeStep and AfterStep, because it would help me to have a "log" file with all the step names and additional log information. It is a bit easier than creation of custom formatter.

This has been added as apart of https://github.com/cucumber/cucumber-js/pull/1416

Closing this issues since the hooks have been added in https://github.com/cucumber/cucumber-js/pull/1416

Was this page helpful?
0 / 5 - 0 ratings