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
Calling steps from step definitions #11
Comments
When this is implemented, bear in mind that we plan to deprecate everything other than |
Thank you Matt. -js will only support steps() then. I like it! |
Any progress on this? Seems like a pretty vital feature. |
This is not planned as part of the current milestone (0.3). It should be part of 0.4. |
@mattwynne I guess we want to support |
@jbpros I guess. Maybe you could start with I personally would be happy to use a Cucumber without this feature, I never use it and consider it to be bad practice. I always prefer to delegate to methods instead. Ultimately, if we're going to support this, I would prefer to see it implemented in Gherkin, so you have a way of defining a macro step that maps to a bunch of other low-level steps. Cucumber then just gets told to invoke the lower level ones and hardly needs to know there's any mapping going on. That would be my preference. |
TL;DR: Should we really add I totally agree with you Matt. Unfortunately, this is the most wanted feature right now on Cucumber.js. As I understand it, many people consider step definitions as methods or functions. The way I see it, they're mappings between some fluent language sentences and pieces of programming language code, nothing more. This has deep implications as to how we treat those beasts. From a programmer perspective, step definitions look just like methods though. I see it as a weakness in Cucumber_s_ today. Step definitions should not be exposed as an API but rather as an explicit translation map, a dictionary, so to speak. @msassak had interesting thoughts on this already and I think he did a great job re-modeling those "mappings" in Cucumber 2.0. I have to say I'm reluctant to work on this very issue in Cucumber.js right now. On the other hand I don't want to do feature retention just because of my personal tastes/opinions. |
👎 👎 👎 👎 👎 Calling steps from stepdefs is one of those features I wish I never added to Cucumber(-Ruby), because it provides so much rope for people to hang themselves with. It came to be because Ruby stepdefs use anonymous closures that you can't call from elsewhere (unless you go through hoops). With JavaScript it's a different situation; Step Definitions use first class functions! function x_is_something(x, cb) {
console.log('x', x);
cb();
}
Given(/x is (.*)/, x_is_something);
Given(/super x/, function(cb) {
x_is_something(97, cb);
}); |
|
I'm not sure I understand how I noticed you wrote since I have no way to trigger a scenario, did you mean step or is that intentionally scenario (in the latter case, I can see what you're trying to do, I think). You can still define users in a background and iterate over them in your Feature:
Background:
Given a valid user called Simon
And a valid user called Sarah
And a valid user called Johnny
Scenario Outline:
When each valid user sends a GET request to /search<query>
Then everyone's request response code is 400
And everyone's request response body starts with <body>
Examples:
| query | body |
| ?foo=1 | ... | And yes this means storing request responses in an array and iterating over them. Is it that bad? |
Well, if you have some flow (for example checkout flow) and you want to get to the final confirmation page, you can go through steps, defined (somewhere) in the step definitions. Invoking one single step is almost useless. I was thinking of porting all ruby's step(s) functionality here. But as my request closed, I would not spend time for it. Thanks. |
So sad this won't fix, as @cono says: invoking one single step is almost useles, real cases are more complex operations. This would be really helpful to create a few fine-grained scenarios and then the others scenarios repeating this operations. Specially when the steps are defined in more than one file, in that case function-reuse alternative is not quite easy nor clean. |
Hy! I've created a lib which does exactly what you are asking (call a step from another step), take a look here: https://github.com/hackhat/cucumberry |
@hackhat It looks really cool. I usually like sync portion of step definition. Is cucumber-pro only a plugin for cucumber.js? |
@jlin412 I don't really know how to call, but is like a helper for cucumber. Thanks for feedback |
@hackhat In order to create sync step, I will need to use syntax: this.addStep(...)? Will I need to use selenium-sync as well instead of protractor.js/webdriver.js? |
@jlin412 you can only use the sync plug-in, look at the docs how to do it. I'm on mobile so I can't give you the exact steps. If you can wait I will explain better around 23h30 Portugal hour. |
@hackhat please change the name of your project to something else. See hackhat/cucumberry#1 |
@aslakhellesoy Changed the name to https://github.com/hackhat/cucumberry |
@aslakhellesoy Then how to chain the step calls? Like following? function x_is_something(x, cb) {
console.log('x', x);
this.x = x;
cb();
}
function y_is_something(y, cb) {
console.log('y', y);
this.y = y;
cb();
}
Given(/super z/, function(cb) {
x_is_something(97, cb);
y_is_something(8, cb);
}); That doesn't work very well since And also, if step stores variable in the world context, it will end up each time call the function, we need to bind it like: Given(/super z/, function(cb) {
x_is_something.bind(this)(97, cb);
y_is_something.bind(this)(8, cb);
}); Anyone had solutions to these issues? |
You need to use async and use the parallel function. In this way you call On Thu, May 14, 2015, 00:15 Yun Jia notifications@github.com wrote:
|
+1, this should be part of the lib. What @mattwynne suggested (add a gherkin feature which supports code reusability):
What @aslakhellesoy suggested (extracting the duplicated code to js functions):
Calling steps from step definitions
I still don't understand why do we need another unnecessary abstraction level, do you have any explanation? |
@yunjia this is basic callback theory: Given(/super z/, function(cb) {
x_is_something(97, function () {
y_is_something(8, cb);
});
}); As for the binding issue, you should define those functions as methods on your World: function World(callback) {
this.x_is_something = function (x, callback) {
this.x = ...
};
this.y_is_something = function (y, callback) {
this.y = ...
};
callback(); // tell Cucumber we're finished and to use 'this' as the world instance
};
}
module.exports.World = World; Then in your step definitions: Given(/super z/, function(cb) {
var self = this;
self.x_is_something(97, function () {
self.y_is_something(8, cb);
});
}); Also, please note that synchronous step definitions are supported by Cucumber.js 0.5+: Given(/super z/, function() {
this.x_is_something(97);
this.y_is_something(8);
}); |
@Inf3rno step definitions are a thin translation layer between plain english and JS code. By allowing calling steps from steps, we make that layer fatter. Steps become coupled between each other, rendering them extremely difficult to maintain. It also encourages people to use Gherkin as a scripting language, which it is not at all. |
@Inf3rno if you want to reuse code in stepdefs, move the body of the stepdef to a regular javascript function and reuse that. |
Can you elaborate pls. I don't understand what is the connection, since step definitions are not in gherkin, only the text pattern what is similar. |
@Inf3rno if you can call steps from steps, you're jumping back again into "Gherkinland": the step names need to be parsed, matched against step definitions which can be executed. You're basically writing gherkin scripts within gherkin (they're hidden within JS step definitions, but that's a detail that makes it even worse from a maintenance POV). |
@aslakhellesoy @jbpros The idea is that steps should be an algebraic, composable type, which it's not. |
@jbpros, I am going to use your solution since I am used to programming in Java and not worrying about promises :) |
Did anyone ever come up with an extension to cucumber for defining steps in terms of other steps? Something like
Am pondering whether this is a useful extension to better describe long user journeys through the system and would prefer to work with any prior art. |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Allow calling steps from step definitions.
https://github.com/cucumber/cucumber/wiki/Calling-Steps-from-Step-Definitions
The text was updated successfully, but these errors were encountered: