Can't run cucumber tests with protractor - javascript

Every time when I am running tests, I got the error: TypeError: e.getContext is not a function
I am using examples from https://github.com/cucumber/cucumber-js with some changes in world.js (made them to fix timeout errors)
Versions of apps:
node 4.2.6
cucumber 0.9.4
protractor 3.0.0
protractor-cucumber-framework 0.3.3
zombie 4.2.1
My world.js:
// features/support/world.js
var zombie = require('zombie');
zombie.waitDuration = '30s';
function World() {
this.browser = new zombie(); // this.browser will be available in step definitions
this.visit = function (url, callback) {
this.browser.visit(url, callback);
};
}
module.exports = function() {
this.World = World;
this.setDefaultTimeout(60 * 1000);
};
My sampleSteps.js:
// features/step_definitions/my_step_definitions.js
module.exports = function () {
this.Given(/^I am on the Cucumber.js GitHub repository$/, function (callback) {
// Express the regexp above with the code you wish you had.
// `this` is set to a World instance.
// i.e. you may use this.browser to execute the step:
this.visit('https://github.com/cucumber/cucumber-js', callback);
// The callback is passed to visit() so that when the job's finished, the next step can
// be executed by Cucumber.
});
this.When(/^I go to the README file$/, function (callback) {
// Express the regexp above with the code you wish you had. Call callback() at the end
// of the step, or callback.pending() if the step is not yet implemented:
callback.pending();
});
this.Then(/^I should see "(.*)" as the page title$/, function (title, callback) {
// matching groups are passed as parameters to the step definition
var pageTitle = this.browser.text('title');
if (title === pageTitle) {
callback();
} else {
callback(new Error("Expected to be on page with title " + title));
}
});
};
My sample.feature:
# features/my_feature.feature
Feature: Example feature
As a user of Cucumber.js
I want to have documentation on Cucumber
So that I can concentrate on building awesome applications
Scenario: Reading documentation
Given I am on the Cucumber.js GitHub repository
When I go to the README file
Then I should see "Usage" as the page title
My protractor-conf.js:
exports.config = {
specs: [
'features/**/*.feature'
],
capabilities: {
'browserName': 'chrome'
},
baseUrl: 'http://127.0.0.1:8000/',
framework: 'custom',
frameworkPath: require.resolve('protractor-cucumber-framework'),
// relevant cucumber command line options
cucumberOpts: {
require: ['features/support/world.js', 'features/sampleSteps.js'],
format: "summary"
}
};

I had same issue with this example. The problem is with github.com page. What the problem, I don't know.
So, I made changes for the page which to visit and tests start run without TypeError: e.getContext is not a function.
I changed sampleSteps.js file:
module.exports = function () {
this.Given(/^I am on the Google.com$/, function (callback) {
// Express the regexp above with the code you wish you had.
// `this` is set to a World instance.
// i.e. you may use this.browser to execute the step:
this.visit('http://www.google.com/', callback);
// The callback is passed to visit() so that when the job's finished, the next step can
// be executed by Cucumber.
});
this.When(/^I go to the SEARCH page$/, function (callback) {
// Express the regexp above with the code you wish you had. Call callback() at the end
// of the step, or callback.pending() if the step is not yet implemented:
// changed to this one, otherwise next steps also are skipped...
callback();
});
this.Then(/^I should see "(.*)" as the page title$/, function (title, callback) {
// matching groups are passed as parameters to the step definition
this.browser.assert.text('title', title);
callback();
});
};
Then some changes for sample.feature:
Feature: Example feature
As a user of Google.com
I want to have search with Google
So that I can find something
Scenario: Search something
Given I am on the Google.com
When I go to the SEARCH page
Then I should see "Google" as the page title
I hope, this will help with first steps working with cucumber-js and zombie.js.
It's not the problem with protractor, because same problem is, when I run this sample in the WebStorm.

Related

Having difficulty with javascript(node.js) that needs to be synchronous

I have an express.js app that needs to run a script on the server in order to derive some values using functions later. Here's the gist of it:
shell.exec(commandString);
readFolder();
renderPage();
Essentially, I need to run a script on the server, then run the second function, then run the third function. These need to happen subsequently, but it seems that javascript moves on ahead with the the second and third function no matter what I do. I've tried promises, async, callbacks. All of which I only partially understand and seem to get zero progress.
I will admit that I am a javascript novice. I am working on a project with others and this task fell to me. I doubt this is the best way to accomplish our ultimate goals, but I am left with little choice. please help.
I'll put the entire post here for reference:
//Run script when post is rec'd from root and send to results page
app.post("/", (req, res) => {
var commandString;
//take values and create complete command for Astrum script
commandString = 'bash /home/astrum/Main/Astrum.sh -s ' + req.body.speed + ' -h ' + req.body.host + ' -u ' + req.body.username + ' -p ' + req.body.password;
//execute command in shell
shell.exec(commandString);
readFolder();
renderPage();
//Iterate thru filenames to create arrays for links and link labels
function readFolder() {
fs.readdir('./reports/html/', (err, files) => {
//variable & method for links to html records pages
ipAddressesLink = files; //this is initialized earlier, globally
//variable and method to remove file extension for link labels in pug
ipAddresses = files.map(removeExtension); //this is initialized earlier, globally
});
}
//function to remove last five characters of each element
function removeExtension(value) {
return value.substring(0, value.length - 5);
};
//function to render the page
function renderPage() {
res.render("results", {ipAddressesLink, ipAddresses, title: 'Results'});
}
res.end();
});
You could write it this way:
shell.exec(commandString, (error, stdout, stderr) => {
// Calling the 1st function after shell command is executed
readFolder();
});
function readFolder() {
fs.readdir('./reports/html/', (err, files) => {
// Some stuff
...
// Calls the 2nd function after fs is done reading files
renderPage();
});
}
function renderPage() {
const options = { ... }; // IP addresses etc.
res.render(
"results",
options,
// Calls the final function after render is finished
sendResponse
);
}
function sendResponse(err, html) {
// Sends the response. It’s possible that res.send() is the better solution here
res.end();
}
It’s just the general structure of the callback chain, definitely not the cleanest one. If you want better code structure and readability try switching to async / await syntax.
Is shell here the child_process module? If it is then you can pass an optional callback argument and call your functions from there.
shell.exec(commandString, (error, stdout, stderr) => {
const files = readFolder();
renderPage(files);
});
function readFolder() {
...
return fs.readdirSync(files);
}
function renderPage(files) {
...
}

Protractor Cucumber BDD Tests Show Pass before Execution

I have a sample BDD test using Protractor with Cucumber. On executing the code, the console immediately shows the result as passed and the code actually begins executing only after that.
I wish execution status display to be in sync with actual execution.(e.g Console displays - 'Given I launch the protractor demo page' and the code underneath is executed, then console displays next step and so on) I know it has got something to do with Async coding and callbacks, not able to figure out the exact problem though.
Feature file:
Feature: Test
Scenario: Test Scenario
Given I launch the protractor demo page
When I enter two in the first field
And I enter three in the second field
And I click Go button
Then Result should be displayed as Five
Step File:
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
var expect = chai.expect;
module.exports = function () {
this.Given(/^I launch the protractor demo page$/, function (callback) {
browser.driver.manage().window().maximize();
browser.get('http://juliemr.github.io/protractor-demo/');
browser.getTitle().then(function(text){
console.log('title is - ' + text);
expect(text).to.equal('Super Calculator');
});
callback();
});
this.When(/^I enter two in the first field$/, function (callback) {
element(by.model('first')).sendKeys('2');
callback();
});
this.When(/^I enter three in the second field$/, function (callback) {
element(by.model('second')).sendKeys('3');
callback();
});
this.When(/^I click Go button$/, function (callback) {
element(by.id('gobutton')).click();
callback();
});
this.Then(/^Result should be displayed as Five$/, function (callback) {
element(by.repeater('result in memory')).all(by.tagName('td')).get(2).getText().then(function(text){
expect(text).to.equal('5');
});
callback();
});
};
You need to either return a promise or use the done callback in your step definitions. Otherwise cucumber doesn't know when your asynchronous
actions are complete.
I had the same question and above statement was the response from one of the core members of the protractor-cucumber github forum.
I prefer to return promises when I am performing some actions on the results with .then function and use .done callback function when I am not, Also you don't need callbacks now CucumberJS supports promises. So your step file should look like -
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
var expect = chai.expect;
module.exports = function () {
this.Given(/^I launch the protractor demo page$/, function () {
browser.driver.manage().window().maximize();
browser.get('http://juliemr.github.io/protractor-demo/');
return browser.getTitle().then(function(text){
console.log('title is - ' + text);
expect(text).to.equal('Super Calculator');
});
});
this.When(/^I enter two in the first field$/, function () {
return element(by.model('first')).sendKeys('2');
});
this.When(/^I enter three in the second field$/, function () {
return element(by.model('second')).sendKeys('3'); // you can use return also
});
this.When(/^I click Go button$/, function () {
return element(by.id('gobutton')).click();
});
this.Then(/^Result should be displayed as Five$/, function () {
return element(by.repeater('result in memory')).all(by.tagName('td')).get(2).getText().then(function(text){
expect(text).to.equal('5');
});
});
};
I would recommend you to read about Promises http://www.html5rocks.com/en/tutorials/es6/promises/ as it requires some understanding how they behave.They can be sometimes tricky, it took me a while to get an idea still I have lot to learn :)

Using asynchronous commands in nightwatch e2e tests

I have a following e2e scenario written using Nightwatch:
var Q = require('q');
module.exports = {
afterEach: function (browser, done) {
browser.end(function() {
done();
});
},
'should display same data on second page as on first page': function (browser) {
//Given
var firstPage = bowser.pages.first()
//When
Q.all([
firstPage.getTextPromise('#element1'),
firstPage.getTextPromise('#element2'),
firstPage.getTextPromise('#element3')]
).then( function(values) {
users.click('#linkToSecondPage');
//Then
var secondPage = browser.page.secondPage();
secondPage.expect.element('#dataElement1').text.to.equal(values[0]).before(5000);
secondPage.expect.element('#dataElemnet2').contains.text(values[1]);
secondPage.expect.element('#dataElement3').contains.text(values[2]);
});
} }
The getTextPromise command is defined by me in following way:
commands: [{
getTextPromise: function(selector) {
var self = this;
return Q.Promise(function (resolve, reject) {
self.getText(selector, function(result) {resolve(result.value); });
});
} }]
The rationale behind this scenarion is to remember some values on one page before clicking on link to second page
and then checking that on second page the same content is displayed (for example, you click on one item in a table
and go to page displaying details of this particular item).
Unfortunately, I observed that this test sometimes does not check things inside the then callback.
I think this is caused by the test finishing (calling done in afterEach()) before he callback returns.
I thought there was a done() callback passed to the test (much like in nightwatch async unit tests) that I could use but apparently there is not.
Is there a proper way to do this in Nightwatch? Perhaps I am using commands in wrong way?
Nightwatch will keep track of command run order itself if the command runs a method on 'this', and returns 'this'.
Try a command like this, adapted as a page command if you prefer:
exports.command = function() {
var self = this;
var globals = self.globals;
if (!globals.values) { globals.values = []; }
var link = 'some_xpath';
self.getText('selector', function(result) {
if(result.status !== -1){
self.globals.values.push = result.value;
}
});
return self;
};
Because the command returns this. It can be chained and you could be sure the commands run in order without manually writing promises.
example:
var firstPage = bowser.pages.first()
var secondPage = browser.page.secondPage();
firstPage.getTextPromise('#element1')
.getTextPromise('#element2')
.getTextPromise('#element3');
secondPage.expect.element('#dataElement1').text.to.equal(global.values[0]).before(5000)
.expect.element('#dataElemnet2').contains.text(global.values[1])
.expect.element('#dataElement3').contains.text(global.values[2]);
I haven't tested this out so it may need a slight tweak. Hopefully it gives a rough idea of how to chain your commands the nightwatch way. If you run into a problem let me know.

How to pass additional information to a callback of a 3rd party module in node.js

It is a simple node.js application. I'm using Browser.visit(url, callback) provided by Zombie module (http://zombie.labnotes.org), Browser.visit() will call the callback as (error, browser, status) in uncertain future with different context. And my callback need some extra information to finish its job.
So far I can make it "working" as:
function test(title, url) {
var browser = new Browser();
browser.visit(url, function (e, browser, status, thetitle)
{
// generate info using the title if browser visited url successfully
}
.bind(undefined, browser, undefined, title);
}
test("foo", fooUrl);
test("bar", barUrl);
But there is a problem, the bind() just bypassed the error and status parameters. It seems not the right way. How could I pass the additional info to this callback?
FYI: Just got confirmed, the API doc of Zombie.js is for 1.4.x, 2.0.0-Alpha API is not finalized yet. https://groups.google.com/forum/?hl=en#!topic/zombie-js/qOS0W_cMCgQ
It's a little difficult to understand your question, I'm not sure why you are using bind, but perhaps this is what you are trying to achieve?
Javascript
function Browser(url) {
this.url = url;
}
Browser.prototype.visit = function (url, fn) {
var self = this,
error = 'error',
status = 'status';
setTimeout(function () {
fn(error, self, status);
}, 1000);
};
function test(title, url) {
var browser = new Browser(url);
browser.visit(url, (function (theTitle) {
return function (theError, theBrowser, theStatus) {
// generate info using the title if browser visited url successfully
console.log('theError: ', theError);
console.log('theBrowser: ', theBrowser);
console.log('theStatus: ', theStatus);
console.log('theTitle: ', theTitle);
};
}(title)));
}
test('hello', 'world');
test('goodbye', 'mum');
Output
theError: error
theBrowser: Browser {url: "world", visit: function}
theStatus: status
theTitle: hello
theError: error
theBrowser: Browser {url: "mum", visit: function}
theStatus: status
theTitle: goodbye
On jsFiddle
There is no need to use bind just to make the anonymous function passed to browser.visit access title. This would work:
function test(title, url) {
var browser = new Browser();
browser.visit(url, function (e, browser, status) {
console.log(title);
});
}
The value of title in console.log(title) is the same as the value of the title parameter of the test function.
Note that this works whether the callback passed to browser.visit is called synchronously or asynchronously.

How to make Grunt wait for a task to finish before running another?

Here's my Gruntfile and the output.
As you can see in the output, there are a couple of issues related to asynchronous tasks:
imagemin is called and the next one comes straight ahead. This makes its output appear in the end of the tasks, what's quite messy;
build, which is a custom task, is using var done = this.async() and calling done() after finishing the command; however, this only works correctly if I run the task alone; running it with another tasks makes it run async too;
With build running later, jasmine has nothing to test and thus is useless.
Is there a way to fix this behavior?
I believe your problem is with this task:
grunt.registerTask('prepare-dist', 'Creates folders needed for distribution', function() {
var folders = ['dist/css/images', 'dist/imgs/icons'];
for (var i in folders) {
var done = this.async();
grunt.util.spawn({ cmd: 'mkdir', args: ['-p', folders[i]] }, function(e, result) {
grunt.log.writeln('Folder created');
done();
});
}
});
If you have multiple folders, both async() and done() will be called multiple times. Async is implemented as a simple flag (true/false) and is meant to be called once. The first done() call allows any follow on tasks to run.
There are many ways to move the calls to async and done out of the loop. A quick google search on something like: nodejs how to callback when a series of async tasks are complete will give you some additional options. A couple of quick (& dirty) examples:
// Using a stack
(function() {
var work = ['1','2','3','4','5']
function loop(job) {
// Do some work here
setTimeout(function() {
console.log("work done");
work.length ? loop(work.shift()) : done();
}, 500);
}
loop(work.shift());
function done() {
console.log('all done');
}
})();
-- or --
// Using a counter (in an object reference)
(function() {
var counter = { num: 5 }
function loop() {
// Do some work here
setTimeout(function() {
--counter.num;
console.log("work done");
counter.num ? loop() : done();
}, 500);
}
loop();
function done() {
console.log('all done');
}
})();
As you could read in the Grunt documentation:
If a task is asynchronous, this.async method must be invoked to instruct
Grunt to wait. It returns a handle to a "done" function that should be
called when the task has completed.
And a short example would be similar to:
// Tell Grunt this task is asynchronous.
var done = this.async();
// Your async code.
fetchData(url).then( data => {
console.log(data);
done();
}).catch( error => {
console.err(error);
done(false); // false instructs Grunt that the task has failed
});

Categories

Resources