How to pass integer values in cucumber test and verify the result - javascript

How do I call a simple addition function and assert the result of two values using selenium-cucumber-js framework with a test written below. While running the below it says
TypeError: TypeError: Cannot read property 'addvalues' of undefined
at createWorld.When (C:\Tests\cucumber\step-definitions\addvalues-steps.js:5:25)
Feature:
Scenario: Addition of two values
When Add two values 5 and 10
Then I should get result 15
// Here is my 'addvalues-steps.js' file
const expect = require('chai').expect;
module.exports = function () {
this.When(/^Add two values (-?\d+) and (-?\d+)$/, (x, y) =>{
this.page.addvalues.addValues(x,y);
})
this.Then(/^I should get result (-?\d+)$/, (ans) =>{
let tot = this.page.addvalues.addValues(x, y);
expect(tot).to.be.eql(ans);
})
};
// Following is my 'addvalues.js file'
module.exports = {
addValues(x,y){
var total = x + y ;
return total ;
}
};
// world.js >>
const { CustomWorld } = require('cucumber')
function CustomWorld() {
console.log('overriding the world')
this.page = {
addvalues: require('../page-objects/addvalues')
}
console.log("This is the recent error log:"+this.page.addvalues)
}
module.exports = function() {
this.World = CustomWorld;

Note: the below example is for an old version of cucumber-js: 1.3.3.
With cucumber.js, when you're referencing this from inside step definitions, you're actually referencing the World context. So, for this.page.addvalues.addValues(x,y); to work properly, you'll first need to create page that has a reference to your addvalues.js. Something along these lines:
world.js:
function CustomWorld() {
console.log('overriding the world')
this.page = {
addvalues: require('../page-objects/addvalues')
}
}
module.exports = function() {
this.World = CustomWorld;
};
addvalues.js:
//addvalues.js
module.exports = {
addValues(x,y){
var total = x + y ;
return total ;
}
};
There's also a couple of things to correct in your steps.js.
Don't pass arrow functions into the steps, as this will remove the this context that you're setting in World.js.
If you want to share variables between steps (as you do in your example), you need to store them somewhere. One such place, again, would be the World context. Note how in my version I set this.prevResult
When the variables are injected into your steps, they are injected as strings. Note the parseInt() in my version.
addvalues-steps.js:
const expect = require('chai').expect;
module.exports = function() {
this.When(/^Add two values (-?\d+) and (-?\d+)$/, function (x, y) {
this.prevResult = this.page.addvalues.addValues(parseInt(x, 10), parseInt(y, 10));
})
this.Then(/^I should get result (-?\d+)$/, function (ans) {
let tot = this.prevResult;
expect(tot).to.be.eql(parseInt(ans, 10));
})
}
UPD: It turns out that the question is about selenium-cucumber-js, which is a framework on top of cucumber-js. Disregard the comments about the world.js.
According to selenium-cucumber-js docs, you don't need this to access the page objects in your step definitions:
Page objects are accessible via a global page object and are
automatically loaded from ./page-objects.
const expect = require('chai').expect;
module.exports = function() {
this.When(/^Add two values (-?\d+) and (-?\d+)$/, function (x, y) {
this.prevResult = page.addvalues.addValues(parseInt(x, 10), parseInt(y, 10));
})
this.Then(/^I should get result (-?\d+)$/, function (ans) {
let tot = this.prevResult;
expect(tot).to.be.eql(parseInt(ans, 10));
})
}

Related

if can't access parameter in JavaScript module

Hi I'm having problems with the scope of an if in a JavaScript module.
Here is a mock up of my code :
module.exports = {
caser(nb){
if(0 === 0){
nb = 3+2
}
}
}
The function is called from another JavaScript file. Nb however doesn't change when I do this.
My editor (visual studio code) marked nb as unused. This I tried :
module.exports = {
caser(nb){
let number = nb
if(0 === 0){
number = 3+2
}
}
}
This still doesn't seem to alter the value of nb. Does anyone know a solution to this problem?
Thanks in advance.
Reassigning nb (or number) will only change what those variable names point to in the current function. It sounds like what you need to do is return the changed value, and have the consumer of the function use it to reassign the value it passes in. Something like:
// consumer file:
const { caser } = require('./foo');
let nb = 5;
nb = caser(nb);
module.exports = {
caser(nb) {
if (0 === 0) {
nb = 3 + 2
}
return nb;
}
}
The only way to avoid having to reassign in the consumer would be for the consumer to pass an object instead, and mutate the object.
// consumer file:
const { caser } = require('./foo');
const objToPass = { nb: 5 };
caser(objToPass);
module.exports = {
caser(objToPass) {
if (0 === 0) {
objToPass.nb = 3 + 2
}
}
}

Get line number with abstract syntax tree in node js

Im making a program that takes some code via parameter, and transform the code adding some console.logs to the code. This is the program:
const escodegen = require('escodegen');
const espree = require('espree');
const estraverse = require('estraverse');
function addLogging(code) {
const ast = espree.parse(code);
estraverse.traverse(ast, {
enter: function(node, parent) {
if (node.type === 'FunctionDeclaration' ||
node.type === 'FunctionExpression') {
addBeforeCode(node);
}
}
});
return escodegen.generate(ast);
}
function addBeforeCode(node) {
const name = node.id ? node.id.name : '<anonymous function>';
const beforeCode = "console.log('Entering " + name + "()');";
const beforeNodes = espree.parse(beforeCode).body;
node.body.body = beforeNodes.concat(node.body.body);
}
So if we pass this code to the function:
console.log(addLogging(`
function foo(a, b) {
var x = 'blah';
var y = (function () {
return 3;
})();
}
foo(1, 'wut', 3);
`));
This is the output of this program:
function foo(a, b) {
console.log('Entering foo()');
var x = 'blah';
var y = function () {
console.log('Entering <anonymous function>()');
return 3;
}();
}
foo(1, 'wut', 3);
And this is the AST (Abstract Syntax Tree) for that last function passed to addLoggin:
https://astexplorer.net/#/gist/b5826862c47dfb7dbb54cec15079b430/latest
So i wanted to add more information to the console logs like for example the line number we are on. As far as i know, in the ast, the node has a value caled 'start' and 'end' which indicates in which character that node starts and where it ends. How can i use this to get the line number we are on? Seems pretty confusing to me to be honest. I was thinking about doing a split of the file by "\n", so that way i have the total line numbers, but then how can i know i which one im on?
Thank you in advance.
Your idea is fine. First find the offsets in the original code where each line starts. Then compare the start index of the node with those collected indexes to determine the line number.
I will assume here that you want the reported line number to refer to the original code, not the code as it is returned by your function.
So from bottom up, make the following changes. First expect the line number as argument to addBeforeCode:
function addBeforeCode(node, lineNum) {
const name = node.id ? node.id.name : '<anonymous function>';
const beforeCode = `console.log("${lineNum}: Entering ${name}()");`;
const beforeNodes = espree.parse(beforeCode).body;
node.body.body = beforeNodes.concat(node.body.body);
}
Define a function to collect the offsets in the original code that correspond to the starts of the lines:
function getLineOffsets(str) {
const regex = /\r?\n/g;
const offsets = [0];
while (regex.exec(str)) offsets.push(regex.lastIndex);
offsets.push(str.length);
return offsets;
}
NB: If you have support for matchAll, then the above can be written a bit more concise.
Then use the above in your main function:
function addLogging(code) {
const lineStarts = getLineOffsets(code); // <---
let lineNum = 0; // <---
const ast = espree.parse(code);
estraverse.traverse(ast, {
enter: function(node, parent) {
if (node.type === 'FunctionDeclaration' ||
node.type === 'FunctionExpression') {
// Look for the corresponding line number in the source code:
while (lineStarts[lineNum] < node.body.body[0].start) lineNum++;
// Actually we now went one line too far, so pass one less:
addBeforeCode(node, lineNum-1);
}
}
});
return escodegen.generate(ast);
}
Unrelated to your question, but be aware that functions can be arrow functions, which have an expression syntax. So they would not have a block, and you would not be able to inject a console.log in the same way. You might want to make your code capable to deal with that, or alternatively, to skip over those.

Unit Testing JS - using JEST

Beginner Level - Unit Testing
Here's the function
export function toHex(number) {
const nstr = number.toString(16);
if (nstr.length % 2) {
return `0${nstr}`;
}
return nstr;
Able to figure out if the function is true or not by running the following Unit testing code:
// testing new function
describe('toHex', () => { //mocking the method
test('Testing Function toHex ', () => { // declaring the method
const str = 14 // initial value
const actual = toHex(str) // calculate the value
expect(actual).toMatchSnapshot(); // checking whether is true
})
});
Now how could I add different scenarios and make the following function to pass / Fail
Thanks

calling function within module that is imported to another class

I am new to JavaScript (working my way through some basic tutorials). Can someone tell me what I am doing wrong here? I am trying to get the run function to reference the withinCircle function, then export the whole thing to another file so I can reference the run function. Feel free to modify my code anyway you want- I tried to follow "best" practices but I may have screwed up. Thanks!
var roleGuard = {
/** #param {Creep} creep **/
run: function(creep)
{
var target = creep.pos.findClosestByRange(FIND_HOSTILE_CREEPS, {filter: { owner: { username: 'Invader' } }});
if(target!=null)
{
console.log(new RoomPosition(target.pos.x,target.pos.y,'sim'));
//ranged attack here
//within 3, but further than 1
if(creep.pos.getRangeTo(target)<=3&&creep.pos.getRangeTo(target)>1)
{
creep.rangedAttack(target);
console.log("ranged attacking");
}
}
else
{
var pp=withinCircle(creep,target,3,'sim');
console.log(pp);
creep.moveTo(pp);
}
}
//------------------------------------------------------------
//move to closest point within z units of given evenmy
withinCircle: function(creep,target,z,room)
{
var targets = [new RoomPosition(target.pos.x-z,target.pos.y-z,room), new RoomPosition(target.pos.x+z,target.pos.y-z,room),new RoomPosition(target.pos.x-z,target.pos.y+z,room),new RoomPosition(target.pos.x+z,target.pos.y+z,room)];
var closest = creep.pos.findClosestByRange(targets);
return(closest);
}
//------------------------------------------------------------
};
module.exports = roleGuard;
Other file contains:
var roleGuard = require('role.guard');
for example:
// foo.js
function add(a,b){
return a + b
}
module.exports = add
and in the other file:
// bar.js
const add = require("./foo");
console.log(add(1,1))
those paths are relative to the file location. extension can be omitted.
you'll need node or browserify or webpack to make exports/require to work properly.
if you want a better explanation about modular javascript, look there, even if you not enter in the browserify world it will present you to what we can do nowadays.
EDIT:
in order to export more symbols you can do the following:
// foo2.js
function add(a,b){
return a + b
}
function multiply(a,b){
return a * b
}
module.exports = {
add:add,
multiply:multiply
}
And then in the consumer:
// bar2.js
const add = require("./foo2").add
const multiply = require("./foo2").multiply
//...
This is also valid:
// foo3.js
function add(a,b){
return a + b
}
exports.add = add
function multiply(a,b){
return a * b
}
exports.multiply = multiply
Consumer will need no relevant alteration:
// bar3.js
const add = require("./foo3").add
const multiply = require("./foo3").multiply
//...
If using babel/es6 modules have a different idion, which you can check there.

Are there any behavioural differences before and after this javascript refactoring?

I recently had to refactor a chunk of javascript that is using YUI.
So, originally it was something like this:
YAHOO.namespace('space.time');
YAHOO.space.time = (function() {
var b = document.getelementbyid("aifdsgyalierg");
function c(b) {
var a = new YAHOO.util.Anim(d, b); //just assume the parameters are correct here
a.method = YAHOO.util.Easing.easeOut;
a.animate();
};
return { c:c };
})();
For the sake of being able to inject dependencies, i refactored it to the below:
YAHOO.namespace('space.time');
YAHOO.namespace('space.timefn');
YAHOO.space.timefn = function(yuianim) {
var b = document.getelementbyid("aifdsgyalierg");
function c(d) {
var a = new yuianim(d, b); //just assume the parameters are correct here
a.method = YAHOO.util.Easing.easeOut;
a.animate();
};
return { c:c };
};
YAHOO.space.time = YAHOO.space.timefn(YAHOO.util.Anim);
So..
1) Ignoring any committed fallacies.. Will the behaviour of the two snippets differ?
2) What fallacies have i committed?

Categories