Test passed but action did not happen selenium webdriver + testng - java

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:
public void clickSaveButton(WebDriver driver){
Configuration.clickfoundElement(By.id(conf.get("saveButton")), driver);
}
to this:
public void clickSaveButton(WebDriver driver) {
WebDriverWait doWait = new WebDriverWait(driver, 15 , 100);
WebElement elementToClick = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(conf.get("saveButton"))));
elementToClick.click();
}
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:
Always find the element using your locator every time you use it.
Use the PageFactory class in support.
I personally use PageFactories in all my test code, a basic example would look like this:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.support.PageFactory;
public class LoginExample {
#FindBy(how = How.ID, using = "username")
private WebElement usernameField;
#FindBy(how = How.ID, using = "password")
private WebElement passwordField;
#FindBy(how = How.ID, using = "login")
private WebElement submitButton;
public LoginExample(WebDriver driver) {
PageFactory.initElements(driver, this);
}
public void enterCredentialsAndSubmitForm(String username, String password) {
usernameField.clear();
usernameField.sendKeys(username);
passwordField.clear();
passwordField.sendKeys(password);
submitButton.click();
}
}
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.

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 of driver.findElement() and use some assertions. For example try to check if the button is really there.

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:
By saveButton = By.id("saveButton");
public By getSaveButton() {
waitForElementPresent(saveButton, 15);
return driver.findElement(saveButton);
}
public void waitForElementPresent(final By locator, int timeout) {
ExpectedCondition e = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return driver.findElements(locator).size() > 0;
}
};
WebDriverWait wait = new WebDriverWait(driver, timeout);
wait.until(e);
}
The expected condition can be changed to desired condition.
Then in your test, click the savebutton:
page.getSaveButton().click();
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.

Related

xpath tested and correct but i recieve the error : no such element: Unable to locate element

My Xpath is correct & no iFrame and I can locate element in Chrome console but my program still fails. I have used explicit wait also.
no such element: Unable to locate element: {"method":"xpath","selector":"//*[contains(#ng-click,'authenticationCtrl.onSubmitMage()')]"}
i tested my xpath with Try xpath and it works but when i compile my code i still recieve the error
the page Object :
package com.orange.pageObject;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.CacheLookup;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class MageReferentiel {
WebDriver webdriver;
public MageReferentiel(WebDriver rwebDriver) {
webdriver = rwebDriver;
PageFactory.initElements(webdriver, this);
}
#FindBy(xpath = "//*[contains(#ng-click,'authenticationCtrl.onSubmitMage()')]")
#CacheLookup
WebElement connexion;
public void clickConnexion() {
connexion.click();
}
The step definition :
#When("l utilisateur choisi le referentiel")
public void l_utilisateur_choisi_le_referentiel() throws Exception {
mr.clickConnexion();
Thread.sleep(3000);
}
im looking to click in button
thanks
I agree with #Prophet, it could be because of some JS call the button, //*[contains(#ng-click,'authenticationCtrl.onSubmitMage()')] changing it's state to some other state. so what we can do about is that, to try with different locator.
such as :
//button[#translate ='LOGIN']
and see if that works, even if it doesn't try changing it to css.
Since ng elements are going very well with Protractor (Angular), better to use in Protractor in that case, so it suppose to be something like element(by.click('authenticationCtrl.onSubmitMage').click();
I guess the ng-click attribute value is dynamically updated on the page, so when you trying to access that element this element is changed, not having it's initial state.
Instead of locator you are using try this XPath:
//button[contains(text(),'Connexion')]
or this
//button[#translate='LOGIN']
The second element with this locator will be
(//button[#translate='LOGIN'])[2]
Looks like the element is not rendering on time. Try using explicit wait. Following gif shows how it is done using Cucumber:
https://nocodebdd.live/waitime-cucumber
Same been implemented using NoCodeBDD:
https://nocodebdd.live/waittime-nocodebdd
Disclaimer: I am the founder of NoCodeBDD so BDD automation can be achieved in minutes and without code. Through NoCodeBDD you could automate majority of the scenarios and it allows you to write your own code if there are edge cases. Would love to get some feedback on the product from the community. Basic version (https://www.nocodebdd.com/download) is free to use.
The default wait strategy in selenium is just that the page is loaded.
You've got an angular page so after your page is loaded there is a short delay while the JS runs and the element is finally ready in the DOM - this delay is causing your script to fail.
Check out the selenium docs here for wait strategies .
Your options are:
An explicit wait - This needs to be set per element you need to sync on.
I note you say you've used an explicit wait - but where? - It's not present in the code you shared and it might be that you've used the wrong expected condition.
Try something like this:
WebElement button = new WebDriverWait(rwebDriver, Duration.ofSeconds(10))
.until(ExpectedConditions.elementToBeClickable(By.xpath("//*[contains(#ng-click,'authenticationCtrl.onSubmitMage()')]")));
button.click();
Use an implicit wait - you only use this once when you initialise driver and it will wait the specified amount of time for all element interaction.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
There are other reasons that selenium returns a NoSuchElement but synchronisation is the most common one. Give the wait a go and let me know if it is still giving you trouble.
Through discussion in the comments, the trouble is an iframe
If you google it - there are lots of answers out there.
With frames, you need to identify it, switch to it, do your action(s) then switch back:
//find and switch - update the By.
driver.switchTo().frame(driver.findElement(By.id("your frame id")));
//actions go here
//back to normal
driver.switchTo().defaultContent();

element not interactable exception in selenium web automation

In the below code i cannot send password keys in the password field, i tried clicking the field, clearing the field and sending the keys. But now working in any of the method. But its working if i debug and test
public class TestMail {
protected static WebDriver driver;
protected static String result;
#BeforeClass
public static void setup() {
System.setProperty("webdriver.gecko.driver","D:\\geckodriver.exe");
driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
}
#Test
void Testcase1() {
driver.get("http://mail.google.com");
WebElement loginfield = driver.findElement(By.name("Email"));
if(loginfield.isDisplayed()){
loginfield.sendKeys("ragesh#gmail.in");
}
else{
WebElement newloginfield = driver.findElemnt(By.cssSelector("#identifierId"));
newloginfield.sendKeys("ragesh#gmail.in");
// System.out.println("This is new login");
}
driver.findElement(By.name("signIn")).click();
// driver.findElement(By.cssSelector(".RveJvd")).click();
driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
// WebElement pwd = driver.findElement(By.name("Passwd"));
WebElement pwd = driver.findElement(By.cssSelector("#Passwd"));
pwd.click();
pwd.clear();
// pwd.sendKeys("123");
if(pwd.isEnabled()){
pwd.sendKeys("123");
}
else{
System.out.println("Not Enabled");
}
Try setting an implicit wait of maybe 10 seconds.
gmail.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Or set an explicit wait. An explicit waits is code you define to wait for a certain condition to occur before proceeding further in the code. In your case, it is the visibility of the password input field. (Thanks to ainlolcat's comment)
WebDriver gmail= new ChromeDriver();
gmail.get("https://www.gmail.co.in");
gmail.findElement(By.id("Email")).sendKeys("abcd");
gmail.findElement(By.id("next")).click();
WebDriverWait wait = new WebDriverWait(gmail, 10);
WebElement element = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.id("Passwd")));
gmail.findElement(By.id("Passwd")).sendKeys("xyz");
Explanation: The reason selenium can't find the element is because the id of the password input field is initially Passwd-hidden. After you click on the "Next" button, Google first verifies the email address entered and then shows the password input field (by changing the id from Passwd-hidden to Passwd). So, when the password field is still hidden (i.e. Google is still verifying the email id), your webdriver starts searching for the password input field with id Passwd which is still hidden. And hence, an exception is thrown.
"element not interactable" error can mean two things :
a. Element has not properly rendered:
Solution for this is just to use implicit /explicit wait
Implicit wait :
driver.manage().timeouts().implicitlyWait(50, TimeUnit.SECONDS);
Explicit wait :
WebDriverWait wait=new WebDriverWait(driver, 20);
element1 = wait.until(ExpectedConditions.elementToBeClickable(By.className("fa-stack-1x")));
b. Element has rendered but it is not in the visible part of the screen:
Solution is just to scroll till the element. Based on the version of Selenium it can be handled in different ways but I will provide a solution that works in all versions :
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].scrollIntoView(true);", element1);
Suppose all this fails then another way is to again make use of Javascript executor as following :
executor.executeScript("arguments[0].click();", element1);
If you still can't click , then it could again mean two things :
1. Iframe
Check the DOM to see if the element you are inspecting lives in any frame. If that is true then you would need to switch to this frame before attempting any operation.
driver.switchTo().frame("a077aa5e"); //switching the frame by ID
System.out.println("********We are switching to the iframe*******");
driver.findElement(By.xpath("html/body/a/img")).click();
2. New tab
If a new tab has opened up and the element exists on it then you again need to code something like below to switch to it before attempting operation.
String parent = driver.getWindowHandle();
driver.findElement(By.partialLinkText("Continue")).click();
Set<String> s = driver.getWindowHandles();
// Now iterate using Iterator
Iterator<String> I1 = s.iterator();
while (I1.hasNext()) {
String child_window = I1.next();
if (!parent.equals(child_window)) {
driver.switchTo().window(child_window);
element1.click()
}
Please try selecting the password field like this.
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement passwordElement = wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#Passwd")));
passwordElement.click();
passwordElement.clear();
passwordElement.sendKeys("123");
you may also try full xpath, I had a similar issue where I had to click on an element which has a property javascript onclick function. the full xpath method worked and no interactable exception was thrown.
In my case the element that generated the Exception was a button belonging to a form. I replaced
WebElement btnLogin = driver.findElement(By.cssSelector("button"));
btnLogin.click();
with
btnLogin.submit();
My environment was chromedriver windows 10
In my case, I'm using python-selenium.
I have two instructions. The second instruction wasn't able to execute.
I put a time.sleep(1) between two instructions and I'm done.
If you want you can change the sleep amount according to your need.
I had the same problem and then figured out the cause. I was trying to type in a span tag instead of an input tag. My XPath was written with a span tag, which was a wrong thing to do. I reviewed the Html for the element and found the problem. All I then did was to find the input tag which happens to be a child element. You can only type in an input field if your XPath is created with an input tagname
I'm going to hedge this answer with this: I know it's crap.. and there's got to be a better way. (See above answers) But I tried all the suggestions here and still got nill. Ended up chasing errors, ripping the code to bits. Then I tried this:
import keyboard
keyboard.press_and_release('tab')
keyboard.press_and_release('tab')
keyboard.press_and_release('tab') #repeat as needed
keyboard.press_and_release('space')
It's pretty insufferable and you've got to make sure that you don't lose focus otherwise you'll just be tabbing and spacing on the wrong thing.
My assumption on why the other methods didn't work for me is that I'm trying to click on something the developers didn't want a bot clicking on. So I'm not clicking on it!
I got this error because I was using a wrong CSS selector with the Selenium WebDriver Node.js function By.css().
You can check if your selector is correct by using it in the web console of your web browser (Ctrl+Shift+K shortcut), with the JavaScript function document.querySelectorAll().
If it's working in the debug, then wait must be the proper solution.
I will suggest to use the explicit wait, as given below:
WebDriverWait wait = new WebDriverWait(new ChromeDriver(), 5);
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#Passwd")));
I came across this error too. I thought it might have been because the field was not visible. I tried the scroll solution above and although the field became visible in the controlled browser session I still got the exception. The solution I am committing looks similar to below. It looks like the event can bubble to the contained input field and the end result is the Selected property becomes true.
The field appears in my page something like this.
<label>
<input name="generic" type="checkbox" ... >
<label>
The generic working code looks more or less like this:
var checkbox = driver.FindElement(By.Name("generic"), mustBeVisible: false);
checkbox.Selected.Should().BeFalse();
var label = checkbox.FindElement(By.XPath(".."));
label.Click();
checkbox.Selected.Should().BeTrue();
You'll need to translate this to your specific language. I'm using C# and FluentAssertions. This solution worked for me with Chrome 94 and Selenium 3.141.0.
I had to hover over the element first for the sub-elements to appear. I didn't take that into account at first.
WebElement boardMenu = this.driver.findElement(By.linkText(boardTitle));
Actions action = new Actions(this.driver);
action.moveToElement(boardMenu).perform();
Another tip is to check that you are having one element of that DOM. Try using Ctrl+F when inspecting the web page and check your xpath there; it should return one element if you are going with the findElement method.

Explicit Wait PageFactory #Findby

I have this wait command in Java with a css locator, and then clicks on it.
new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button.md-primary.md-raised.md-button.md-default-theme"))).click();
Now I turned that locator into a pagefactory object which is lp.btnSignIn() what would be the proper way to issue this explicit wait and then click? Can I still use expected conditions?
This is my PageFactory Code:
#FindBy(css="button.md-primary.md-raised.md-button.md-default-theme")
WebElement btnSignIn;
public WebElement btnSignIn() {
return btnSignIn;
}
Solved by changing to VisibilityOf:
new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOf(lp.btnSignIn())).click();
Be careful though as this checks if the element is visible, which it might not be, but it is still in a DOM.
It simply depends on what your lp.btnSignIn() method is returning.
Quoting from the selenium documentation here
public static ExpectedCondition<WebElement> presenceOfElementLocated(By locator)
An expectation for checking that an element is present on the DOM of a page. This does not necessarily mean that the element is visible.
Parameters:
locator - used to find the element
Returns:
the WebElement once it is located
Hence you could use lp.btnSignIn() only if it's returning the css locater in place of WebElement
Hence your btnSignIn() methos would something like this:
public static Locater btnSignIn() {
return By.cssSelector("button.md-primary.md-raised.md-button.md-default-theme");
}
And now your could use the Expected conditions as below:
new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(lp.btnSignIn())).click()`;

How do I print using getText from a page object model with log4j?

I am coding some automated tests using the Selenium Webdriver in Netbeans. I have a pretty simple test, and I am implementing page objects. My trouble is here:
I previously had this code:
//Click the Timing Parts subcategory
WebElement PartSubcategory = driver.findElement(By.xpath("//label[contains(.,'Timing Parts & Camshafts')]"));
PartSubcategory.click();
logger.info("Found subcategory: "+PartSubcategory.getText());
And, after implementing page object model, it looks like this.
Page object:
public class findPartSubcategory {
private static WebElement element = null;
//Click the Timing Parts subcategory
public static WebElement PartSubcategory(WebDriver driver)
{
element = driver.findElement(By.xpath("//label[contains(.,'Timing Parts & Camshafts')]"));
return element;
}
}
Test code:
//Click the Timing Parts subcategory
findPartSubcategory.PartSubcategory(driver).click();
logger.info("Found subcategory: "+findPartCategory.getText());
So, the compile error is in getText(), "Cannot find symbol method getText()". I am guessing it's because I am not printing out a properly declared variable, but a page object class.
So how do I get to print what it found for that page object? Yes, I am using log4j ver. 1
Thanks!
You have a compilation error. Trying to reference findPartCategory.PartCategory which does not exist.
Change
findPartCategory.PartCategory(driver).click();
To
findPartCategory.PartSubcategory(driver).click();
You are also trying to call getText() on your findPartSubcategory class and I assume you want to call that on the WebElement.
WebElement element = findPartSubcategory.PartSubcategory(driver);
element.click();
logger.info("Found subcategory: "+ element.getText());
That should achieve the same functionality as your old code.

Selenium with WebDriver - wait

I have a Selenium test suite in Java, using WebDriver.
I have a generic wait function in place that takes a CSS selector and wait for the element to become present and visible before moving on to assertions, using WebDriverWait. Now, though, I want to have something that waits for all elements of a certain type, that are in the DOM to not be visible anymore, before proceeding. The exact example is that I have a number of images being loaded and I want to wait for their loading spinners to disappear before continuing. Haven't been able to find something that would solve this for me yet, so posting it here.
Any clues?
Thanks!
public void waitForPageToLoad(WebDriver webDriver, String cssToWaitFor) {
WebDriverWait wait = new WebDriverWait(webDriver, 20);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(cssToWaitFor)));
}
Check the invisibilityOfElementLocated expected condition. Reference. From the doc:
invisibilityOfElementLocated
public static ExpectedCondition<java.lang.Boolean> invisibilityOfElementLocated(By locator)
An expectation for checking that an element is either invisible or not present on the DOM.
Parameters:
locator - used to find the element
So you could use it like:
public void waitForInvisibility(WebDriver webDriver, String cssToWaitFor) {
WebDriverWait wait = new WebDriverWait(webDriver, 20);
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector(cssToWaitFor)));
}
Alternatively you can look into public static ExpectedCondition<java.lang.Boolean> not(ExpectedCondition<?> condition), which by the doc does:
An expectation with the logical opposite condition of the given
condition.

Categories

Resources