How can I increase the robustness of my Selenium scripts? - selenium

I'm running approx 30 scripted test cases (each test case is a script) in series and there are often failures that include: cannot identify specified element, element not present.
I've already added a lot of different methods to wait for an element to show up. Sometimes when it is clearly there, I guess Selenium has a hard time trying to find the element's id ?
I've included several
do{
if(selenium.isElementPresent("id=resultTable_0_0"){
selenium.click("viewResultForm:refresh_button");
}
}while (!selenium.isElementPresent("id=resultTable_0_0"));
and
if(selenium.isElementPresent("id=resultTable_0_0"))
selenium.isVisible("id=resultTable_0_0");
and
if(selenium.isElementPresent("id=resultTable_0_0_1_to"))
selenium.click("resultTable_0_0_1_to");
always checking if an element is even present before doing something. This probably has a huge impact on performance, but for now I just want my scripts to run error-free, completely robust. I have this piece of code:
do{
if(selenium.isElementPresent("id=resultTable_0_0")){
selenium.click("viewResultForm:refresh_button");
}
}while (!selenium.isElementPresent("id=resultTable_0_0"));
if(selenium.isElementPresent("id=resultTable_0_0"))
selenium.isVisible("id=resultTable_0_0");
if(selenium.isElementPresent("id=viewResultForm:currentDetailViewType"))
selenium.isVisible("id=viewResultForm:currentDetailViewType");
if(selenium.isElementPresent("id=viewResultForm:currentSearchDateType"))
selenium.isVisible("id=viewResultForm:currentSearchDateType");
if(selenium.isElementPresent("id=viewResultForm:currentLegalEntity"))
selenium.isVisible("id=viewResultForm:currentLegalEntity");
if(selenium.isElementPresent("id=viewResultForm:currentRollupBy"))
selenium.isVisible("id=viewResultForm:currentRollupBy");
if(selenium.isElementPresent("id=viewResultForm:currentSecurityAltId"))
selenium.isVisible("id=viewResultForm:currentSecurityAltId");
if(selenium.isElementPresent("id=viewResultForm:currentSecurityAltIdType"))
selenium.isVisible("id=viewResultForm:currentSecurityAltIdType");
if(selenium.isElementPresent("id=viewResultForm:currentDepoViewType"))
selenium.isVisible("id=viewResultForm:currentDepoViewType");
if(selenium.isElementPresent("id=viewResultForm:currentBusinessDate"))
selenium.isVisible("id=viewResultForm:currentBusinessDate");
System.out.println("Success T13001");
selenium.stop();
Even this will error out !!! and it wont fall through to reach selenium.stop and 'fake' a success. What can I do to build on the robustness of my scripts? Any help would be appreciated.
I'm using Selenium 2.20.0 on IE 8.

As per your question if its the problem of not finding the id of locators then try using other locators like css and xpath.
Apply selenium.waitforpagetoload when ever you move to a new page or you open a url.
If you are working on an ajax based application then selenium.waitforcondition would be gud to you.
Whereever you think that a locator may take some time to appear after some operation,Use proper waits for those elements.

Related

How to iterate over an element (node) list on Android Jetpack Compose UI Tests?

I'm implementing some instrumented tests using the Jetpack Compose testing library. I'm not too familiar with Kotlin / Android development yet, but I have years of experience with Selenium and other testing libraries, so I'm missing some basic things and have no idea how to implement them.
What I want to do:
Iterate over an element (node) list. I have this list an all items are identified by the same test tag "item". I need to click on each one of these items.
On Selenium I can easily do that:
elements = driver.find_elements("item")
elements.each do |element|
element.click
end
But on Kotlin with the Composing Testing Framework I have no clue how to do that. The method below (responsible for returning a list of nodes) doesn't support forEach:
composeTestRule.onAllNodes(hasTestTag("item")
I also want to retrieve the list size.
On Selenium the method below returns the qty of items found:
driver.find_elements("item").size
But, again, there's nothing like that available with composing:
composeTestRule.onAllNodes(hasTestTag("item")
I've already read the official JetPack Compose Testing Tutorial, but it doesn't provide much details
I'm not sure how you'd go about iterating over a SemanticsNodeInteractionCollection. I'm also uncertain of why you'd want to do that. That said, in a testing scenario you'd likely have an expected count of items in a collection. Therefore, you can create a range and get the SemanticsNodeInteraction for each element that .OnAllNodes() returns.
Example where I expect there to be 10 ui elements returned:
val nodes = composeTestRule.onAllNodes(hasTestTag("item"))
for (index in 0..10) {
val node = nodes[index]
// node.assert whatever you want here.
}
Asserting the count equals something can also be done through:
composeTestRule.onAllNodes(hasTestTag("item")).assertCountEquals(10)
If you just want to get the total count and not assert it. I'd argue there might be something wrong with the tests themselves. I'd expect your test to be a controlled environment where you know exactly how many items should be shown on the screen at any given time.
Let me know if this helps, otherwise please elaborate on your exact scenario.
To iterate:
composeTestRule.onAllNodes(hasTestTag("item")).apply {
fetchSemanticsNodes().forEachIndexed { i, _ ->
get(i).performClick()
}
}
To check size:
composeTestRule.onAllNodes(hasTestTag("item")).fetchSemanticsNodes().size == 1

Storing and reusing the text content of an object using Playwright and Javascript, then use it for assertion/validaton

I would like to store the text from an object locator and use it for assertion. For instance, I have a trade number - 1234. This trade number only appears after a transaction, so it is not static on other screens. This number is located on several other screens and I need to validate that it appears. I am able to locate the element through inspect and Playwright accepts it, but having issues:
Grabbing the text (1234)
Then setting up an assertion statement to compare it
Below are my humble and naïve attempts:
async getConfirmNumber() {
//Store the contents in the page locator which has the trade number
const tradeNumber = page.locator('div:nth-of-type(2) > .col-md-9.display-value.ng-binding').textContent;
//Navigate to a different screen which now will display the trade number
await this.page.click('a[caption="History"]')
await this.page.click('a[href="#/trade-summary"]')
//Line of code that I am not sure how to correctly write. ".bidconfirmation" is the locator on the new screen which displays the trade number.
//If the contents or value of ".bidconfirmation" is NOT 1234 then an error needs to display.
await expect(tradeNumber).toHaveCSS('.bidconfirmation', tradeNumber);
}
Just to let you know I would change the tag on this post to playwright-JavaScript to better reach the intended audience.
However, if I understand your question correctly you are trying to get the text content of an element but the textContent() method is not working, I would try to use the innerText() method and see if that works.
Apologies if this is a little off as I work with the java version of Playwright but you could do:
const tradeNumber = page.locator('div:nth-of-type(2) > .col-md-9.display-value.ng-binding').innerText(); //BTW I would change this locator to something unique or a little more stable -- this should give you the tradeNumber
//then I'm not 100% sure what your trying to do here but if I understand correctly this might help
await expect(page.locator('.bidconfirmation').toHaveValue(tradeNumber));
I hope this helped a little, Im sorry I couldn't really get an understanding fully of the question you were asking but feel free to take a look at playwright.dev to find documentation surrounding Playwright.

Detecting Drop down with Selenium WebDriver

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.

WebDriver Selenium API: identifying a WebElement in XPath

I have recently started with Selenium, and I've decided to use only Selenium 2 / WebDriver.
In my test code, I often arrive at a WebElement without knowing where it is in the page.
I'd like to have code that, given an WebElement, constructs an XPath expression to uniquely select it.
FireFox recorder plugins for Selenium do this; what I want is code to do it in Selenium 2.
I can write such code myself by using WebElement's findElement to walk up the tree and findElements to find the child we came from, but it's nontrivial to come up with something fast (repeatedly calling By.xpath seems bad) and complete (e.g. due to namespaces).
(A related question suggests using CSS selectors instead - that's fine with me.)
Has anyone done this for me? What is the best approach?
Maybe this will help: I am testing a website where the id's are dynamically generated, so they change all the time. In order to get their xpath and work with it I use this function:
/**
* Gets the absolute xPath for elements with dynamic ids.
*
* #param driver - the current WebDriver instance
* #param element - the element for which the xPath will be found
* #return the absolute xPath for this element
*/
public static String getElementXPath(WebDriver driver, WebElement element) {
return (String)((JavascriptExecutor)driver).executeScript(
"gPt=function(c)" +
"{" +
"if(c.id!=='')" +
"{return c.tagName + '[#id=\"'+c.id+'\"]'}" +
"if(c===document.body)" +
"{return c.tagName}" +
"var a=0;" +
"var e=c.parentNode.childNodes;" +
"for(var b=0;b<e.length;b++)" +
"{var d=e[b];" +
"if(d===c)" +
"{return gPt(c.parentNode)+'/'+c.tagName+'['+(a+1)+']'}" +
"if(d.nodeType===1&&d.tagName===c.tagName)" +
"{a++}" +
"}" +
"};" +
"return gPt(arguments[0]);", element);
}
It's pretty straight forward: and btw yes css is the way to go; xpath should be only used as a measure of last resort. http://sauceio.com/index.php/2010/01/selenium-totw-css-selectors-in-selenium-demystified/ explains css locators in much more depth than I can in the space provided here.
Best approach: If you're using firefox download firebug, that will let you look at your html. Pres cmd+Shift+c and it'll open for you with an element highlighter. Find your html element, maybe it'll look something like this
<input type="submit" tabindex="110" value="Post Your Answer" id="submit-button">
Then you can find your element pretty simply
WebElement element = driver.findElement(By.cssSelector("input[id='submit-button']"))
Notice that we put the tagname first "input" followed by some kind of unique identifier in the brackets "input[id='submit-button']." For the most part this will cover 75% of all css locators you use. The other 25% require a little bit more tricky stuff covered in the link I placed at the top of the page.
You may ask "What kind of unique identifiers can I use besides id" well that is covered here: http://release.seleniumhq.org/selenium-remote-control/0.9.2/doc/dotnet/Selenium.html
Good luck starting out
EDIT
Well good luck finding your elements in the first place...If you need you can search elements by partial locator text like input[id*='submit']. Using that is helpful for dynamically generated elements, when you use the partial text as the part of the locator that doesn't vary from element to element.
You mentioned walking up the html tree perhaps I didn't see that when I first read the question. I think you hit the on issue at hand. Walking up the html tree isn't suggested as it makes your tests more fragile to html changes. It will also make your code unreadable in the long run as well. In general if your id's are missing or unpredictable I would suggest talking to proj. management about getting the developers to make code that can actually be automated (eg: getting identifiers implemented on critical elements). This will actually save both you and the developers alot of effort in the long run, and it will also increase the speed and reliability of your tests.
We can find the Submit Button using ID:
1.driver.findElement(By.id("submit-button"))
ID > NAME > CSS > XPATH

Finding text on page with Selenium 2

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.