Closed adamwood-novafori closed 8 months ago
Currently it is not supported. We should think about it.
From one hand, it could be an easy way for people to re-use code without defining extra helpers. Some examples are in https://github.com/badeball/cypress-cucumber-preprocessor/issues/170. It is also exists in official Cucumber-ruby package.
From the other, calling steps from steps is considered anti-pattern in Cucumber docs:
In Cucumber-js calling steps from step definitions is not supported; this is by design.
There are several discussions in Cucumber repo with reasonable concerns about steps nesting:
In fact, playwright-bdd already supports calling step from step when using decorators syntax:
export @Fixture('todoPage') class TodoPage {
constructor(public page: Page) { }
@When('I create todo {string}')
async createTodo(text: string) {
// ...
}
@When('I create 2 todos {string} and {string}')
async createTodos(text1: string, text2: string) {
await this.createTodo(text1);
await this.createTodo(text2);
}
I like this approach most of all, b/c it's very native and relies on the code, not step titles. Feel free to share your thoughts on that.
For the decorator approach can you have the decorators in the step files instead of the page objects? Then it would be very similar to SpecFlow in C# or cucumber java.
For the decorator approach can you have the decorators in the step files instead of the page objects? Then it would be very similar to SpecFlow in C# or cucumber java.
Current JavaScript syntax does not allow decorators on functions, there is a proposal for that, but not very active.
I thought more about it and have another idea: When creating step definitions we can return a function that can call this step. It allows to re-use the step without extracting a helper function and avoids dependency on step title. For example:
const createTodo = When('I create todo {string}', async ({}, text: string) => {
// ...
});
When('I create 2 todos {string} and {string}', async ({}, text1: string, text2: string) => {
await createTodo(text1);
await createTodo(text2);
});
What do you think?
Ah, I see!
That could be a nice option, would you still be able to pass fixtures through the parameters also?
would you still be able to pass fixtures through the parameters also?
I think no. Step implementation should have all needed fixtures inside, to be able to run the step in a usual way from gherkin. When some logic depends on fixtures, I guess it's a case for helper function.
Cool, I like that way it looks clean, can we do that now or would you have to make a change?
Will add this feature to the nearest release. Lets keep this issue open for that.
That could be a nice option, would you still be able to pass fixtures through the parameters also?
After deeper investigation I've realized that we need to pass fixtures as parameters when calling steps. Otherwise Playwright will not know from outer step that these fixtures should be created.
Here is the updated syntax of calling steps:
const createTodo = When('I create todo {string}', async ({ page, myFixture }, text: string) => {
// ...
});
When('I create 2 todos {string} and {string}', async ({ page, myFixture }, text1: string, text2: string) => {
await createTodo({ page, myFixture }, text1);
await createTodo({ page, myFixture }, text2);
});
Sweet! I had a feeling it would need that. Nice work!
Released in v6.1.0. See Call step from step in docs. Please re-check on your side and re-open in case of any issues.
Hey, is there a way to reuse steps within other steps like you can in cypress cucumber preprocessor?
https://github.com/badeball/cypress-cucumber-preprocessor/blob/master/docs/cucumber-basics.md#nested-steps