Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

To support hooks #25

Closed
jlin412 opened this issue Mar 9, 2018 · 34 comments
Closed

To support hooks #25

jlin412 opened this issue Mar 9, 2018 · 34 comments

Comments

@jlin412
Copy link

jlin412 commented Mar 9, 2018

hooks are not supported feature yet

@stevepkuo
Copy link

Is it possible to add a BeforeFeature hook? Such that whatever I specify in BeforeFeature will run before each feature file? (Such as clearing the test database)

@lgandecki
Copy link
Collaborator

@stevepkuo I don't think you shouldn be running things before feature itself, your scenario should be independent, and they should start with a clean state everytime. That's what you can use Background functionality for

@BenoitAverty
Copy link
Contributor

How would the hooks work ? Would they be defined in the feature files ? In the steps file ? (but then the question is, where are they placed).

I'd be happy to attempt a PR but I'm not sure how we want to design this.

@lgandecki
Copy link
Collaborator

I think we would probably want to design it to resemble the cucumberjs hooks:

https://github.com/cucumber/cucumber-js/blob/master/docs/support_files/hooks.md

So, in step definitions.
I’m not sure what are the rules for how the before would work - do we make them work on file basis?

A good attempt might be to install cucumberjs and play with their functionality and then try to reflect it here.

The beforeAll afterAll might be the easiest to start :-)

@BenoitAverty
Copy link
Contributor

It seems that the hooks are "global" in the sense that we can't restrict them to a specific feature or scenario (which is normal I think). I think it might be better to define them in their own support file or folder with a new configuration option, similar to the ste_definitions folder.

@lgandecki
Copy link
Collaborator

Yeah, I think that makes sense actually.
But that's more of a pattern. If someone wants they should be able to put those anywhere.

@jlin412
Copy link
Author

jlin412 commented Jun 20, 2018

actually, you can have tagged hook where you restrict hooks based on scope of tags

@victorheid
Copy link

What is the advised if i need to have my database reset after every scenario? The scenario is independent each time, but in my case I rely on an external service that needs to be reset

@lgandecki
Copy link
Collaborator

is background step not suitable for that?

@victorheid
Copy link

@lgandecki Although I forgot about the Background steps (thanks for remind myself!), I was trying to attach something like the beforeEach, to just wipe the api application after every Scenario.

It can be done through the Background steps as well I guess, just a preference if you want to have the api wipe/refresh as a step.

Do you have any opinion about this? Does CCP support Contexts BTW?

@andrei-ciocan
Copy link

andrei-ciocan commented Nov 2, 2018

  @before-hook1
  @before-hook2
  @after-hook3
  Scenario: Do Something
    Given I do something
    When I do something else
    Then something else should happen

Could we support adding those kind of hooks inside the .feature files? It would be really helpful controlling what you want to run and when, so you don't repeat unnecessarily a large amount of code when you have a chain of actions that reuses a certain feature. Inside step_definitions or hooks folder we could have the implementation.

@ludmilanesvitiy
Copy link

@lgandecki Hi! Global hooks should available for the next reasons:

  • global hook give the possibility to support DRY principle (when user want to do any interactions with his app before all or before each scenario/feature)
  • global hooks give the possibility to do any actions when any scenario have failed (like making screenshots or saving browser console logs anywhere)
  • global hooks give the possibility to make pre-post conditions through the API calls for saving time (it also could be in the background, but DRY will not be supported in that case).
    In cucumber all such functions were in the support/*.hooks.ts (or other) files. And it also could contain other settings for Cucumber, like setDefaultTimeout(N)

@alexttransisland
Copy link

I am also not sure about questions whether the hooks are needed or not. The cucumber is just a DSL wrapper of actual test. In usual (mocha/chai) DSL wrapper you have before/after hooks, same way it could work for cucumber DSL.
As cucumber usually used for defining plain-language or business language, it's strange to use technical steps like

Given I want to mock backend for this test if the record mode is set

I would rather decide

Before(() => {
  cy.route(...) if !Cypress.env('RECORD_MODE')
})

vs.

Given("I want to mock backend for this test if the record mode is set", () => {
  cy.route(...) if !Cypress.env('RECORD_MODE')
});

@lgandecki is there any hint when it could be a reality?

@kayvanbree
Copy link
Contributor

I agree with @alexttransisland that something technical has no place in the Cucumber syntax. My co-worker is trying to transform his tests to Cucumber style now. He has a login step and putting that as Given when I am logged in and on the page doesn't make any sense.

Is there anybody that has done some work towards this already?

@leksinteractive
Copy link

leksinteractive commented Nov 28, 2018

Yeah we're doing something similar as that logged in step @kayvanbree, but we've placed it in the Background section. How do other people handle this logged in requirement? Obviously placing it in the Background section means it will run before each scenario, but this causes so much redundant repetition. Also any ideas about achieving a global beforeAll and afterAll hook, for things like database seeding/clean up?

@kayvanbree
Copy link
Contributor

kayvanbree commented Nov 29, 2018

I did not know background was already supported. There's no docs for it. I created #116 for that.

Although I like the background section, but I would rather use it for simple feature-specific stuff, like navigating to the correct page. Seeding/resetting the database just doesn't belong in a feature file.

@lgandecki
Copy link
Collaborator

@leksinteractive what do you mean it creates redundant repetitions? Do you want to leak state between different scenarios? Could you show me an example?

@kayvanbree good catch. If you have a moment I'd appreciate a PR with the docs update.
Could you tell me how would you do seeding/resetting the db in a pure cucumber project? using hooks, based on tags? but that's sill in a feature file..

@alexttransisland
Copy link

@lgandecki the usual way to use cucumber in other languages is env file where you could do all the pre-setup needed. Something like env.js or cucumberEnv.js with

before(() => {
  dbHelper.connect('...')
  dbHelper.seed('...')
})

beforeEach(() => {
  if (Cypress.env('RECORD_MODE')) {
    cy.recordServerResponses()
    cy.recordRoutes()
  } else {
    cy.readRoutes(fixtureName)
  }

  cy.viewport('iphone-6')

  cy.visit('whatever')
})

afterEach(() => {
  dbHelper.cleaniseData() //remove test data generated by previous test but don't touch the seed
})

after(() => {
  if (Cypress.env('RECORD_MODE')) {
    cy.writeRecordedFixtures(fixtureName)
  }
})

and then in cucumber feature you just execute your test or do additional setup per requirements

@lgandecki
Copy link
Collaborator

@alexttransisland
I'm pretty sure you can do this with this package as well, have you tried?
https://docs.cypress.io/guides/core-concepts/writing-and-organizing-tests.html#Hooks

@alexttransisland
Copy link

@lgandecki Of course I can do this if we talk about mocha/chai, but here we talk about Cucumber DSL. And there is no way to do this for cucumber features. (run same hooks)

@lgandecki
Copy link
Collaborator

I still don't understand. Just put them in one of your step definitions files and they should work just fine :) I guess we could add a configurable file (like env.js) that would be imported automatically before all tests.
I personally prefer to create a js file and import it in the step definitions file that require a particular configuration (with before/after steps)

@lgandecki
Copy link
Collaborator

btw, this cucumber is not fully a cucumber, it does use mocha beneath, so you can use all the mocha hooks. Your scenario becomes an it() block, and your feature is describe() block.

@alexttransisland
Copy link

@lgandecki great. It simply worked
so actual beforeFeature() block becomes a simple before block for the file which contains first step for cucumber feature. 🤔
Thanks!

@lgandecki
Copy link
Collaborator

No problem.. Happy it worked!

@kayvanbree
Copy link
Contributor

kayvanbree commented Nov 30, 2018

@lgandecki @alexttransisland should it be documented that you can use the mocha hooks? That might be useful for newcomers.

(I created PR #117 fro the background section docs)

@leksinteractive
Copy link

leksinteractive commented Dec 1, 2018

I for one would love to see a small code example (or ideally proper documentation) of how we can use the cypress hooks within scenario steps and step definition files. Specifically i'm interested in hooks before/after each feature file, before/after the whole suite and a hook for after each scenario (as we already have the background section for before each scenario). Thanks!

@alexttransisland
Copy link

alexttransisland commented Dec 1, 2018

@leksinteractive There are no such hooks as far as I understand. So basically to use beforeAll() hook it should be written in the way

before(() => {
  ...
})

Given('this is first scenario step', () => {
  ...
})

to use beforeEach you could have same approach as ^ with background section, like

beforeEach(() => {
  ...
})

Given('this is background scenario step', () => {
  ...
})

to use after or afterEach

after(() => {
  ...
})

Then('this is the last scenario step', () => {
  ...
})
afterEach(() => {
  ...
})

Then('this is the last scenario step', () => {
  ...
})

According to @lgandecki current Cucumber preprocessor implementation is just a DSL which translates

Your scenario becomes an it() block, and your feature is describe() block.

meaning there should be additional codebase which supports beforeFeature or beforeScenario as these entities are not part of .js, but parts of .feature

Though my example supports any actions before/after particular step (considering you did proper files split, because it applies to all steps the hook is written for). That's not ideal, but somehow could solve issues for small amount and non-reused steps.

@lgandecki
Copy link
Collaborator

@kayvanbree yeah, I'm happy to extend the documentation. I'm a bit worried of duplicating information from either cucumberjs OR cypress - especially if they own the API. But I think this information is so basic that it's ok to have it here. If you would like to make another PR, or you @alexttransisland - you have a good intro here, that would be great.
I think the best doc would also discuss the advantages and disadvantages (or things that are currently not possible or difficult), as Alex was starting to define in the comment above.

@kayvanbree
Copy link
Contributor

@lgandecki I used the background section (added to readme) and not the hooks, so maybe @alexttransisland is better for the job.

About the redundant documentation: The best part of Cypress is that you can find anything about it in one place. You don't have to look up parts in your assertion libraries docs, and some in your test runners docs. The beforeEach and afterEach (after hooks should be avoided) are explained in Cypress' documentation, but I think people would expect hooks to be a supported feature of this plugin, but instead they need to use the standard Cypress way. If we don't document that, it might be confusing.

@darasandeep91
Copy link

darasandeep91 commented Jan 29, 2019

Hi @lgandecki

To make things clear, I have made few observations regarding the support for hooks.
can you correct those I am wrong.
I have created a hooks.js file in step_definitions folder and have placed the following code:

Here is my directory structure:

Cypress
      -Integrations
            -Folder 1
                 -step_definitions
                         -step_definitions1.js
                          - hooks.js
                  a.feature
            -Folder 2
                  -step_definitions
                         -step_definitions2.js
                   b.feature
before(() => {
    cy.log('I Run for each feature before all the scenarios');
});

beforeEach(() => {
    cy.log('I Run for each feature before Every Scenario');
});


afterEach(() => {
    cy.log('I Run for Each Feature After every Scenario');
});

after(() => {
    cy.log('I Run for Each Feature After all the scenarios');
}
 

Here are the observations:

  • Before block executed before all my scenario's [suppose if we select run all tests, it will be executed multiple times before all my tests start to run ]

  • BeforeEach block executed before each scenario

  • AfterEach block executed before each scenario

  • After block executed After all my scenario's

  • Even tough we placed hooks.js in Folder1, before, beforeEach, after, afterEach got executed when i am running b.feature

  • before, beforeEach, after, afterEach are global not limited to a feature

Missing functionality for hooks:

  • no way to restrict the hook to run only for a particular feature
  • no way to pass tags to hooks

@sanik-bajracharya
Copy link

sanik-bajracharya commented Feb 6, 2019

@darasandeep91 Make sure you have "nonGlobalStepDefinitions": true set in your package.json or .cypress-cucumber-preprocessorrc file. It disables global step definitions and uses the step definitions and before/after hooks based on the folder structure you've setup i.e Folder 1 and Folder 2.

Also be sure to remove "step_definitions": "cypress/integration/**/path/to/step_definitions" if you have it configured

@RMoroney
Copy link

RMoroney commented Feb 7, 2019

I am facing same issue as @darasandeep91 . Hooks are seem to be always global irrespective of any folder they are placed. @sanik-bajracharya I did the settings mentioned still hooks are global.

Scenario which are affected due to this in my case is:
I have multiple feature files - login.feature, cropping.feature, dashboard.feature. For login scenarios, I don't want user to login but for all other scenario I need user to login to application. Now as hooks are global I can't keep login step in before hook as it logs in for login.feature which fails all tests.

@lgandecki is there any way to make hooks non-global so that they are feature file specific (as this is something much need than global hooks ) which I might be missing how to do or we don't have support for this in Cypress yet?

Thanks in advance!

@lgandecki
Copy link
Collaborator

@ReemaMoroney @sanik-bajracharya this is exactly how it should be, and works, as in the example here: https://github.com/TheBrainFamily/cypress-cucumber-example . Please make a reproduction if it doesn't work for you.

There is one caveat which is running all features inside the GUI at the same time - cypress-io/cypress#3323 which is a bug in cypress. But if you run your tests with run or separately, the hooks should not be global.

lgandecki added a commit that referenced this issue Aug 21, 2019
feat: Added cucumber-js-style Before and After hooks.

Related: #25
@lgandecki
Copy link
Collaborator

🎉 This issue has been resolved in version 1.14.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests