I am creating a script that involved searching for a record and then updating the record. On the search screen, the user has the option of viewing advanced search options. To toggle showing or hiding advanced search is controlled by one button.
<a title="Searches" href="javascript:expandFilters()"><img border="0" align="absmiddle" alt="Advanced" src="****MASKED URL****"></a>
The only difference between the properties of the search button when it is showing or hiding the advanced search is the img src:
When advanced search is hidden the IMG src ends with "/Styles/_Images/advanced_button.jpg", when advanced search is visible, the IMG src ends with "/Styles/_Images/basic_button.png"
When I open the page, sometimes the Advanced search options are showing, sometimes they aren't. The value that I want to search on appears in the Advanced section, so for my script to work I have added an IF statement.
<input type="text" value="" maxlength="30" size="30" name="guiSystemID">
The IF statement looks for the fields that I need to enter data into, and if the field does not exist then that would indicate that the Advanced options are not visible I need to click on the button to expand the search option.
I created the following IF statement.
if (!driver.findElement(By.name("guiSystemID")).isDisplayed()) {
driver.findElement(By.cssSelector("img[alt='Advanced']")).click();
}
When I run the script and the Advanced search is expanded then the script runs successfully. However, when I run the script and the Advanced search is not expanded, the script fails, advising me that it could not find the object "guiSystemID". This is frustrating because if it can't find it then I want the script to continue, entering into the True path of the IF statement.
Has anyone got any suggestions about how else I could assess if the field is appearing without having the script fail because it can't find the field.
Thanks in advance
Simon
I might be late in answering this, but it might help someone else looking for the same.
I recently faced a similar problem while working with isDisplayed(). My code was something like this
if(driver.findElement(By.xpath(noRecordId)).isDisplayed() )
{
/**Do this*/
}
else
{
/**Do this*/
}
This code works pretty well when the element that isDisplayed is trying to find is present. But when the element is absent, it continues looking for that and hence throws an exception "NosuchElementFound". So there was no way that I could test the else part.
I figured out a way to work with this(Surround the {if, else} with try and catch block, say something like this.
public void deleteSubVar() throws Exception
{
try
{
if(driver.findElement(By.xpath(noRecordId)).isDisplayed() )
{
/**when the element is found do this*/
}
}
catch(Exception e)
{
/**include the else part here*/
}
}
Hope this helps :)
I've had mixed results with .isDisplayed() in the past. Since there are various methods to hide an element on the DOM, I think it boils down to a flexibility issue with isDisplayed(). I tend to come up with my own solutions to this. I'll share a couple things I do, then make a recommendation for your scenario.
Unless I have something very specific, I tend to use a wrapper method that performs a number of checks for visibility. Here's the concept, I'll leave the actual implementation approach to you. For general examples here, just assume "locator" is your chosen method of location (CSS, XPath, Name, ID, etc).
The first, and easiest check to make is to see if the element is even present on the DOM. If it's not present, it certainly isn't visible.
boolean isPresent = driver.findElements(locator).size() > 0;
Then, if that returns true, I'll check the dimensions of the element:
Dimension d = driver.findElement(locator).getSize();
boolean isVisible = (d.getHeight() > 0 && d.getWidth() > 0);
Now, dimensions, at times, can return a false positive if the element does in fact have height and width greater than zero, but, for example, another element covers the target element, making it appear hidden on the page (at least, I've encountered this a few times in the past). So, as a final check (if the dimension check returns true), I look at the style attribute of the element (if one has been defined) and set the value of a boolean accordingly:
String elementStyle = driver.findElement(locator).getAttribute("style");
boolean isVisible = !(elementStyle.equals("display: none;") || elementStyle.equals("visibility: hidden;"));
These work for a majority of element visibility scenarios I encounter, but there are times where your front end dev does something different that needs to be handled on it's own.
An easy scenario is when there's a CSS class that defines element visibility. It could be named anything, so let's assume "hidden" to be what we need to look for. In this case, a simple check of the 'class' attribute should yield suitable results (if any of the above approaches fail to do so):
boolean isHidden = driver.findElement(locator).getAttribute("class").contains("hidden");
Now, for your particular situation, based on the information you've given above, I'd recommend setting a boolean value based on evaluation of the "src" attribute. This would be a similar approach to the CSS class check just above, but used in a slightly different context, since we know exactly what attribute changes between the two states. Note that this would only work in this fashion if there are two states of the element (Advanced and Basic, as you've noted). If there are more states, I'd look into setting an enum value or something of the like. So, assuming the element represents either Advanced or Basic:
boolean isAdvanced = driver.findElement(locator).getAttribute("src").contains("advanced_button.jpg");
From any of these approaches, once you have your boolean value, you can begin your if/then logic accordingly.
My apologies for being long winded with this, but hopefully it helps get you on the right path.
Use of Try Catch defies the very purpose of isdisplayed() used as If condition, one can write below code without using "if"
try{
driver.findElement(By.xpath(noRecordId)).isDisplayed();
//Put then statements here
}
Catch(Exception e)
{//put else statement here.}
Related
I am trying to complete a test case that involved opening propertypal.com, entering some values and validating the responses using the software cypress. I've never used cypress before but the company asking me to do this test want me to utilise it.
This is the website i'm testing https://www.propertypal.com/
I want to type bt6 into that text box, but I cant work out the correct locator to use. Everything I try either returns multiple elements or doesn't find anything.
Below are some of the things I tried with no success. The main things I have been honing in on are the placeholder text, the ID and element name.
I'm very new to this type of automation so any help would be amazing.
cy.get('query').type('bt6')
cy.get('input:first').should('have.attr', 'placeholder', 'Search Area, Address, Agent').click()
cy.get('search-form-textbox').type('bt6')
With this element
<input id="query"
type="text"
name="q"
class="search-form-textbox"
autocorrect="off"
spellcheck="false"
value=""
placeholder="Search Area, Address, Agent">
Using the id="query" should be best,
cy.get('input#query') // should only be one id "query" on the page
.type('bt6');
If there's multiple id's "query" and you want to flag it,
cy.get('input#query')
.then($els => {
expect($els.length).to.eq(1) // assert there's only one id found, otherwise fail
})
.type('bt6');
If there's multiple id's "query" and you don't really care, you can select the third which is the visible one.
cy.get('input#query')
.eq(2) // take the third, which is at center of the page
.type('bt6');
Taking the "nth" element found is always a bit fragile, but placeholder text is pretty good instead (provided the page isn't multi-lingual)
cy.get('input[placeholder="Search Area, Address, Agent"]') // easier with attribute in selector
.eq(1) // take the second, as the are two of these
.type('bt6');
Class is not so good, as can often be applied to multiple elements, but in this case it's pretty good because it's specific to the role,
cy.get('input.search-form-textbox') // prefix class with "."
.eq(2) // take the third, which is at center of the page
.type('bt6')
Web pages can often have multiple elements with the same selector, for example cy.get('input#query') has three elements with this id.
What happens is the developer creates a component, adds an id like <input id="query"> then adds the component in several places, so the page actually ends up with multiple ids of the same name.
When the page is complex with hidden sections, to find the element you want start by testing with a console.log
cy.get('input#query') // finds 3 elements
.then(console.log) // log them to dev tools
Open dev tools, click open the object printed and you can see the list of elements selected.
Now you can hover each element, and the corresponding element on the page is highlighted.
In this case the first two are hidden behind menu items, but the third is the one we need.
So now we can add an .eq(2) to select the third element
cy.get('input#query') // finds 3 elements
.eq(2) // take the third element
.type('bt6');
So when I ran the cypress Test for your website, I got an uncaught exception that is originating from your Application. This is something that should be analyzed and is possibly fixed.
If this is something that is not going to be fixed, then you can add the below in your test, so that cypress ignores the exception and doesn't throw an error.
Cypress.on('uncaught:exception', (err, runnable) => {
return false
})
Now I tried using the locator id(#query) to input the test, as it is always good to use id because it's unique, but unfortunately, it gave me an error as the element is not visible. Unfortunately adding {force: true} also didn't help me solve the issue.
cy.get('#query').type('bt6')
1.So, the locator that worked for me was .search-ctrl. So your Final Test will look like this:
cy.visit('https://www.propertypal.com/')
Cypress.on('uncaught:exception', (err, runnable) => {
return false
})
cy.get('.search-ctrl').type('bt6')
2.Now, if you want to globally handle the exception, then go to cypress/support/index.js and then write there:
Cypress.on('uncaught:exception', (err, runnable) => {
return false
})
And then in this case your test will just have:
cy.visit('https://www.propertypal.com/')
cy.get('.search-ctrl').type('bt6')
http://i.stack.imgur.com/L4WUv.jpg
Link to Grid
I'm trying to detect the different drop downs on this page (depicted by the filters by the text boxes). The problem i'm having is that it seems that the filters all have the same ids. I can get the webdriver to find the initial filter button but not target the options in the drop down.
Note the filters I'm talking about are the ones from the funnel buttons. For example contains, isEqual, between etc *
This is wrong but an example
it('Should filter grid to -contain Civic', function() {
browser.element(by.id('ctl00_ContentPlaceHolder1_RadGrid1_ctl00_ctl02_ctl03_FilterTextBox_Model')).sendKeys("civic");
browser.element(by.id('ctl00$ContentPlaceHolder1$RadGrid1$ctl00$ctl02$ctl03$FilterTextBox_Model')).click();
browser.element(by.xpath("//*[contains(text(), 'Contains')]")).click();
})
NOTE The answer that was being looked for is at the bottom of this answer after the word "EDIT". The rest of this answer is retained because it is still useful.
It's a challenge to test webpages that dynamically generate ids and other attributes. Sometimes you just have to figure out how to navigate the stable attributes with an xpath. Here's an xpath that finds all four dropdowns:
//tr[#class='rgFilterRow']//input
To differentiate between each one, you can do this:
(//tr[#class='rgFilterRow']//input)[1] // Brand Name
(//tr[#class='rgFilterRow']//input)[2] // Classification
(//tr[#class='rgFilterRow']//input)[3] // Transmission
(//tr[#class='rgFilterRow']//input)[4] // Fuel
Using numbers to specify elements in an xpath isn't really desirable (it will behave incorrectly if the order of columns in the table changes), but it's probably the best you can do in this case because of all the dynamic ids and general lack of reliable identifying attributes.
EDIT
I misunderstood what you were trying to get because I didn't look at the image that you linked to. Once you've opened up that menu, you should be able to use an xpath to get whichever option you want by the text. For example, if you want the "Contains" option:
//a[#class='rmLink']//span[text()='Contains']
This page is highly dynamic. You had better brush up on your XPath, as nothing else will be able to help you. You can use this: http://www.zvon.org/xxl/XPathTutorial/General/examples.html .
Here is a simple example of how to access the Brand Name "pulldown". This is written in Groovy, which looks a lot like Java. If you know Java you should be able to get the idea from this:
WebElement brandName = driver.findElement(By.id("ctl00_ContentPlaceHolder1_RadGrid1_ctl00_ctl02_ctl03_BrandNameCombo_Arrow"))
brandName.click() // to open the "pulldown"
List<WebElement> brandItems = driver.findElements(By.xpath("//ul[#class='rcbList']/li"))
brandItems.each {
if(it.text == 'BMW')
it.click()
}
Unfortunately, the above id is not very reliable. A much better strategy would be something like:
WebElement classification = driver.findElement(By.xpath("//table[#summary='combobox']//a[contains(#id, 'ClassificationCombo_Arrow')]"))
Selecting its items is done similarly.
classification.click() // to open the "pulldown"
List<WebElement> classificationItems = driver.findElements(By.xpath("//ul[#class='rcbList']/li"))
classificationItems.each {
if(it.text == 'Sedan')
it.click()
}
If you are not up to the task, you should be able to get help from your development colleagues on how to locate all the elements in this page.
Scenario: I have a scenario like after login to some page, a profile update button intermittently appears which i need to click on. Thing is like if that button will appear i have to click otherwise i have to leave that part and go ahead. I have written a logic to handle that scenario like below.
public boolean isElementPresent(By locatorKey) {
try {
getDriver().findElement(locatorKey);
return true;
} catch (org.openqa.selenium.NoSuchElementException e) {
return false;
}
}
If that element will appear it will return true otherwise it will return false.. The above code is working fine...but the problem is it is taking around one min to return either true or false..suppose i have used five places in my script so unnecessarily i the script is waiting for 5 mins...I have also tried the below code
getDriver().findElement(locator).isDisplayed();
But the same issue i am facing ...the code is working fine but it is also taking around 1 min to return the command...
Is there any efficient way to handle this kind of scenario without waiting one min to get the status?
Use method findElements instead, and check if the returned list is not empty:
return !getDriver().findElements(locatorKey).isEmpty();
Please note that a try/catch clause is not required here.
barak manos has a perfectly viable answer to your question, but if you'd like to avoid the boolean inversion, here is an alternative:
public boolean isElementPresent(By locatorKey){
return (getDriver().findElements(locatorKey).size() > 0);
}
As with his solution, no try/catch is required for this as findElements() will simply return an empty list if the locator is not found or has gone stale.
Again, not to detract from barak manos here. This is just another solution.
How can I check whether a given text string is present on the current page using Selenium?
The code is this:
def elem = driver.findElement(By.xpath("//*[contains(.,'search_text')]"));
if (elem == null) println("The text is not found on the page!");
If your searching the whole page for some text , then providing an xpath or selector to find an element is not necessary. The following code might help..
Assert.assertEquals(driver.getPageSource().contains("text_to_search"), true);
For some reason, certain elements don't seem to respond to the "generic" search listed in the other answer. At least not in Selenium2library under Robot Framework which is where I needed this incantation to find the particular element:
xpath=//script[contains(#src, 'super-sekret-url.example.com')]
A simpler (but probably less efficient) alternative to XPaths is to just get all the visible text in the page body like so:
def pageText = browser.findElement(By.tagName("body")).getText();
Then if you're using JUnit or something, you can use an assertion to check that the string you are searching for is contained in it.
assertThat("Text not found on page", pageText, containsString(searchText));
Using an XPath is perhaps more efficient, but this way is simpler to understand for those unfamiliar with it. Also, an AssertionError generated by assertThat will include the text that does exist on the page, which may be desirable for debugging as anybody looking at the logs can clearly see what text is on the page if what we are looking for isn't.
I'm doing some drag and drop js testing with selenium-client. It works (taking screengrabs before and after clearly show the elements to switch places), but I'm having trouble programatically asserting the change happened.
Am I mental, or can I not do something like:
selenium.assert_equal("css locator", "expected id of element")
which, in this case, would look something like:
selenium.assert_equal("css=li:nth-child(1)", "li#list_item_2")
Any tips on how to implement this would be great.
Thanks,
Adam
Edit: if I had selenium.get_element that would take a selector and return what it was, I could then perform the assertion in the next step.
i.e.
element = selenium.get_element("css=li:nth-child(1)")
assert_equal(element, "li#list_item_2")
(I think).
Your example won't work because you're comparing two strings that aren't equal. One way to assert that your element has moved would be to use isElementPreset as demonstrated below:
//before drag and drop
assertTrue(selenium.isElementPresent("css=#source li:nth-child(1)"));
assertFalse(selenium.isElementPresent("css=#target li:nth-child(1)"));
//drag and drop code here
...
//after drag and drop
assertTrue(selenium.isElementPresent("css=#target li:nth-child(1)"));
assertFalse(selenium.isElementPresent("css=#source li:nth-child(1)"));
This example uses the Java client API, but it should be easy to work out how to do it in your preferred client API. It will also depend heavily on your application, as the above will check that the element with id of 'target' has one child li element before the drag and drop, and none afterwards. If you have a snippet of your HTML source I might be able to prove a more robust example.