-
-
Save jbpros/8414fc60f4fd072c12f3 to your computer and use it in GitHub Desktop.
# 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 |
// 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) | |
}); | |
} |
// 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 }); | |
}; | |
} |
Hi there,
@robsquires you're right, the function loses the World
context that cucumber associates to the callback of Givens
, Thens
... In order to make things work, I've changed a little bit the t
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:
function t(fn) {
return function() {
return fn.apply(this, _.reduce(arguments, function(memo, arg) {
return memo.concat(cast(arg));
}, []));
};
}
Hope this helps,
Kind regards.
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.
Really helpful, thats for posting this 👍
I'm experiencing a bit of a strange error within my step definition callbacks...
this
is now scoped to{fn: fn, cast: cast}
, so anything I've set inWorld
is now longer accessible. I've had a little play but can't quite work out where I'm going wrong. I've tried:Function.apply(null, args.concat([body])).bind(Object.assign(World, {fn: fn, cast: cast})
, but I think this is not the World I am looking for.I'm putting the snippet in
/support/transform.js
Any thoughts?