I'm quite new in selenium webdriver, I'm using 2.31 version, testng 6.8 and fire tests on IE 8. I'm writting my tests in this scheme: I have test classes where i have methods with testng @Test annotation. It looks like this:
@Test(description="click Save Button ", dependsOnMethods = { "edit form" })
public void clickSaveButton(ITestContext context) {
page.clickSaveButton(driver);
}
Then, as you can see I have page class where I store elements ids, xpaths etc. It lokks like this:
public void clickSaveButton(WebDriver driver){
Configuration.clickfoundElement(By.id(conf.get("saveButton")), driver);
}
conf is object that represents properties file. At last I have Configuration class where I do somethink like this:
public static void clickfoundElement(By by, WebDriver driver){
int attempts = 0;
while(attempts < 10) {
try {
driver.findElement(by).click();
break;
} catch(NoSuchElementException e) {
System.out.println("NoSuchElementException");
Reporter.log("NoSuchElementException<br/>");
if(attempts==9){
throw(e);
}
}
catch(StaleElementReferenceException e) {
System.out.println("StaleElementReferenceException");
Reporter.log("StaleElementReferenceException<br/>");
if(attempts==9){
throw(e);
}
}}
That prevents me from having NoSuchElementException and StaleElementReferenceException and works quite fine.
My first question is if this approach is correct? Second and the most important question is that from time to time I have following problem:
Testng says that"clickSaveButton" (in final report) is passed, but in fact clickSaveButton action did not happen (I can see it watching my browser during test). At the end in next test I have "NoSuchElementException" (especially when next test is not about clicking in something but only about getting text from html component). Of course this NoSuchElementException happens because there is really no element I am looking for (because last test action did not happen so I am still at the previous site, without this element) Can you tell me why this situation happen (what is important not always but only sometimes) and how to prevent it?
Thanks in advance.
I would suggest you use a explicit wait to wait for the element to be visible. This is done with a WebDriverWait, this would change your code from this:
to this:
It also completely gets rid of your clickfoundElement() method. This will not stop StaleElementExceptions from happening. A StaleElementException is caused by the DOM being modified and the element you want to interact with being destroyed and then recreated.
To avoid StaleElementExceptions you have a couple of options:
I personally use PageFactories in all my test code, a basic example would look like this:
The @FindBy annotation effectively creates a proxy WebElement, every time you use this WebElement the locator specified in the annotation will be used to find it again, so no more StaleElementException errors (Unless you are so unlucky that element changes in the couple of ms between Selenium finding it and then performing an action on it).
In the example above I have kind of cheated by initialising the page factory in the constructor, you don't have to do it this way but I find it is generally a nice and easy way to do things.
For more information about page factories jave a look at the Selenium Wiki.
Thank you all for your time. It turned out that my problem occured because I had something like popup winowow in application I was testing (richFaces rich:modalPanel to be exact). That cause DOM "behind" this popup was still visible, but elements in it could no be clicked because of it. What solved my problem was just waiting a little bit longer for element to be clickable via ExpectedConditions.elementToBeClickable(By by) which made sure my popup disapeared after closing it and clicking another element is possible. That makes Ardesco answer the best. Thank you one more time.
I would probably solve the issue by creating a By variable, then passing that variable to the following methods in your page object like this:
The expected condition can be changed to desired condition. Then in your test, click the savebutton:
As for the click() not happening on IE8, I've seen similar behaviour with RemoteWebDriver. Make sure you have correct zoom settings in your webdriver since this seems to be one reason for click() not being fired correctly. Some people seems to have solved this with clicking several times which seems like a dirty solution. My solution for IE7,8 & 9 click() was to execute the actual onclick javascript function with
((JavaScriptExecutor)driver).executeScript("onclickFunction();");
This was only acceptable since the tests main assert was not that the javascript function should be called onclick but to test that the javascript function dynamically added elements to the page.
Regarding StaleElementReferenceException, I would instantiate a new page object in each test, this way you won't get stale elements and you start from a clean state. In JUnit4 this would be in your @Before method.
You are not incrementing attempts variable in while loop. I do not know a proper approach but I would not use while loop to search for an element. Maybe you should try to use
driver.findElements()
instead ofdriver.findElement()
and use some assertions. For example try to check if the button is really there.