selenium-webdriver npm wait - node.js

I have a simple script that performs a login using the selenium-webdriver npm module. The script works, but it is really slow and the wait timeout is giving very odd results (sometimes it seems to timeout immediately, and other times it waits far past the defined timeout).
Am I doing something wrong that would make the login very slow (running this through a selenium hub perhaps)? The site itself is very responsive.
Here is the script:
var webdriver = require('selenium-webdriver');
var driver = new webdriver.Builder().
usingServer('http://hubserver:4444/wd/hub').
withCapabilities(webdriver.Capabilities.firefox()).
build();
console.log('\n\nStarting login.');
console.log('\nConnecting to grid: http://hubserver:4444/wd/hub' );
// Load the login page and wait for the form to display
driver.get('https://testsite.com');
driver.wait(function() {
return driver.isElementPresent(webdriver.By.name('user'));
}, 3000, '\nFailed to load login page.');
// Enter the user name
driver.findElement(webdriver.By.name('user')).sendKeys('testuser').then(function() {
console.log("\nEntering user name");
});
// Enter the password
driver.findElement(webdriver.By.name('pass')).sendKeys('testpwd').then(function() {
console.log("\nEntering password");
});
// Click the login button
driver.findElement(webdriver.By.id('submit')).click().then(function() {
console.log("\nLogging in.");
});
// Wait for the home page to load
driver.wait(function() {
console.log("\nWaiting for page to load");
return driver.isElementPresent(webdriver.By.id('main'));
}, 3000, '\nFailed to load home page.');
driver.getCurrentUrl().then(function(url) {
console.log("\nPage loaded: " + url);
});
driver.quit();

Maybe you have it specified elsewhere, but in the code shown your driver.wait() has no amount of time specified.
Also, maybe I'm misunderstanding your code because I do this mainly in Python, but driver.wait(function(){}); looks weird to me. Is this really proper use of the JS bindings? Generally, you wait for the element to be found and then subsequently call a function that does something with the element. I can't write it in JS, but in pseudocode:
driver.wait(#element you're looking for)
# Handle exception if there is one
# Otherwise do something with element you're looking for
Also, I would think
driver.isElementPresent(webdriver.By.name('user'));
Should be
driver.isElementPresent(By.name('user'));

Related

galen: how to wait dynamic new page with same url

I started working with Galen and I had this test that was working perfectly:
this.HomePage = $page('Welcome Page', {
aboutButton: 'nav.navbar .about'
});
this.AboutPage = $page('About page', {
modalContent: 'div.modal-content',
supportLink: '.support-link',
dismissButton: '.dismiss'
});
var homePage = new HomePage(driver);
homePage.waitForIt();
homePage.aboutButton.click();
var aboutPage = new AboutPage(driver);
aboutPage.waitForIt();
I understand that the waitForIt method waits for all the attributes defined by page so the framework knows when to execute the next statement.
Now, I want to run this as a grunt task and I've been using grunt-galenframework, and I configured it correctly, everything is working, but I can't make the previous test pass, the task code is as follows:
load('../gl.js');
forAll(config.getDevices(), function (device) {
test('simple test on ' + device.deviceName, function () {
gl.openPage(device, config.getProjectPage(), "Welcome Page", {
aboutButton: 'nav.navbar .about'
});
elements.aboutButton.click();
// MISSING WAIT FOR ABOUT_PAGE
gl.runSpecFile(device, './test/responsive/galen/about.gspec');
});
});
As you can see, I get into the Welcome Page and then I need to click a button, wait for a dialog to appear, and then check the about.gspec specs (they verify elements inside the dialog).
So how can I add a wait for new elements to appear on the same URL? it feels like grunt-galenframework only offers wait when entering a new url, with the openPage method.
you could try
elements.newElement.waitToBeShown()
The methods from here should be available.
PS: I'm the author of the grunt plugin for Galen and also involved in the development of the Galen Framework itself

How to run selenium webdriver code once element is present

Everything I've seen over the past month of looking is outdated.
Here's my problem, I traverse through about 5 different pages on one website before I get to the data I need. I can't fire off a driver.get as the url stays the same for all 5 different pages.
Since Node.js is asynchronous it runs the code before the element is present. I realize I could use a timeout, but i'm running this code 100's of times so a timeout won't work.
Everyone online says to do this, but it's outdated and doesn't work:
driver.findElement(By.css('#gridsortlink')).then(function(webElement) {
webElement.isElementPresent(By.css('#gridsortlink'))
.then(function(found) { console.log(found); });
});
If you do know how to do this that'd be great as I've been looking for a month now for the solution.
Your tried attempt looks incorrect, you should try as below :-
var webdriver = require('selenium-webdriver'),
By = webdriver.By,
until = webdriver.until;
driver.wait(until.elementLocated(By.css('#gridsortlink')), 5 * 1000).then(function(found) {
console.log(found);
});
In place of webElement.isElementPresent try to use driver.isElementPresent
driver.findElement(By.css('#gridsortlink')).then(function(webElement) {
driver.isElementPresent(By.css('#gridsortlink'))
.then(function(found) { console.log(found); });
});
I don't have access to your application thats why I created a demo code for gmail where I am putting some wrong value in Email field and after some time I am getting an error message. and the output here is 'true'.
var webdriver = require('selenium-webdriver');
var driver = new webdriver.Builder().forBrowser('chrome').build();
var By = webdriver.By;
driver.get('http://gmail.com');
driver.findElement(By.id("Email")).then(function(emailText){
emailText.sendKeys("aaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddd").then(function(){
driver.findElement(By.id("next")).then(function(submit){
submit.click().then(function(){
driver.isElementPresent(By.className("error-msg")).then(function(text){
console.log(text);
});
});
});
});
});
Java code:
if((driver.findElements(By.css('#gridsortlink')).size())==1)
{
system.out.println(executecode);
}
else
{
system.out.println(element is not exist in webpage);
}
You can check element is present or not.
driver.findElements(By.css('#gridsortlink')).size() this row returns to 0 or 1.
1 means - Element exists on webpage.
0 means - Element does not exist on webpage.
Try in your code.

Intern and Leadfoot conditional wait until

If there a way to perform .click() after the element become visible.
My function chain is built like that:
this.remote.findByXpath("//div[#data-index='blockContainer']/button[text()='Create new']").then(function(element) {
return element.click().end();
})
Sometimes I got error says 'the element is not visible', is it possible to perform click after the element displayed in browser? I know Leadfoot supplies pollUntil to do similar thing but I don't want to execute xpath at browser side, instead of I want to do until at running server side.
To solve my problem I tried following two ways but doesn't help:
I tried to pass Leadfoot Element to browser side script and check if it is visible. But it seems browser side code doesn't recognize leadfoot/element object.
command.find(...).then(function(element) {
return command.then(pollUntil(
function(element) {
if (element.style.display == 'none') return null;
return true;
}, [element], 60000, 500)).then(function(el){
});
}).click().end();
Also tried to customize pollUntil myself but doesn't work as well
function pollVisible(element, timeout) {
var dfd = new Deferred();
var endTime = Number(new Date()) + timeout;
(function poll() {
element.isDisplayed().then(function (displayed) {
if (displayed) {
dfd.resolve();
}
else if (Number(new Date()) < endTime) {
setTimeout(poll, 500);
}
else {
var error = new Error('timed out; final url is ' + url);
dfd.reject(error);
}
});
})();
return dfd.promise;
}
You've probably had an answer to this by now but here's my solution to this just in case you're still unsure or if anyone else comes across this issue.
I'm not sure why you are polling until an element is visible here. What I would do is set the find timeout of your leadfoot/Session as follows:
this.remote.setFindTimeout(60000)
Then when you invoke the this.remote.findByXPath method, it will automatically search for your element for a maximum of 1 minute (in the case of my above example). If it finds the element within that time, it will then proceed to the next step in your code. If it doesn't find the element within that time, the test case will time out.
You can then simplify your code to (for example):
this.remote
.setFindTimeout(60000)
.findByXpath("//div[#data-index='blockContainer']/button[text()='Create new']")
.click()
.end();
Of course there's no need to set the find timeout every time you wish to find an element in the UI. You can set it once somewhere more appropriate (ie. at the beginning of your test) and it will remain in place for the duration of your test. I'm just doing it here as a means of documenting a full example for you.
Hope this helps!

Does PhantomJS store any persistent files by default?

As a new user to PhantomJS I want to be sure that I understand how PhantomJS handles any persistence of data that it accumulates from a HTTP request.
My question is: Does PhantomJS store any data persistently by default (i.e. a simple example where you are not using require('fs') anywhere in the script to store the request, just dumping it out to STDOUT). I am assuming that all of the work from a page.evaluate() call is done in memory.
Here is a simple example for illustration:
var page = require('webpage').create(),
system = require('system'),
address;
if(system.args.length != 2)
{
console.log('Usage: phantomjs thisFile.js URL');
phantom.exit(1);
}
else
{
address = system.args[1];
page.open(address, function (status)
{
if(status !== 'success')
{
console.log('Unable to load the address!');
phantom.exit(1);
}
else
{
// Wait for the js to finish loading
window.setTimeout(function(){
var results = page.evaluate(function(){
return document.documentElement.innerHTML;
});
console.log(results); // This would be to stdout
phantom.exit(0);
}, 200);
}
console.log("Done.");
});
}
This script would be called by something like phantomjs thisScript.js www.example.com.
I know that you can save a page to file, I just want to be sure that I am aware of all the places that PhantomJS may accumulate data on its own.
I also have looked into how PhantomJS handles cookies.
Yes, there is one type that is saved by default and this is the localStorage database.
On Windows 7: C:\Users\<user>\AppData\Local\Ofi Labs\PhantomJS
On Windows 8: C:\Ofi Labs\PhantomJs
On Linux: /home/<user>/.qws/share/data/Ofi Labs/PhantomJS
Everything else is saved only when you add the commandline options. The disk cache is inside of the above directory and the cookie file path has to be set explicitly.
So it means that if the web application that you test doesn't use localStorage then you can run PhantomJS in parallel.

selenium-webdriver in nodejs sample not returning current title

I was working through the selenium web-driver example and it didn't work. Several months ago it worked just fine so I am wondering if I am doing something wrong or if the testing methods have changed.
var assert = require('assert'),
test = require('selenium-webdriver/testing'),
webdriver = require('selenium-webdriver');
var By = webdriver.By;
test.describe('Google Search', function() {
test.it('should work', function(done) {
var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build();
driver.get("http://www.google.com");
driver.findElement(By.name("q")).sendKeys("webdriver");
driver.findElement(By.name("btnG")).click();
driver.getTitle().then(function(title) {
assert.equal("webdriver - Google Search", title);
done();
});
driver.quit();
});
});
The output is:
AssertionError: "webdriver - Google Search" == "Google"
Expected :"Google"
Actual :"webdriver - Google Search"
This tells me that the page has not updated yet but I am not sure why. The example appears here: https://code.google.com/p/selenium/wiki/WebDriverJs#Getting_Started
Selenium version from package.json: 2.39.0
Update
I should have also stated that the test is being run through Mocha. Is Mocha the culprit? When I tried this last time it was using Jasmine.
Straight from the example in the documentation, use wait:
driver.wait(function() {
return driver.getTitle().then(function(title) {
return title === 'webdriver - Google Search';
});
}, 1000);
Why do you need to use wait? Because the Google page works asynchronously. After you enter the keys, it may take a bit of time before the server sends a response and the page is updated.
You should also remove done. While in general you need it for asynchronous tests, it seems the sequencer that comes with this incarnation of Selenium's webdriver will block on quit until all actions are performed. This example in the documentation does not use it.
Also, if you wonder why there is no assertion: you'll know your test has failed if you get a timeout exception when the timeout has expired.

Resources