How to run selenium webdriver code once element is present - node.js

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.

Related

Chrome Plugin Manifest V3 - strange behavior of a promise function in popup.js

I'm trying to create a small plugin to make my day-to-day job easier. I have faced a very strange situation within the popup.js script. The promise function randomly refuses to get executed. I have spent some hours trying to debug or at least understand where the issue could be but without any results.
Here is the skeleton of the code:
document.addEventListener('DOMContentLoaded', function () {
// some initialization
document.getElementById("signinbutton").addEventListener("click", function(event) {
try {
// some more initialization
var user_email = '';
var advertiserId = '';
var checkibm = '';
user_email = $('#emailfield').val().trim();
advertiserId = $('#advertiseridfield').val().trim();
checkibm = $('#checkibm').is(':checked');
if (advertiserId && checkibm) {
_act = 'getTokenIdByAdvId',
_data = advertiserId
}
else if (advertiserId && !checkibm) {
_act = 'getTokenIdByAdvId',
_data = advertiserId
}
else if (user_email && validateEmail(user_email))
{
_act = 'getTokenIdByEmail',
_data = user_email
}
else
{
throw new Error("Valid input has not been provided");
}
sendMessagePromise({
act : 'getTokenIdByAdvId',
data: '16910'//encodeURIComponent(user_email)
})
.then(responseHandler)
.then(responseReplaceTokenHandler)
.then(show_ok('Done'))
.catch(failureCallback);
}
catch (error){
//doing some error catching here
});
});
The code above works perfectly. However, as soon as I fill in the real values in sendMessagePromise e.g
//_act and _data show the proper values when inspected
sendMessagePromise({
act : _act,
data: _data//encodeURIComponent(user_email)
})
the flow skips execution of sendMessagePromise and any other chained function, except the last one ".then(show_ok('Done'))", i.e the only result is the "Done" message on the screen.
I made sure the values are correct. I'm able to debug step-by-step and see the values being properly supplied. I have also put a bunch of console messages inside the chain promise functions to see where the execution gets stuck, but it seems like it doesn't even start executing sendMessagePromise.
As soon as I replace expression back to hardcoded values i.e
sendMessagePromise({
act : 'getTokenIdByAdvId',
data: '16910'//encodeURIComponent(user_email)
})
it starts working again. I'm really stuck and not sure how to debug or which steps to take further.
Please assist

Getting error while running selenium test in node.js

The code I am using to run the automated test for google search is below.
const webdriver = require('selenium-webdriver'),
By = webdriver.By,
until = webdriver.until;
const driver = new webdriver.Builder()
.forBrowser('chrome')
.build();
driver.get('http://www.google.com');
driver.findElement(By.name('q')).sendKeys('webdriver');
driver.sleep(10000).then(function() {
driver.findElement(By.name('q')).sendKeys(webdriver.Key.TAB);
});
driver.findElement(By.name('btnK')).click();
driver.sleep(20000).then(function() {
driver.getTitle().then(function(title) {
if(title === 'webdriver - Google Search') {
console.log('Test passed');
} else {
console.log('Test failed');
}
driver.quit();
});
});
and it is throwing an error which says that element is not interactable. I have added extra time delays for loading page successfully.
(node:32241) UnhandledPromiseRejectionWarning: ElementNotInteractableError: element not interactable
element not interactable is telling you that the element you are trying to click on - is just not clickable.
You have 2 ways to overcome this:
Find the child element of the element you are trying to click on or its parent element.
Force the element to be clicked by injecting JavaScript into it:
JavascriptExecutor jse = (JavascriptExecutor)driver;
jse.executeScript("document.getElementsByName
('btnK')[0].click();");
You need to make a couple of adjustments as follows:
Remove the first occurance of findElement(By.name('q')) as you are already using the line of code later.
Modify the second occurance of findElement(By.name('q')) to send the text and Key.RETURN
Remove the line findElement(By.name('btnK')) as you are already using the line of code later.
Your effective line of code will be:
const driver = new webdriver.Builder()
.forBrowser('chrome')
.build();
driver.get('http://www.google.com');
driver.sleep(10000).then(function() {
driver.findElement(By.name('q')).sendKeys('webdriver' + Key.RETURN);
});
driver.sleep(20000).then(function() {
driver.getTitle().then(function(title) {
if(title === 'webdriver - Google Search') {
console.log('Test passed');
} else {
console.log('Test failed');
}
driver.quit();
});
});
Basically driver.findElement() return promise,
So it can be anywhere in your code, so basically you have sync your code
may be here:
:driver.findElement(By.name('q')).sendKeys('webdriver');
or:
driver.findElement(By.name('btnK')).click();
so you need to make your code sync. just put ==>
await driver.findElement(By.name('btnK')).click();
-> this method won't work. Because you do not know browser behaviour some time it is fast and sometimes slow so this won't help you, driver.sleep().
Better to use:
await driver.wait(until.elementedlocated(By.xpath("xpath"),5000));

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!

selenium-webdriver npm wait

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'));

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