I'm attempting to create an ArrayList of WebElements from this page:
If all the elements are displayed, they're able to be added to the ArrayList just fine.
ArrayList<WebElement> TodoArray = new ArrayList<WebElement>();
TodoArray.add(todo1);
If I remove one of the elements from the web page(not code) I get this error when running my Test Case:
org.openqa.selenium.NoSuchElementException: Unable to locate element: *[name='todo[9]']
Is there any way to bypass this error and force java to skip the missing element, but continue adding the elements that are displayed?
My code is pretty straight forward. I'm using JUnit to run my test cases. The elements are defined correctly using the #FindBy annotations.
#FindBy(name="todo[1]")
WebElement todo1;
I tried surrounding the variables with Try/Catch and using NoSuchElementException, but I wasn't sure how to format it. Is using the "continue" keyword possible in this situation?
Hopefully I provided enough information. Any help would be appreciated. Thank you!
The exact syntax for Java Try/Catch would be this for you:
try {
#FindBy(name="todo[1]")
WebElement todo1;
}
catch(NoSuchElementException e) {
System.out.println("could not find element todo1");
}
...
//rest of your code
Does this help?
Or you can use fluent wait, this way:
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(10, SECONDS)
.pollingEvery(1, SECONDS)
.ignoring(NoSuchElementException.class);
I think this is a more elegant way to do it.
Related
Summary
I want to figure out a way to add a <script> tag into the head of DOM using Selenium's JavascriptExecutor, or any other way of doing this would be nice.
I have tried many ways and also found a few similar topics and none of them solved my problem which is why I felt the need to ask it on here.
For example :
Suggested solutions in this question did not solve my problem. Some people say it worked for them but nope, it didn't for me.
What I've been trying to execute?
Here is the small snippet of the code that I want to execute:
WebDriver driver = new FirefoxDriver();
JavascriptExecutor jse = (JavascriptExecutor) driver;
jse.executeScript("var s = document.createElement('script');");
jse.executeScript("s.type = 'text/javascript';");
jse.executeScript("s.text = 'function foo() {console.log('foo')}';");
jse.executeScript("window.document.head.appendChild(s);");
I just skipped the code above where you navigate to a webpage using driver.get() etc. and then try to execute the scripts.
Also, s.text would contain the actual script that I want to use so I just put there a foo() function just to give the idea.
The above code throws this error when you run it:
Exception in thread "main" org.openqa.selenium.JavascriptException: ReferenceError: s is not defined
So far I've tried every possible solution I could find on the Internet but none of them seems to work.
OP came up with the following solution:
jse.executeScript("var s=window.document.createElement('script');" +
"s.type = 'text/javascript';" + "s.text = function foo() {console.log('foo')};" +
"window.document.head.appendChild(s);");
For one, this line is invalid.
jse.executeScript("s.text = 'function foo() {console.log('foo')}';");
Note how you wrap single-quote text in single quotes. Use one set as "\""
I would personally do this by doing (edited to make it a global function):
using OpenQA.Selenium.Support.Extensions;
driver.ExecuteJavascript("window.foo = function foo() {console.log('foo')}");
It's as simple as that. You are registering foo as a method by doing this. After you execute this javascript, you can manually go in to the browser developer tools and call "foo()" to check. Additionally, you can check this by registering it directly in the console. Just enter "function foo() {console.log('foo')}" into your browser console, and then call "foo()".
No need to add this as a script tag.
EDIT #2: I fixed my above code suggestion so that the method is assigned to the window, and thus accessible globally, and outside of the anonymous script that javascript executor runs the code in. The original issues with this not working are resolved by this, at least in my testing of it.
This is an odd variety of a common problem.
I am running a Selenium project using a headless firefox browser.
I get the common NoSuchElementExceptions. That's nothing new. However, attempting to resolve them through explicit waits does not resolve the issue.
For example, the following line throws the NoSuchElementException:
WebElement trackingInbox = methodDriver.findElement(By.id("inbox-widget-container-id"));
I then add the following above this line:
FluentWait wait = new FluentWait(methodDriver);
wait.withTimeout(90, TimeUnit.SECONDS);
wait.pollingEvery(250, TimeUnit.MILLISECONDS);
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("inbox-widget-container-id")));
WebElement trackingInbox = methodDriver.findElement(By.id("inbox-widget-container-id"));
In the first instance, I get the exception at the "methodDriver.findElement . . . ."
In the second instance I get it at the "wait.until . . . "
This happens when I wait for "presenceOf . . ." and when I wait for "visibilityOf . . ." The way it appears, the element has to be available before I wait for it, which appears to defeat the purpose.
The way it currently appears, I have no option but to add implicit waits, but I know there must be some way to do the explicit waits such that the element does not have to be available before I wait for it.
I wonder if there are any ideas as to what I am doing wrong and if there are any principles I can go by to determine whether a particular wait would be useful or not.
You have actually forgot to call ignoring function at the end, This ignoring is what you want. When you are waiting for visibility of the element, it might occur that element doesn't exist but If you use Ignoring function, it would ignore if such error happens until it meet with the given condition.
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(30, SECONDS)
.pollingEvery(5, SECONDS)
.ignoring(NoSuchElementException.class);
I am trying to select value from the drodown. this is my code.
driver.findElement(By.xpath(".//*[#id='accountSelectContainer']/span/a/span[1]")).click();
driver.findElement(By.xpath("//ul[#id='ui-id-1']/li/a[equals(text(),'60091 - AFCENT')]")).click();
Now here i have hardcoded the value, which works perfect but i am reading my testdata from excel file . so instead of using direct hard code values , i want to declare my testdata in xpath and read it from excel file. so i tried to this:
Efforts
public void combobox(String testData)
{
driver.findElement(By.xpath(".//*[#id='accountSelectContainer']/span/a/span[1]")).click();
driver.findElement(By.xpath("//ul[#id='ui-id-1']/li/a[equals(text(),'"+testData+"')]")).click();
}
But i am getting the exception
org.openqa.selenium.InvalidSelectorException: invalid selector: Unable
to locate an element with the xpath expression
//ul[#id='ui-id-1']/li/a[equals(text(),'60091 - AFCENT')] because of
the following error: SyntaxError: Failed to execute 'evaluate' on
'Document': The string '//ul[#id='ui-id-1']/li/a[equals(text(),'60091
- AFCENT')]' is not a valid XPath expression.
I tried to change it to "+testData+" too instead of using '"+testData+"'
But same exception.
I tried this code too:
driver.findElement(By.xpath(".//*[#id='accountSelectContainer']/span/a/span[1]")).click();
List<WebElement> options = driver.findElements(By.xpath("//ul[#id='ui-id-1']/li"));
for (WebElement option : options) {
if(testData.equals(option.getText()))
option.click();
}
which works perfect but after this code execution , it is making my browser to wait for about 15 secs before executing next step or for quit too. i am not getting Why so ?
Please need suggestion or any ideas..
I doubt your fast attempt works perfect as xpath doesn't have equals. You would have gotten the same exception. To check for text equality use =
"//ul[#id='ui-id-1']/li/a[text()='"+testData+"']"
You can also use contains
"//ul[#id='ui-id-1']/li/a[contains(text(),'"+testData+"')]"
First: the exception you have got is because you xpath: //ul[#id='ui-id-1']/li/a[equals(text(),'60091 - AFCENT')] is not correct syntax.
Second: the code that you can run is not make your browser wait for 15s, it's just because problem about internet connection or you computer is a little slow.
actually i want to get an element with the #FindBy that is use into the Page Objects pattern.
I've 2 classes, the 1st one is my page objects named TestPage and the 2nd one is named PageSaveTest (where my tests happen and call the TestPage).
I've also tried to use the #FindBy with xpath and id.
>> This is my TestPage
import java.util.List;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class TestPage {
// get autocomplete input
#FindBy(css = "input[id*='supplierOps_input']")
private WebElement autocompleteSupplierOps;
// getter
public WebElement getAutocompleteSupplierOps() {
return autocompleteSupplierOps;
}
}
>> This is my PageSaveTest
// How i "inject" my TestPage
#Page
TestPage testpage;
[...]
// My test
WebElement autocomplete = testpage.getAutocompleteSupplierOps();
String keys = "OP";
autocomplete.sendKeys(keys); // >>>>>>> Error throwed here !
List<WebElement> listSugg = testpage.getSuggestionsSupplierOps();
Error message :
org.openqa.selenium.NoSuchElementException : Returned node was not an HTML element.
My thoughts :
I think the trouble comes from the #FindBy. But i use this example to build my TestPage and my test and this one too.
Question : Can someone explain to me how #FindBy works and be used in my example ? The documentation is really poor about Graphene.
EDIT :
I've modify my getter in TestPage (above), i've tried a simple print of the id attribute value like
public WebElement getAutocompleteSupplierOps() {
System.out.println(">>>> "+autocompleteSupplierOps.getAttribute("id"));
return autocompleteSupplierOps;
}
But still the same error, the #FindBy is f*cked up.
Another #FindBy spec to add in this issue.
Update :
I've fixed my selector but actually there is a probleme with the driver session like :
page2.getAutocompleteSupplierOps();
PAGE 1 ----------------------------------> PAGE 2
driver id:1 ----------------------------------> driver id:2
driver.showPageSource() is empty
return no element found <---------------------- driver.findElement() -> not found
I've used 3 different ways, the #FindBy, the #Drone WebDriver and finally what #Lukas Fryc suggested to me.
Instead of injection of WebElement using #FindBy, you can try using driver directly:
WebDriver driver = GrapheneContext.getProxy(); // this will be removed in Alpha5 version, use `#Drone WebDriver` instead
WebElement autocompleteSupplierOps =
driver.findElement(By.css("input[id*='supplierOps_input']"));
But it should give you the same result as #FindBy do - however it will check that the issue isn't caused by injection, but some other issue is appearing.
You might have wrong CSS selector - support of CSS selectors depends on the used browser and its version.
The node you are trying to find doesn't have to be yet in the page, you might need to wait before it will appear using Waiting API or request guards.
The best practice is usage of remote reusable session and real browser in a development - it can reveal the cause quickly.
I think that instead of using #FindBy(css ="...") you could try #FindBy(xpath="...") I find it a lot more reliable.
I'm trying to automate a task through selenium that deletes a set of database tables.
The corresponding code is
WebElement element=null;
while((element = driver.findElement(By.name("db__button"))) != null){
driver.findElement(By.name("db__button")).click();
driver.findElement(By.name("ConfirmButton")).click();
}
However I'm getting the following error:-
org.openqa.selenium.NoSuchElementException: Unable to locate element: {"method":"name","selector":"db_vaults__button"}
For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html
This runs fine as long as there are tables in the database but when there are no tables left then the GUI doesn't show any list (rightly so) and db__button is not present on the page and therefore By.name("db__button") is failing.
I guess there is something missing in this code which is trying to delete some tables in a loop.
The suggested link in the stack trace doesn't has any information.
Any Ideas?
Thanks.
You can do something like mentioned below:
try {
element = driver.findElement(By.name("db__button"));
driver.findElement(By.name("db__button")).click();
driver.findElement(By.name("ConfirmButton")).click();
} catch (NoSuchElementException e) {
}
The above code will try to find your button and in case it is not found will throw an exception.You can write code(if any) inside the catch block when the element(db_button) is not found.
There are several options. I recommend these.
Create a method or web driver extension as below an use it.
var elements = driver.FindElements(by);
return (elements.Count >=1) ? elements.First() : null;