Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Added support for string-based matchers for step definitions. #48

Closed
wants to merge 3 commits into from

2 participants

@tdekoning

Format example:

  • 'I increment the variable by %d'
  • 'I enter %s into firstname and %s into lastname'

Regexp support in step-definitions are still working as they should.

Ted de Koning Added support for string-based matchers for step definitions.
Format example:
 - 'I increment the variable by %d'
 - 'I enter %s into firstname and %s into lastname'
8447f57
@jbpros
Owner

Thanks for the pull request, Ted.

Cucumber-ruby supplies a similar syntax:

'I increment the variable by $value'

This feature is definitely missing in Cucumber.js, as many people have reticences using regexps (to say the least!).

However, I'd rather stick with the $ syntax. Two reasons for that:

  • Keep it consistent between Cucumber implementations;
  • Do not assume things regarding what is a number/string/whatever.

[^"]* is too restrictive as a any string matcher. A more reasonable one would be [^\s]* or something similar. Using quotes to surround a string is not mandatory, we can't just force that rule.

Also, I have the feeling %d could suggest there is some typecasting going on behind the scene.

What do you think?

@tdekoning

I'm not an expert on regular expressions, but i do agree with you about keeping the syntax the same as the ruby version of cucumber.

I think that matching for numbers/strings etc can be usefull in some situations where you build your logic for a certain datatype and when specs change, you know immediatly that your steps are being skipped because the parameter does not map to a single step.
However, on the other hand without typechecks you can see if your code works properly with other datatypes without having to add steps.

How does the ruby version of cucumber handle string-based matchers? Perhaps it is the best to keep the feature the same.

@jbpros
Owner

I think $-variables are simply matching any string of non-whitespace characters. Basically, it maps to ([^\s]*) or something, passing the captured string to the step definition and ignoring the actual variable name.

When one needs smarter step arguments, transforms are generally a nice way to go. It allows for both matching group reuse and typecasting.

NUMBER = Transform /^(\d+)$/ do |number|
  return number.to_i
end

Given /^I have #{NUMBER} cucumbers$/ do |cucumber_count|
  # cucumber_count is an integer, not a string
end

But of course, this is all based on regexps.

@tdekoning

I agree, the name in the $ should not mean anything (unless someone really wants it, like in your example).

Do you want me to rewrite the code so it can use $ANYTHING and replace that with ([^\s]*) or something?

@jbpros
Owner

Sure, that'd be a nice addition.

Ted de Koning Easyer string-based matchers using '$' prefixes.
Example:
 - 'I incremend the variable by $VAR1'
 - 'I enter $var into firstname and $var2 into lastname'
615dfaf
@tdekoning

I have added the simpler matcher that matches on parameters with a $.

Step usage:
Given('a variable set to $nummer2', function(number, callback) {
console.log('number: ', number);
callback();
});

Feature:
Scenario: easy maths
Given a variable set to 1
When I increment the variable by 1
Then the variable should contain 2

@jbpros
Owner

Great, thank you Ted.

I'm thinking it would be a good idea to introduce a "step definition pattern" that would encapsulate the string/regexp of the step definition.

Also we need some tests for this ;) Are you up to it?

@tdekoning

While a "step definition pattern" isn't a bad idea, perhaps that would overengineer it.

What kind of tests do you have in mind?

@jbpros
Owner

As soon as we're dealing with a "multi-type" variable, I smell a need for encapsulation. Additionally, I try to keep constructors a simple as possible. They're then easier to test and much less responsible for business logic.

Regarding the tests, there are both features and specs. Cucumber.js is passing the cucumber-tck feature suite entirely when run from both Cucumber-ruby and Cucumber.js in addition to a few features specific to it.

But again, I can help on this if you want.

@tdekoning

Okay. I would really appreciate the help, im not familiar with ruby and i dont know how to properly run those .tck spec tests.

@tdekoning

I have added a testfeature that now passes in the cucumber-tck suite (running npm test).

Rewriting the code should be safe now :).
I do not know how your vision is on the encapsulation but i will let you to decide how to implement that.

@tdekoning

Will you implement this feature in cucumber-js?

@jbpros
Owner

@tdekoning Don't worry, I will. I'm quite busy preparing my talks at CukeUp!, among other things.

I should be able to take care of it in ~two weeks or so. I'm sorry for this rather long delay.

Stay tuned!

@jbpros jbpros commented on the diff
README.md
@@ -34,6 +34,7 @@ Cucumber.js is still a work in progress. Here is its current status.
| [Undefined steps](https://github.com/cucumber/cucumber-tck/blob/master/undefined_steps.feature) | Done |
| [Wire protocol](https://github.com/cucumber/cucumber-tck/blob/master/wire_protocol.feature) | To do |
| [World](https://github.com/cucumber/cucumber-tck/blob/master/world.feature) | Done |
+| [String defined step definitions](https://github.com/cucumber/cucumber-tck/blob/master/stringdefined.feature) | Done |
@jbpros Owner
jbpros added a note

There is no such feature in cucumber-tck. Do you have it on your local repo?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jbpros jbpros commented on the diff
features/step_definitions/cucumber_steps.js
@@ -333,5 +353,9 @@ callback();\
this.assertExecutedNumberedScenarios(2, 3, 4);
callback();
});
+
+ Then('The string-defined scenario is finished', function(callback) {
+ callback();
@jbpros Owner
jbpros added a note

The step definitions you added are not doing anything apart from calling back. I think you are missing something here :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jbpros jbpros closed this pull request from a commit
@jbpros jbpros Add support for string-based step definition patterns (closes #48)
Thanks to Ted de Koning (@tdekoning) for the original pull request.
8aa8d9d
@jbpros jbpros closed this in 8aa8d9d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 12, 2012
  1. Added support for string-based matchers for step definitions.

    Ted de Koning authored
    Format example:
     - 'I increment the variable by %d'
     - 'I enter %s into firstname and %s into lastname'
  2. Easyer string-based matchers using '$' prefixes.

    Ted de Koning authored
    Example:
     - 'I incremend the variable by $VAR1'
     - 'I enter $var into firstname and $var2 into lastname'
Commits on Mar 15, 2012
  1. @tdekoning
This page is out of date. Refresh to see the latest.
View
1  README.md
@@ -34,6 +34,7 @@ Cucumber.js is still a work in progress. Here is its current status.
| [Undefined steps](https://github.com/cucumber/cucumber-tck/blob/master/undefined_steps.feature) | Done |
| [Wire protocol](https://github.com/cucumber/cucumber-tck/blob/master/wire_protocol.feature) | To do |
| [World](https://github.com/cucumber/cucumber-tck/blob/master/world.feature) | Done |
+| [String defined step definitions](https://github.com/cucumber/cucumber-tck/blob/master/stringdefined.feature) | Done |
@jbpros Owner
jbpros added a note

There is no such feature in cucumber-tck. Do you have it on your local repo?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
1. Not certified by [Cucumber TCK](https://github.com/cucumber/cucumber-tck) yet.
2. Considered for removal from [Cucumber TCK](https://github.com/cucumber/cucumber-tck).
View
24 features/step_definitions/cucumber_steps.js
@@ -156,6 +156,10 @@ setTimeout(callback.pending, 10);\
callback();
});
+ Given('a feature is defined with a string', function( callback ) {
+ callback();
+ });
+
When(/^Cucumber executes the scenario$/, function(callback) {
this.runFeature({}, callback);
});
@@ -219,6 +223,22 @@ callback();\
this.runFeature({tags: [tag1, '~' + tag2, '~' + tag3]}, callback);
});
+ When('Cucumber executes scenarios with parameter $param1 and $param2 are not equal in a string', function( param1, param2, callback ) {
+ if( param1 != param2 ) {
+ callback();
+ } else {
+ throw(new Error('Params were equal'));
+ }
+ });
+
+ When('Cucumber executes scenarios with parameter $param1 and $param2 are equal in a string', function( param1, param2, callback ) {
+ if( param1 == param2 ) {
+ callback();
+ } else {
+ throw(new Error('Params were equal'));
+ }
+ });
+
Then(/^the scenario passes$/, function(callback) {
this.assertPassedScenario();
callback();
@@ -333,5 +353,9 @@ callback();\
this.assertExecutedNumberedScenarios(2, 3, 4);
callback();
});
+
+ Then('The string-defined scenario is finished', function(callback) {
+ callback();
@jbpros Owner
jbpros added a note

The step definitions you added are not doing anything apart from calling back. I think you are missing something here :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ });
};
module.exports = cucumberSteps;
View
17 lib/cucumber/support_code/step_definition.js
@@ -1,6 +1,23 @@
var StepDefinition = function(regexp, code) {
var Cucumber = require('../../cucumber');
+ var constructor = function() {
+ // Converts a string to a proper regular expression
+ var parseRegexString = function( regexString ) {
+
+ // Replace the $VARIABLES with the correct regex.
+ regexString = regexString.replace(/\$[a-zA-Z0-9]+/g, '([^"]*)');
+ return new RegExp( regexString );
+ }
+
+ if( typeof(regexp)=='string' ) {
+ // regexp is a string, convert it to a regexp.
+ regexp = parseRegexString(regexp);
+ }
+ }
+
+ constructor();
+
var self = {
matchesStepName: function matchesStepName(stepName) {
return regexp.test(stepName);
Something went wrong with that request. Please try again.