For loop on test case titles in robot frame work - selenium

On one page there are various item. I am able to iterate over all items/elements on the page.
Though would like to keep every iteration is a separate test cases.
As in below Test case title First Page Item No expand
Is there any way to put test case name in for loop.
For example First Page and Item No both can be variable and controlled by for loop.
*** Test Cases ***
First Page Item No expand
: FOR ${INDEX} IN RANGE 1 80
\ Click Element xpath=/html/body/div[1]/div[2]/section/div/div[2]/div[2]/div[${INDEX}]/div[1]/div/p[2]

From my understanding this should not be possible. However there are two ways to get around:
Treat is as one test case, have a keyword that does the FOR loop
Have 80 test cases calling one keyword with an ${index} attribute

Related

composeTestRule checking that atleast 1 item exists

I have a list which has 2 different items. However, if the user gets close to the end of the list then the 2 same items are added again and again to create an infinite scrolling feel.
I've created a test to basically verify that the item exists like so:
composeTestRule
.onAllNodesWithContentDescription("Home")
.assertCountEquals(2)
As you can see this just finds nodes with the content description of "Home" and checks if their are 2.
Currently, this works as the screen size is small but let's say the screen size is doubled then this will fail as the assertCountEquals(2) would need to check for 4.
I was wondering to make this code better, is there a way to basically check that atleast 1 exists?
onAllNodes methods return an array, grab the first element and check whether it exists or is displayed.
composeTestRule
.onAllNodesWithContentDescription("Home")
.onFirst().assertExists()

How to wait untill drop down values load in if else condition in robot framework

My scenarios are: I have two drop down values side by side if the first drop down-selected based on the value selected second drop-down values will be loaded from that we need to pick one value. in one case from the first drop down if I select unknown or any legal purpose I should not go for the second dropdown. this is what the requirement I have please help me out. Below is the code I have written
Variables
${var1}= Unknown
${var2}= Any legal purpose
The user selects random NAICS code and subcode from the drop-down
${selectedNAICScode}= User selects NAICS code from the drop down
${NAICS_code} run keyword if
${selectedNAICScode}!=${var1} or ${selectedNAICScode}!=${var2} run keywords
... element should be visible xpath://select[#id="ddlNAICSSubCode"]
# ... is visible ${NAICS_subcode}
... User selects NAICS-sub code from the drop down
... ELSE run keywords
... element should not be visible xpath://select[#id='ddlNAICSSubCode']
Even though we are giving one argument when I run the script it is saying expecting 1 to 2 arguments but got 0. my question is how we can wait until the drop-down values load into the drop-down in else condition.
You can use the following functionality:
WebDriverWait wait = new WebDriverWait(driver, INSERT_INTEGER_WAITING_TIME);
boolean waitUntil = wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("ENTER_YOUR_XPATH_OR_OTHER_ATTRIBUTE")));
In this way, your action will happen only when the element is going to be visible.
If you need further information check this link

Can I count rows across multiple pages of a table with robot framework?

I am quite new to robot, and have only been working solo on it at work for a month or so.
Currently I am trying to count the total number on rows in a table within the application I am testing. (chrome based)
This is what I am using:
${count}= get element count //table[#class='options-table']/tbody/tr
Which brings back a value of 5 - this is counting the first page. However, I'm expecting it to bring back 76 as there are multiple pages.
Can anyone help on how to bring back the amount of rows across multiple pages?
${count}= get element count //table[#class='options-table']/tbody/tr
Expected result: 76
Actual result: 5 (only the first page)
To avoid a slightly complex logic (iterating through pages, summing up element counts) in a Robot Framework keyword you could write your own keyword in Python for example.
In this case you need a keyword that takes an element locator (//table[#class='options-table']/tbody/tr to be specific) and a list of page urls.
To implement such keyword, create a file like ExtendedSeleniumLib.py:
from robot.libraries.BuiltIn import BuiltIn
def get_element_count_from_pages(locator, *page_urls):
seleniumlib = BuiltIn().get_library_instance('SeleniumLibrary')
element_count = 0
for url in page_urls:
seleniumlib.go_to(url)
element_count += seleniumlib.get_element_count(locator)
return element_count
and from your test code you can use it like:
*** Settings ***
Library SeleniumLibrary
Library ExtendedSeleniumLib
*** Variables ***
${SE HEADER LOCATOR} //a[#class='site-header--link fs-headline1 fw-bold']
*** Test Cases ***
Count Elements On Multiple Pages Example
[Setup] Open Browser https://stackoverflow.com Firefox
Maximize Browser Window
Set Selenium Speed 0.1
${count}= Get Element Count From Pages ${SE HEADER LOCATOR}
... https://iot.stackexchange.com/
... https://sqa.stackexchange.com/
... https://robotics.stackexchange.com/
Should Be Equal As Integers ${count} 3
[Teardown] Close Browser
This example iterates through three Stack Exchange sites and counts the header elements. As there should be only one on each page the expected result is 3. Based on this you should be able to count the table rows on your pages.
About how to configure search path for libraries and resources, check the relevant chapter form the Robot Framework User Guide; Configuring where to search libraries and other extensions. If you place the python file into the same directory where your robot file is, then you do not need anything to do.
Please check below code, it assumes that the total number of pages will not be more than 100 since I'm not aware of the webpage, you can either take this number from webpage if available. Also, if you are sure that total number of rows per page is always 5 then you can use below formula
[ 5 * (total number of pages - 1 ) + row count of the last page]
This can give you total row count across all pages without traversing through all the pages. Also, please add any time synchronisation steps for the successful run.
Get Count of All Pages
${next_page_locator} Set Variable enter next page icon/link xpath here
${first_row_locator} Set Variable enter first row xpath here
${total_count} set variable 0
: FOR ${index} IN RANGE 1 100
\ Wait Until Element Is Visible ${first_row_locator}
\ ${count} get element count //table[#class='options-table']/tbody/tr
\ ${total_count} evaluate ${count} + ${total_count}
\ ${next_link_present} Run Keyword And Return Status Page Should Contain Element ${next_page_locator}
\ exit for loop if ${next_link_present} is ${False}
\ Click Element ${next_page_locator}

How to assign a keyword to Group of Test Cases at one time in TestLink?

I want to add a keyword to some of the test cases in my test specification. May I know whether there is any easy way of doing it other than adding the keyword to each test case manually?
Any help is appreciated. Thanks in advance.
You can assign keyword to multiple test cases under specification's node.
Select Desktop item from top nav bar menu in Testlink
From the left select Test Specification -> Assign Keywords
Specifications' tree is opened - select the needed node (test suite)
In Keyword Assignment frame from the right assign with > button keyword from available ones to Keywords to be assigned.. and click Save
As result all test cases under the selected node will get the assigned keyword.
You may also filter test cases by some of available filter fields and then assign the keyword (using the process described above) but with "Assign ONLY to filtered Test Cases" checkbox activated, so only filtered TCs will get the needed keyword.

How to use variable, which value should be set in keyword or test, in XPATH?

I need to click on element based on what value it contains..but I want to set this value in test run or keyword definition (best option is in the test I guess)
How should I do it?
the variable containing xpath should look like that:
${DROPDOWN ITEMS} xpath=//*[contains(#class,'listitem-element')]/span[contains(text(),'${second_number}')]
This locator works when I replace the variable with actual number like '002', but I want to have it more general..
In keyword definition I use it like:
Choose Value From Dropdown
focus ${DROPDOWN ITEMS}
click element ${DROPDOWN ITEMS}
and in test I just call the keyword
my question is where and how to set the variable value of ${second_number} variable used in xpath?
PS:the xpath definition, keyword and test are each in separate files
thank you!
I use similar approach in my SUT, as it works with fairly complex objects, both precreated and dynamically generated during the tests executions - and their main user-identifiable attribute is the displayed name. Here's simplified version of my flow, and it's based around string substitution.
Starting off from the variables file - a simple collection of selenium locators, the value of the locator has a "special" string, which will later be substituted:
*** VARIABLES ***
${DROPDOWN ITEMS} xpath=//*[contains(#class,'listitem-element')]/span[contains(text(),'SELENIUM_PLACEHOLDER_CHANGE_ME')]
Then, in the keyword files there are private keywords for returning the proper locators, for example for this one:
*** KEYWORDS ***
_Return Selenium Locator For The Dropdown Item Named
[Documentation] Verifies the desired dropdown item is valid, ando returns its locator (not Webelements!!)
[Arguments] ${name}
# change the placeholder with the actual UI name
${loc}= Replace String ${DROPDOWN ITEMS} SELENIUM_PLACEHOLDER_CHANGE_ME ${name}
# why? Rationale explained below
Element Should Be Visible ${loc} message=The dropdown does not have an item called ${name}
[Return] ${loc}
Why the visibility check? Simple - to fail as early as possible if there's no such object currently in the SUT, and to have uniform error message, independent of how is the element further used (clicked on, checked for presence, attribute retrieval, etc.)
Then, a follow up user keyword for performing actions on the element uses the previous one:
# the user keywords
Choose Value From Dropdown
[Documentation] It does what it does :)
[Arguments] ${the value}
${loc}= _Return Selenium Locator For The Dropdown Item Named ${the value}
# as you can see, no checks is the element real - that'she offloaded to the helper keyword ^
Focus Element ${loc}
Click Element ${loc}
Finally, the test cases use the keyword to work with any data you deem neaded:
*** TESTCASE ***
The dropdown should do X
[Documentation] Steps: 1, 2, 3, etc
# do the normal steps you'do do
Choose Value From Dropdown my current value
This approach applies fairly well for negative tests also - for example, to check a value is not present, a test case would contain:
Run Keyword And Expect Error The dropdown does not have an item called no_such_element Choose Value From Dropdown no_such_element
Thus we're both using selenium checks for the absence of the element, and keeping the test case close to real-life expression - a description of what should happen, with no special syntax and SE keywords.
please excuse any typos and minor syntax omissions - it's not easy to type on a mobile that much, next time I'd think twice before taking it on :D
You can define variables when you fire off your test suite by using arguments.
Here is the documentation for it
Right now, you would leave your xpath as it is. Keeping the ${second_number} inside. Now you can either define it within the argument or within the argument file. They do the exact same thing, but one is neater. Just to get it working I would just worry about putting it directly in the console.
pybot -v second_number:002 nameOfTestFile.robot
This will tell pybot to create a variable called ${second_number} with the value of 002. It does not save this inside the test, so after the test is completed, it will forget the variable.
Once this works, you can then move this into a Argument file Or if you want you can even define it inside a Variable file where you can store all of your variables and then call them within the argument file / within the console.
Any questions do ask and ill try to help out
how about using the set suite variable keyword?
we can use Evaluate keyword for framing dynamically changing xpath
*** Variable ***
${common xpath} xpath=//label[contains(text(), '{0}')]
${text to be replaced} my name
*** Keyword ***
Frame xpath based on user input
${final xpath} Evaluate "${common xpath}".format("${text to be replaced}")
log ${final xpath}
RESULT
In ${final xpath}, you will have the "xpath=//label[contains(text(), 'my name')]"