Can I assert an element that is not present? I want to assert that the element "textarea" is not present on the site.
try {
assertFalse(isElementPresent(By.cssSelector("textarea")));
} catch (Error e) {
verificationErrors.append(e.toString());
System.out.println(verificationErrors);
}
private boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}
The code in your question ought to work.
Another method is to call driver.findElements instead of driver.findElement (note the added s). Instead of throwing a NoSuchElementException, driver.findElements will return an empty list if there are no matches. From there, you just have to assert that the size of the returned list is zero.
Method #1
import junit.framework.Assert;
if(!isElementPresent(By.cssSelector("textarea")))
{
System.out.println("Text Not Available");
} else
{
Assert.fail();
}
Method #2
In your case, please go with negative use case given below
positive case
import junit.framework.Assert;
boolean b = driver.getPageSource().contains("your text");
Assert.assertTrue(b);
negative case
import junit.framework.Assert;
boolean b = driver.getPageSource().contains("your text");
Assert.assertFalse(b);
There are numerous ways to do this. The above is few :)
Method #1 is highly suggested!
Related
I want to use Expected Condition interface and implement apply method as follows in WebDriver sampler. This script for loading multiple charts on single page but it give me error
javax.script.ScriptException: In file: inline evaluation of:
import java.io.File; import org.apache.commons.io.FileUtils;
import openqa.selen . . . '' Encountered "( new ExpectedCondition <"
at line 22, column 19.in inline evaluation of: ``
import java.io.File; import org.apache.commons.io.FileUtils;
import openqa.selen . . . '' at line number 22.”
Environment:
JMeter : version 5
Java : java version "1.8.0_181"
Can anyone please help? This is my code:
WDS.sampleResult.sampleStart();
List loading =WDS.browser.findElements(By.xpath("//img[#class='loading']"));
WDS.log.info("Total "+loading.size());
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver WDS.browser) {
Iterator eleIterator =WDS.browser.findElements(By.xpath("//img[#class='loading']")).iterator();
while (eleIterator.hasNext()) {
boolean displayed = false;
try {
displayed = eleIterator.next().isDisplayed();
// System.out.println("TEST = "+displayed);
}
catch (NoSuchElementException e)
{
displayed = false;
}
catch (StaleElementReferenceException e)
{
displayed = false;
}
if (displayed) {
// return false even if one of them is displayed.
return false;
}
}
//this means all are not displayed/invisible
return true;
}
});
WDS.sampleResult.sampleEnd();
I have been working with GEB and selenium for some time now, and many a time I have run into the dreaded stale element exception because one of the pages I have to test loads dynamically, thus inducing the stale element exception.
I have come very close to creating a catch all solution to the stale element exception but alas not close enough which is why I need help.
My solution was to override the NonEmptyNavigator class that comes with GEB. I am going to show my click() method as an example:
class NonEmptyNavigator extends geb.navigator.NonEmptyNavigator {
def NonEmptyNavigator() {
super()
}
NonEmptyNavigator(Browser browser, Collection<? extends WebElement> contextElements) {
super(browser, contextElements)
}
//overridden click method (all of the methods are overridden though
Navigator click(count = 0){
if (count >= 60) {
return super.click()
}
else{
try{
return super.click()
}
catch (StaleElementReferenceException s) {
def oData = this.toString()
def matcher = Pattern.compile("-> ([^:]+): (.*)]").matcher(oData) //Parses out the xPath
matcher.find() //Again more Parsing
def newXpath = matcher.group(2) //final Parsing step
newNav = browser.$(By.xpath(newXpath)) //create a new NonEmptyNavigator from the Stale Navigator's xpath
return newNav.click(count + 1) //attempt to click the new Navigator
}
}
}
}
Now you might be thinking "Wow this is a really good solution" (and it is) but there are instances where this doesn't work, and I am not sure how to overcome. Let me give an example.
If I do something like this (simplified for readability):
class SomePage extends Page{
static content = {
table(required: false) {$(By.xpath("//table/tbody"))}
}
//assume this method gets called in a test script
def someMethod(){
table.click() //assume this throws a StaleElementException
}
}
Referencing my overridden method above, oData.toString() ends up being something like: "[[[ChromeDriver: chrome on XP (2cd0a7132456fa2c71d1f798ef32c234)] -> xpath: //table/tbody]]"
as you can see I am able to extract the xpath and create a new navigator object which is great.
Where I run into problems is when faced with a situation like this:
class SomePage extends Page{
static content = {
table(required: false) {$(By.xpath("//table/tbody"))}
}
//assume this method gets called in a test script
def someMethod(){
table.children().getAt(1).children().getAt(2).click() //assume this throws a StaleElementException
}
}
When executing the click() throws a stale element, oData.toString() appears like this:
"[[[[[ChromeDriver: chrome on XP (2cd0a7132456fa2c71d1f798ef32c234)] -> xpath: //table/tbody]] -> xpath: child::*]] -> xpath: child::*]]"
As you can see there is some information showing that I am currently trying to access the child of a child node, but I no longer have the reference I need to redefine that specific element. I don't have the index of the specific child (or children) I want.
I am wondering if there is any way I can obtain that information given my current framework. I would also be open to other ideas and suggestions.
All in all I am essentially looking to create a catch all solution to the StaleElementException. I think I am pretty close and need a little nudge to get over the final hump.
I was able to figure this out on my own. and now I no longer get the StaleElementReferenceException. I did some more overriding of the NonEmptyNavigator and EmptyNavigator classes. I added in a custom ArrayList field called children. whenever getAt() is called the index of the child being accessed is stored the in the children array. all subsequent calls will pass the children array "down the chain" so that the index can be used when and if the stale element appears. bellow I will show you my code. to save space I only have the click method shown but I did end up overriding a majority of the methods in this class.
class NonEmptyNavigator extends geb.navigator.NonEmptyNavigator {
public children = [];
def NonEmptyNavigator() {
super()
}
NonEmptyNavigator(Browser browser, Collection<? extends WebElement> contextElements) {
super(browser, contextElements)
}
def ogClick(){
ensureContainsSingleElement("click")
contextElements.first().click()
this
}
NonEmptyNavigator click(count=0) {
if (count >= 60) {
return ogClick()
} else {
try {
return ogClick()
}
catch (StaleElementReferenceException s) {
println("Click StaleElement was caught this many times = ${count + 1}")
def oData = this.toString()
println("attempting to parse this string's xpath")
println(oData)
def matcher = Pattern.compile("-> ([^:]+): (.*)]").matcher(oData);
matcher.find()
def orgXpath = matcher.group(2)
def type = matcher.group(1)
println("original XPath")
println(orgXpath)
def newNav
def numberOfChildren = StringUtils.countMatches(orgXpath, "-> xpath: child::*")
if(!(numberOfChildren>0)){
try{
if (type=="css") {
newNav = (NonEmptyNavigator) browser.$(orgXpath)
newNav.children.addAll(this.children)
return newNav.click(count + 1)
} else if (type=="xpath") {
newNav = (NonEmptyNavigator) browser.$(By.xpath(orgXpath))
newNav.children.addAll(this.children)
return newNav.click(count + 1)
} else {
return ogClick()
}
}
catch(Throwable t){
println("Unable to create new navigator from the stale element")
return ogClick()
}
}
else{
println("this had a child")
println("number of children on record: ${children.size()}")
def newXpath = orgXpath.substring(0, orgXpath.indexOf("]]"))
children.each{
newXpath = newXpath + "/child::*[${it+1}]"
}
println("New Xpath here")
println(newXpath)
newNav = browser.$(By.xpath(newXpath))
if(!newNav.isEmpty()){
newNav = (NonEmptyNavigator) newNav
}
else{
newNav = (EmptyNavigator) newNav
}
newNav.children.addAll(this.children)
return newNav.click(count + 1)
}
}
catch (Throwable t) {
def loseOfConnection = $(By.xpath("<REDACTED>"))
def reconnect = $(By.xpath("<REDACTED>"))
if(loseOfConnection.displayed||reconnect.displayed){
println("Loss Of Connection waiting ${count} out of 60 seconds to regain connection")
Thread.sleep(1000)
return this.click(count+1)
}
else{
return ogClick()
}
}
}
}
NonEmptyNavigator addChild(index){
println("a child was stored")
this.children << index
return this
}
NonEmptyNavigator getAt(int index){
println("getAt was called")
this.navigatorFor(Collections.singleton(getElement(index))).addChild(index)
}
NonEmptyNavigator navigatorFor(Collection<WebElement> contextElements) {
println("navigateFor was called")
def answer = browser.navigatorFactory.createFromWebElements(contextElements)
if(answer.isEmpty()){
answer = (EmptyNavigator) answer
}
else{
answer = (NonEmptyNavigator) answer
}
answer.children.addAll(this.children)
return answer
}
}
I believe this is the best way to suppress the StaleElementReferenceException if you wish to do so. Most people will say that the Exception should not be suppressed, but I KNOW for sure that in this case I do not care about the Exception and this is how to stop it from ending your tests. hope you enjoy.
Checkbox function: Using below function, I want to select a checkbox and want to skip it if already selected. But isSelected() is not working, neither clear() nor isEnabled() is working.
Maybe this help you understand more: Besides 'requiredId', there is also a class that appears only when checkbox is selected say 'requireIdClassName').
requiredId="checkbox_id";
public void clickRequiredId() {
if (helper.isElementPresent(helper.locateById(requiredId)) == true) {
if (!helper.findElementById(requiredId).isSelected()) {
helper.findElementById(requiredId).click();
}
}
}
isElementPresent:
public boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}
locateById:
public By locateById(String element) {
return By.id(element);
}
findElementById:
public WebElement findElementById(String element) {
waitForElement(locateById(element), 10, element);
return driver.findElement(By.id(element));
}
getAttribute methods returns the attribute value or null if it isn't set. You can use it to determine if requireIdClassName appeared
public void clickRequiredId() {
if (helper.isElementPresent(helper.locateById(requiredId)) == true) {
if (helper.findElementById(requiredId).getAttribute("class") == null) {
helper.findElementById(requiredId).click();
}
}
}
Try this :
WebElement checkBox = driver.findElement(By.id("requiredId"));
boolean checkedState = checkBox.getAttribute("checked") != null;
if (desiredCheckState != checkedState) {
checkBox.click();
}
When checking to see if a price is given on a webpage, I don't want to check the exact value (as that's subject to change), I first want to check that the page object exists (no error, etc.) and then that it's returning a numerical value.
Is this possible?
With C#
private IWebElement priceElement = driver.FindElement(By.Id("price_value"));
public bool PriceObjectValidation()
{
decimal outDecim;
try
{
string str = priceElement.Text;
bool isDecimal = decimal.TryParse(str, out outDecim);
return isDecimal;
}
catch (NoSuchElementException e)
{
throw new Exception("Price element is not found");
}
catch (FormatException)
{
return false;
}
}
In your Test Script you can use
Assert.True(PriceObjectValidation(), "Price element is not numeric value");
In Selenium 2 I want to ensure that an element on the page that the driver has loaded does not exist. I'm including my naive implementation here.
WebElement deleteLink = null;
try {
deleteLink = driver.findElement(By.className("commentEdit"));
} catch (NoSuchElementException e) {
}
assertTrue(deleteLink != null);
Is there a more elegant way that basically verifies to assert that NoSuchElementException was thrown?
If you are testing using junit and that is the only thing you are testing you could make the test expect an exception using
#Test (expected=NoSuchElementException.class)
public void someTest() {
driver.findElement(By.className("commentEdit"));
}
Or you could use the findElements method that returns an list of elements or an empty list if none are found (does not throw NoSuchElementException):
...
List<WebElement> deleteLinks = driver.findElements(By.className("commentEdit"));
assertTrue(deleteLinks.isEmpty());
...
or
....
assertTrue(driver.findElements(By.className("commentEdit")).isEmpty());
....
You can use this:
Boolean exist = driver.findElements(By.whatever(whatever)).size() == 0;
If it doesn't exist will return true.
I split out page classes so I don't have to define elements more than once. My nunit and mbunit test classes call those page classes. I haven't tried this out yet but this is how I'm thinking about doing it so I can use .exists() like I did with WatiN.
Extension Class:
public static class ExtensionMethods
{
public static IWebElement ElementById(this IWebDriver driver, string id)
{
IWebElement e = null;
try
{
e = driver.FindElement(By.Id(id));
}
catch (NoSuchElement){}
return e;
}
public static bool Exists(this IWebElement e)
{
if (e == null)
return false;
return true;
}
}
Page Class:
public IWebElement SaveButton { get { try { return driver.ElementById("ctl00_m_m_body_body_cp2_btnSave")); } }
Test Class:
MyPageClass myPageClass = new MyPageClass(driver);
if (myPageClass.SaveButton.Exists())
{
Console.WriteLine("element doesn't exist");
}
You can retrieve a list of elements by using driver.findElements("Your elements") and then search for the element. if the list doesn't contains the element you got yourself your desired behavior :)
If you're using the Javascript API, you can use WebElement.findElements(). This method will return a Promise with an array of found elements. You can check the length of the array to ensure no items were found.
driver.findElements(By.css('.selector')).then(function(elements) {
expect(elements.length).to.equal(0)
})
I'm using Chai assertion library inside the Promise's callback to expect a certain value.
Reference: https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebElement.html
Best solution
protected boolean isElementPresent(WebElement el){
try{
el.isDisplayed();
return true;
}
catch(NoSuchElementException e){
return false;
}
}
public boolean exist(WebElement el){
try {
el.isDisplayed();
return true;
}catch (NoSuchElementException e){
return false;
}
}
if(exist(By.id("Locator details"))==false)
or
WebElement el= driver.findElementby(By.locator("locator details")
public boolean exists(WebElement el)
try{
if (el!=null){
if (el.isDisplayed()){
return true;
}
}
}catch (NoSuchElementException e){
return false;
}
}
Using webdriver find_element_xxx() will raise exception in my code and take us the waiting time of implicit/explicit webdriver wait.
I will go for DOM element check
webdriver.execute_script("return document.querySelector('your css class')")
p.s.
Also found similar discussion on our QA-main sister site here
For full check for visibility+existence
# check NOT visible the :aftermeet and :viewintro
# ! . . ! !offsetWidth to check visible in pure js ref. https://stackoverflow.com/a/20281623/248616
css='yourcss'; e=wd.execute_script(f"return document.querySelector('{css}').offsetWidth > 0") ; assert not e
# check NOT exists :viewintro
css='yourcss'; e=wd.execute_script(f"return document.querySelector('{css}')") ; assert not e
Use assertFalse :)
assertFalse(isElementPresent(By.className("commentEdit")));