Last active
May 25, 2021 10:17
-
-
Save jbpros/8414fc60f4fd072c12f3 to your computer and use it in GitHub Desktop.
Cucumber.js step definition transforms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# features/my.feature | |
Feature: | |
Scenario: cukes | |
Given I have 10 cucumbers in my BaG | |
Given I don't have 20 cucumbers in my bAg | |
Given I have 98775655 cucumbers in my bag |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// features/step_definitions/stepdefs.js | |
var transform = require('./support/transform.js'); | |
module.exports = function () { | |
this.Transform(/^(\d+)$/, function (matches) { return parseInt(matches[0]); }); | |
this.Transform(/^(have|don't have)$/, function (matches) { return matches[0] == 'have'; }); | |
this.Transform(/^([bB][aA][gG])$/, function () { return 'bag'; }); | |
this.Given(/^I (have|don't have) (\d+) cucumbers in my (.*)$/, function (has, count, where) { | |
console.log('Given...', has, typeof count, where) | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// features/support/transform.js | |
var transforms = []; | |
function cast(value) { | |
for (var i = 0; i < transforms.length; i++) { | |
var transform = transforms[i]; | |
var matches = transform.pattern.exec(value); | |
if (matches) { | |
return transform.fn(matches); | |
} | |
} | |
return value; | |
} | |
function t(fn) { | |
var args = []; | |
var body = 'var args = [];'; | |
for (var i = 0; i < fn.length; i++) { | |
args.push('arg' + i); | |
body += 'args.push(this.cast(arg' + i + '));\n'; | |
} | |
body += 'return this.fn.apply(this, args);'; | |
var transformedFn = Function.apply(null, args.concat([body])).bind({fn: fn, cast: cast}); | |
return transformedFn; | |
} | |
module.exports = function () { | |
var _defineStep = this.defineStep; | |
this.defineStep = function (pattern, fn) { | |
_defineStep(pattern, t(fn)); | |
}; | |
this.Given = this.When = this.Then = this.defineStep; | |
this.Transform = function (pattern, fn) { | |
transforms.push({ pattern: pattern, fn: fn }); | |
}; | |
} |
I'm trying to implement this, but I keep getting an error which states: Error: TypeError: this.Transform is not a function.
Feature file:
Feature:
Scenario: cukes
Given i have 6 of one
Step file:
let transform = require('./support/transform.js');
module.exports = function () {
this.Transform(/^(\d+)$/, function (matches) {
return parseInt(matches[0]);
});
this.Given(/^i have (\d+) of one$/, function (arg) {
console.log(arg)
});
};
transform.js
let transforms = [];
function cast(value) {
for (let i = 0; i < transforms.length; i++) {
let transform = transforms[i];
let matches = transform.pattern.exec(value);
if (matches) {
return transform.fn(matches);
}
}
return value;
}
function t(fn) {
return function() {
return fn.apply(this, _.reduce(arguments, function(memo, arg) {
return memo.concat(cast(arg));
}, []));
};
}
module.exports = function () {
let _defineStep = this.defineStep;
this.defineStep = function (pattern, fn) {
_defineStep(pattern, t(fn));
};
this.Given = this.When = this.Then = this.defineStep;
this.Transform = function (pattern, fn) {
transforms.push({ pattern: pattern, fn: fn });
};
}
@robsquires - your solution was quite close, but you should do something like that:
Function.apply(null, args.concat([body])).bind(Object.assign({}, new this.World(), {fn: fn, cast: cast})
And just make sure that t
function is called with the same scope from exported function. For example using ES6 you can do something like that:
this.defineStep = (pattern, fn) => {
_defineStep(pattern, t.call(this, fn));
};
@pittgoose I also had same issue as you and to fix it I required transforms inside module.exports
function, i.e.:
module.exports = function () {
require('./support/transform').call(this);
this.Transform(/^(\d+)$/, function (matches) {
return parseInt(matches[0], 10);
});
}
I know maybe it's late for you guys, but I got exactly same problem, so I would like to help others that will fall into same issues here.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi there,
@robsquires you're right, the function loses the
World
context that cucumber associates to the callback ofGivens
,Thens
... In order to make things work, I've changed a little bit thet
function (I'm using lodash, but it is easy to adapt it to normal js). This way, the function doesn't lose context and everything keeps working as usual:Hope this helps,
Kind regards.