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);
Related
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.
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.
I am using Selenium 3.4 with Java. With Chrome, everything works fine. But I need to use Firefox, and there something breaks.
I am automating the testing of a Dojo UI, and need to wait while the Dojo UI does a lot of rendering. So here is what I do, and it works just fine in Chrome. Note that an implicit wait of 20 seconds is normally set in my code.
driver.switchTo().defaultContent();
driver.switchTo().frame(driver.findElement(By.id("contentframe"))); // relying on implicit wait
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
(new WebDriverWait(driver, 120)).
until(ExpectedConditions.elementToBeClickable(By.id("some_id")));
I have simplified the code so you don't see how the implicit wait is set back to 20 seconds. When the problem happens, it does not get there, anyway. The WebDriverWait causes an exception. The exception says TypeError: can't access dead object
There is a corresponding message from inside the wait:
May 16, 2017 3:36:11 PM org.openqa.selenium.support.ui.ExpectedConditions findElement
WARNING: WebDriverException thrown by findElement(By.id:
some_id)
org.openqa.selenium.WebDriverException: TypeError: can't access dead object
There is also some JavaScript error output, apparently, by geckodriver:
JavaScript error: chrome://marionette/content/listener.js, line 1555: TypeError: can't access dead object
*************************
A coding exception was thrown and uncaught in a Task.
Full message: TypeError: can't access dead object
Full stack: find_#chrome://marionette/content/element.js:284:7
element.find/</findElements<#chrome://marionette/content/element.js:255:15
implicitlyWaitFor/</elementSearch#chrome://marionette/content/element.js:600:15
implicitlyWaitFor/<#chrome://marionette/content/element.js:627:5
implicitlyWaitFor#chrome://marionette/content/element.js:593:10
element.find/<#chrome://marionette/content/element.js:254:24
element.find#chrome://marionette/content/element.js:253:10
findElementsContent#chrome://marionette/content/listener.js:1314:19
TaskImpl_run#resource://gre/modules/Task.jsm:319:42
TaskImpl#resource://gre/modules/Task.jsm:277:3
createAsyncFunction/asyncFunction#resource://gre/modules/Task.jsm:252:14
Task_spawn#resource://gre/modules/Task.jsm:166:12
TaskImpl_handleResultValue#resource://gre/modules/Task.jsm:389:16
TaskImpl_run#resource://gre/modules/Task.jsm:327:15
TaskImpl#resource://gre/modules/Task.jsm:277:3
createAsyncFunction/asyncFunction#resource://gre/modules/Task.jsm:252:14
Task_spawn#resource://gre/modules/Task.jsm:166:12
dispatch/<#chrome://marionette/content/listener.js:186:15
*************************
*************************
A coding exception was thrown and uncaught in a Task.
Full message: TypeError: can't access dead object
Full stack: find_#chrome://marionette/content/element.js:284:7
element.find/</findElements<#chrome://marionette/content/element.js:255:15
implicitlyWaitFor/</elementSearch#chrome://marionette/content/element.js:600:15
implicitlyWaitFor/<#chrome://marionette/content/element.js:627:5
implicitlyWaitFor#chrome://marionette/content/element.js:593:10
element.find/<#chrome://marionette/content/element.js:254:24
element.find#chrome://marionette/content/element.js:253:10
findElementsContent#chrome://marionette/content/listener.js:1314:19
TaskImpl_run#resource://gre/modules/Task.jsm:319:42
TaskImpl#resource://gre/modules/Task.jsm:277:3
createAsyncFunction/asyncFunction#resource://gre/modules/Task.jsm:252:14
Task_spawn#resource://gre/modules/Task.jsm:166:12
TaskImpl_handleResultValue#resource://gre/modules/Task.jsm:389:16
TaskImpl_run#resource://gre/modules/Task.jsm:327:15
TaskImpl#resource://gre/modules/Task.jsm:277:3
createAsyncFunction/asyncFunction#resource://gre/modules/Task.jsm:252:14
Task_spawn#resource://gre/modules/Task.jsm:166:12
dispatch/<#chrome://marionette/content/listener.js:186:15
Moreover, my automatic exception processing tries to take a screenshot but that fails with the very same error. The code line is:
File snapshotTempFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
And this time the output from geckodriver is:
A coding exception was thrown and uncaught in a Task.
Full message: TypeError: can't access dead object
Full stack: capture.viewport#chrome://marionette/content/capture.js:65:7
takeScreenshot#chrome://marionette/content/listener.js:1782:14
dispatch/</req<#chrome://marionette/content/listener.js:188:22
TaskImpl_run#resource://gre/modules/Task.jsm:319:42
TaskImpl#resource://gre/modules/Task.jsm:277:3
createAsyncFunction/asyncFunction#resource://gre/modules/Task.jsm:252:14
Task_spawn#resource://gre/modules/Task.jsm:166:12
dispatch/<#chrome://marionette/content/listener.js:186:15
So, can I do anything to make this work properly? And is this something I need to raise as a geckodriver bug?
The only thing I could google out is this: https://github.com/mozilla/geckodriver/issues/614 and the only proposed solution there is driver.switchTo().defaultContent() . This might fix my screenshot routine, but the element I am waiting for is inside the content frame, so I can't use this fix for the wait.
Not sure if this will help you but when I ran into this error message, I was able to get past it by having:
driver.switchTo().defaultContent();
driver.switchTo().frame(0);
between each interaction with an element in the iframe.
Example:
driver.switchTo().frame(0);
myPage.selectElement(getCycleSummary());
driver.switchTo().defaultContent();
driver.switchTo().frame(0);
myPage.selectDisplayedElement(this.getCycleBtn());
Without the driver switches I would receive the dead object error.
It looks like the frame is reloaded with a new reference while you are waiting for the element some_id.
I would classify this issue as a bug since the error returned by the driver is not defined by the WebDriver protocol.
Your best chance to make it work is probably to implement a custom waiter to locate the frame/element and skip unhandled exceptions:
WebElement elem = waiter.Until(elementToBeClickableInFrame(By.id("contentframe"),
By.id("some_id")));
public static ExpectedCondition<WebElement> elementToBeClickableInFrame(final By locatorFrame, final By locator) {
return new ExpectedCondition<WebElement>() {
#Override
public WebElement apply(WebDriver driver) {
try {
driver.switchTo().defaultContent();
driver.switchTo().frame(driver.findElement(locatorFrame));
WebElement elem = driver.findElement(locator);
return elem.isDisplayed() && elem.isEnabled() ? elem : null;
} catch (Exception e) {
return null;
}
}
#Override
public String toString() {
return "element located by: " + locator + " in " + locatorFrame;
}
};
}
See,
There Should be a format which i am giving below:
First switch to frame. (Switch to default first in case already you are in another frame).
Perform your action (click on any element)
Switch to default content again. (if you do not switch it back, it creates problem).
driver.switchTo().defaultContent();
driver.switchTo().frame(locator or name of the frame);
driver.click(your element locator);
driver.switchTo().defaultContent();
I am pretty new to all the Automated Testing thing and recently I have been having trouble with selenium because sometimes fails finding certain input fields / buttons.
I added explicit waits for every element in the page, so the test is supposed to wait for that element to appear on screen, but sometimes randomly fails to do so. I will attach the latest error thrown by selenium in a simple test.
This is one of the tests that I am trying to run and randomly fails:
#Test
public void createTaskTest(){
generateTestEnvironmentSalesForceHomePage();
this.home.clickTasksTab();
generateTestEnvironmentTaskPage();
this.taskspage.clickNewTask();
generateTestEnvironmentNewTask();
this.newtask.setDateField("12/30/2016");
this.newtask.setCostField("1500");
this.newtask.setType("Personal Appointment");
this.newtask.setPaymentType("End of the day");
this.newtask.setDoctor("House");
this.newtask.submitTask();
Assert.assertTrue(this.newtask.checkDetailsPage());
}
Error thrown by selenium:
org.openqa.selenium.TimeoutException: Expected condition failed: waiting for visibility of element located by By.cssSelector: span.dateOnlyInput>input (tried for 130 second(s) with 500 MILLISECONDS interval)
Here is the method to find the 'missing' date input:
public void setDateField(String date){
WebDriverWait wait = new WebDriverWait(this.driver,130);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("span.dateOnlyInput>input")));
this.driver.findElement(By.cssSelector("span.dateOnlyInput>input")).sendKeys(date);
}
I need to reach the following scenario:
1) Initializing JS var with JavascriptExecutor that will indicate if some operation is done.
2) Do some ordinary manipulation with the renderer page.
3) Verify the change to the var created in point (1).
For example:
jsc.executeScript("var test = false;");
Now, some manipulation is done.
And then:
String testVal = jsc.executeScript("return test;").toString
I get the error:
org.openqa.selenium.WebDriverException: {"errorMessage":"Can't find
variable: test","request":{"headers":{"Accept":"application/json,
image/png","Connection":"Keep-Alive","Content-Length":"35","Content-Type":"application/json;
charset=utf-8","Host":"localhost:14025"},"httpVersion":"1.1","method":"POST","post":"{\"args\":[],\"script\":\"return
test;\"}","url":"/execute","urlParsed":{"anchor":"","query":"","file":"execute","directory":"/","path":"/execute","relative":"/execute","port":"","host":"","password":"","user":"","userInfo":"","authority":"","protocol":"","source":"/execute","queryKey":{},"chunks":["execute"]},"urlOriginal":"/session/7e2c8ab0-b781-11e4-8a54-6115c321d700/execute"}}
When i'm running them in the same execution, it works correctly.:
String testVal = jsc.executeScript("var test = false; return test;").toString;
From JavascriptExecutor doc i found the explanation i needed:
Within the script, use document to refer to the current document. Note
that local variables will not be available once the script has
finished executing, though global variables will persist.
What is my alternative/workaround to this?
Not sure what is the motivation behind it, but you can use a globally available window object:
jsc.executeScript("window.test = false;");
String testVal = jsc.executeScript("return window.test;").toString
It might also be a use case for executeAsyncSript(), see:
Understanding execute async script in Selenium