Reputation: 8148
I have searched on Google and the SO site and I get answers for JAVA but do not seem to get answers for node.js
I have a web app that takes time to load. I would like the selenium program to wait till the page is loaded and then perform some actions.
My current code is as follows
//dependencies
var webdriver = require('selenium-webdriver'),
util = require('util'),
_ = require('underscore');
var driver = new webdriver.Builder().withCapabilities(webdriver.Capabilities.chrome()).build();
var branchName = _.isUndefined(process.argv[3]) ? 'branch' : process.argv[3],
hostName = _.isUndefined(process.argv[2]) ? 'localhost' : process.argv[2],
appTmpl = 'http://%s/%s',
username = 'xxxx',
password = 'xxxx';
var appUrl = util.format(appTmpl, hostName, branchName);
driver.get(appUrl);
driver.findElement(webdriver.By.name("username")).sendKeys(username);
driver.findElement(webdriver.By.name("password")).sendKeys(password);
driver.findElement(webdriver.By.name("login_button")).click();
driver.quit();
The error I get is:
C:\Work\study\selenium\node_modules\selenium-webdriver\lib\webdriver\promise.js:1643
throw error;
^
NoSuchElementError: no such element
(Session info: chrome=37.0.2062.103)
(Driver info: chromedriver=2.10.267521,platform=Windows NT 6.1 SP1 x86_64)
at new bot.Error (C:\Work\study\selenium\node_modules\selenium-webdriver\lib\atoms\error.js:109:18)
at Object.bot.response.checkResponse (C:\Work\study\selenium\node_modules\selenium-webdriver\lib\atoms\response.js:106:9)
at C:\Work\study\selenium\node_modules\selenium-webdriver\lib\webdriver\webdriver.js:277:20
at C:\Work\study\selenium\node_modules\selenium-webdriver\lib\goog\base.js:1243:15
at webdriver.promise.ControlFlow.runInNewFrame_ (C:\Work\study\selenium\node_modules\selenium-webdriver\lib\webdriver\promise.js:1539:20)
at notify (C:\Work\study\selenium\node_modules\selenium-webdriver\lib\webdriver\promise.js:362:12)
at notifyAll (C:\Work\study\selenium\node_modules\selenium-webdriver\lib\webdriver\promise.js:331:7)
at resolve (C:\Work\study\selenium\node_modules\selenium-webdriver\lib\webdriver\promise.js:309:7)
at fulfill (C:\Work\study\selenium\node_modules\selenium-webdriver\lib\webdriver\promise.js:429:5)
at C:\Work\study\selenium\node_modules\selenium-webdriver\lib\webdriver\promise.js:1406:10
==== async task ====
WebDriver.findElement(By.name("username"))
at webdriver.WebDriver.schedule (C:\Work\study\selenium\node_modules\selenium-webdriver\lib\webdriver\webdriver.js:268:15)
at webdriver.WebDriver.findElement (C:\Work\study\selenium\node_modules\selenium-webdriver\lib\webdriver\webdriver.js:711:17)
at Object.<anonymous> (C:\Work\study\selenium\test.js:15:8)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
Upvotes: 61
Views: 131780
Reputation: 1
await driver.wait(until.elementLocated(By.className('searchServiceBtn')), 10000); const searchButton = await driver.findElement(By.className('searchServiceBtn'));
// Wait for the button to be clickable
await driver.wait(until.elementIsVisible(searchButton), 10000);
await driver.wait(until.elementIsClickable(searchButton), 10000);
// Click the search button
await searchButton.click();
console.log('Search button clicked.');
// Wait for the search section to be located
await driver.wait(until.elementLocated(By.id('servicelistSearch-form-wrp')), 10000);
// Check if the search section is displayed
const isDisplayed = await driver.findElement(By.id('servicelistSearch-form-wrp')).isDisplayed();
console.log(`Search section is ${isDisplayed ? 'open' : 'closed'}`);
} catch (error) {
console.error('Error occurred:', error);
I am not able to automate the things with this code
Upvotes: -1
Reputation: 4525
You can register a listener on webdriver.wait
by using then()
driver.wait(until.elementLocated(By.name('username')), 5 * 1000).then(el => {
el.sendKeys(username);
});
Upvotes: 44
Reputation: 100486
You don't need a custom function, you can just do this:
let el = await driver.findElement(By.id(`import-file-acqId:${acqId}`));
await driver.wait(until.elementIsVisible(el),100);
await el.sendKeys(file);
See the docs here.
Upvotes: 47
Reputation: 708
The main problem is webdriver thinks element is already there, but not yet. I have a solution, ugly but works. After the webdriver think item is there, try to click on. Get an error message:
StaleElementReferenceError: stale element reference: element is not attached to the page document (Session info: chrome=83.0.4103.106)
No problem, in the loop waiting 500ms, and try to click on again. In my case 5 try is enough, about 2-3 click is success.
async clickonitem( driver, itemname ) {
const strftime = require('strftime');
var trycounter = 0;
var timeout = 500;
var success;
do {
try {
trycounter++;
success = true;
console.log( strftime('%F %T.%L'), "Finding #" + trycounter + " " + itemname );
var item = await driver.wait( until.elementLocated( By.xpath( '//input[@name="' + itemname +'"]' ) ),
timeout );
console.log( strftime('%F %T.%L'), "Found or Timeout #" + trycounter );
//await item.click();
await driver.wait( item.click(),
timeout );
console.log( strftime('%F %T.%L'), "Click #" + trycounter + " " + itemname );
}
catch(err) {
success = false;
//this.log( "Error #" + trycounter + " " + itemname + "\n" +err );
this.log( strftime('%F %T.%L'), "Error #" + trycounter + " " + itemname + " waiting: " + timeout );
await wait( timeout );
continue;
}
} while( !success && trycounter < 5 );
}
async wait( ms ) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
clickonitem( driver, "login_button" );
Upvotes: 0
Reputation: 21
I usually use this way:
var el = driver.wait(until.elementLocated(By.name('username')));
el.click();
Upvotes: 2
Reputation: 63
I came up with this approach because it maintains the chainable promise syntax so that I can write this: await waitFind(By.id('abc')).click()
const waitFind = (locator) => {
return driver.findElement(async () => {
await driver.wait(until.elementLocated(locator));
return driver.findElement(locator);
});
}
Upvotes: 3
Reputation: 2308
This is the only thing that is working for me:
const element = By.id('element');
driver.wait(until.elementLocated(element));
const whatElement = driver.findElement(element);
driver.wait(until.elementIsVisible(whatElement), 5000).click();
Upvotes: 5
Reputation: 21
Writing asynchronous function to avoid this problem
(async function() {
let url = args[0];
await driver.get(url);
driver.quit();
})();
Upvotes: 1
Reputation: 1955
Try something like this:
function isItThere(driver, element){
driver.findElement(webdriver.By.id(element)).then(function(webElement) {
console.log(element + ' exists');
}, function(err) {
if (err.state && err.state === 'no such element') {
console.log(element + ' not found');
} else {
webdriver.promise.rejected(err);
}
});
}
I adapted it slightly based on what I found here: Check if element exists - selenium / javascript / node-js and it worked a charm.
Upvotes: 3
Reputation: 8148
I stumbled upon an answer to my question
So to wait for an element to appear we have to:
driver.wait(function () {
return driver.isElementPresent(webdriver.By.name("username"));
}, timeout);
Upvotes: 59