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

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')]"

Related

Robot Framework variable attribute in seperate file not storing attribute to be used elsewhere

Variable attribute not getting passed into other file.
I have my variables for element locators stored in one file and I have assertions done in another file which has worked fine until now and separates things out nicely. I am doing an assertion to check that an element exists and its attribute(value) is not blank. If I write it on one page as follows it works perfectly. This use the selenium library keywords should not be equal and Get Element Attribute just to note.
${EXAMPLE} get element attribute class=test test-data
should not be equal ${EXAMPLE} ${EMPTY}
But If I separate them out into different files. So a locators.robot file:
#Locater File
${EXAMPLE} get element attribute class=test[test-data]
And an Assertions.robot:
#Assertion File
should not be equal ${EXAMPLE} ${EMPTY}
It stops working. If I use a selenium library assertion like page should contain element then it works, so I know I am pulling in the other Resource correctly. I have a feeling I may need to store the attribute in another variable somehow and actually assert against that. Any ideas would be great. Thanks in advance.
Suppose you have html code like this as you given in other question -
<div id="top-list">
<div data-version="12345" data-list="1" data-point="10">
Way 1 - Less recommended -
This is how my assertion.robot looks like -
*Settings
Library SeleniumLibrary
Resource Locator.robot
*Test Cases
Test attributes Locator
Open Browser file:///C:Desktop/testxpath.html chrome
${attribute_value}= Get Element attribute ${Datalist_locator_with_all_attribt} data-list
should not be equal ${attribute_value} ${EMPTY}
The locators are in locator.robot file. I'm not calling Get Element Attribute keyword in the locators because doing so there will be no link of directly executing it and referencing back the return value of it in testcase... So just keeping the locators in the locator file nothing else. This locators are accessible when I did Resource Locator.robot in my assertion.robot file. As you can see the Get Element Attribute element take first argument locator of element and second argument is nothing but the attribute name of which value you need. And this keyword returns value of attribute that supplied as second argument. -
*Variables
${Datalist_locator_with_all_attribt} xpath://div[#data-version='12345' and #data-list='1' and #data-point='10']
${locator_with_single_attribute} xpath://div[#data-version='12345']
Output
Way 2 - More Recommended -
Wrap the Get Element Attribute and Should Not Be Equal keywords in one single keyword. and dump it in another keyword file or create *keywords section in locator.robot file itself. Doing this your assertion.robot file will look like this -
*Test Cases
Test attributes Locator
Open Browser file:///C:/Desktop/testxpath.html chrome
Attribute values should not be empty
and locator.robot will look like this. You can make it more generic though -
*** Variables
${Datalist_locator_with_all_attribt} xpath://div[#data-version='12345' and #data-list='1' and #data-point='10']
${locator_with_single_attribute} xpath://div[#data-version='12345']
*** Keywords
Attribute values should not be empty
${attribute_value}= Get Element attribute ${Datalist_locator_with_all_attribt} data-list
should not be equal ${attribute_value} ${EMPTY}
Output

How to locate random id generated by a modal?

I was testing my website using RF. The problem is, every time the modal is opened, a different id(locator) will be set on the textbox that I want to input my text. How do you get value of this locator?
I was supposed to try Get Element Attribute but then it cannot support my problem since it still requires a specific locator.
In ROBOT Framework (RF), the locator can be accessed by several ways. Please refer and read this link: http://robotframework.org/Selenium2Library/Selenium2Library.html
The most common way to access the locator is by id such as :
Input Text id:username # Element with id 'username'.
Input Text id:password # Element with id 'password'. you can also use 'Input Password' keyword.
However, if the 'id' element is so dynamic which it keep changing, then the best alternative is to use either ABSOLUTE XPATH expression or CSS selectors. Install the XPATH add-on in your web browser. For firefox, just install ChroPath.
Then, get the ABSOLUTE Xpath element of that username & password text box. Let's assume we know the absolute xpath expression already, so in ROBOT, you can write like below.
${login_absolute_xpath}= Set Variable xpath=/html[1]//div[7]/form[1]/div[1]/input[1]
${password_absolute_xpath}= Set Variable xpath=/html[1]//div[7]/form[1]/div[2]/input[1]
Wait Until Page Contains Element xpath=${login_absolute_xpath}
Input Text xpath=${login_absolute_xpath}
Input Text xpath=${password_absolute_xpath}
...
This should works. Please let me know if this helps.

Can't pass a Test Execution result to a variable in Robo Framework

I am posting the results of automated tests to an offline forum. It would be nice to include PASS/FAIL in the forum post title but I'm having some difficulties retrieving the ${TEST STATUS} value - (obviously a hard-coded value works fine) .
I've defined the following in common-variables.robot as:
${FORUM_TEST_RESULT}....${TEST STATUS}
then on publish-results.robot
Input Text....//*[#id="title"]....${FORUM_TEST_RESULT}
The error I get is: variable ${FORUM_TEST_RESULT} not found
I can see here: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface that ${TEST STATUS} can only be used as part of Teardown.
I'm not sure how to collect the value of ${TEST STATUS} in the context of my RF script.
e.g the very last thing my script does is post to a forum:
Input Text....//*[#id="title"]....${FORUM_TEST_RESULT}
but before that I obviously need to populate ${FORUM_TEST_RESULT} with the value of ${TEST STATUS) which you can only get on Teardown? Hope this makes sense.
Input Text is a keyword of Selenium2Library that types the given text into the text field of a web page. You need to start a browser session first and open the right page an then possibly wait for the element to become visible, for example like this:
Open Browser [URL of your site]
Wait Until Element Is Visible //*[#id="title"]
Input Text //*[#id="title"] ${FORUM_TEST_RESULT}
If you want to retrieve a text from a page (as your coment suggests) then you need to use the keyword Get Text which returns the text of the element identified by locator.
Get Text 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 find value of email field using Selenium2Library

I am writing regression tests for a web application using robot framework and the Selenium2Library library. I have a simple test which changes all of the fields of an "account settings" type form (think username, password, email, etc.), then revisits the page and makes sure all of the data was saved. Like so:
*** Test Cases ***
Sample Test
Change All Account Details
New Account Details Should Be Saved
*** Keywords ***
Change All Account Details
Navigate to Account Page
Input Text accountSettingFrom_firstname Test
Input Text accountSettingFrom_lastname Dummy
Input Text accountSettingFrom_email new_email#example.com
# etc etc, eventually save the form
New Account Details Should Be Saved
Go To ${ACCOUNT_URL}
Textfield Value Should Be accountSettingFrom_firstname Test
Textfield Value Should Be accountSettingFrom_lastname Dummy
Textfield Value Should Be accountSettingFrom_email new_email#example.com
I get the following error on the final step (Textfield Value Should Be accountSettingFrom_email new_email#example.com) when running this test: Value of text field 'accountSettingFrom_email' should have been 'new_email#example.com' but was 'None'
I have taken screenshots the moment before that step runs, and I have added a pause and manually confirmed that the value attribute of 'accountSettingFrom_email' is indeed 'new_email#example.com'. HTML of the element at time the check occurs:
<input type="email" name="accountSettingFrom[email]" value="new_email#example.com" class="foo bar" required="required" tabindex="3" maxlength="128" url="/foo/bar" userid="foobar" id="accountSettingFrom_email">
You'll notice that the first two Textfield Value Should Be keywords pass. The only difference I can discern between the three elements is that 'accountSettingFrom_email' is type="email" instead of type="text", but if the the keyword is successfully locating the element, then why can't it grab the value of the value attribute?
So am I doing something wrong? I feel like this or some similar keyword must exist to test this, without having to resort to writing a custom library.
You have hit some bugs in Selenium2Library. When Selenium2Library was created, HTML5 was not ratified. Internally the library is filtering out your element because it has a type other than 'text' (made sense before HTML5). Textfield Value Should Be can only find your element if it has tag name input and attribute value 'text' for type.
See https://github.com/robotframework/Selenium2Library/issues/546
Also due to how Textfield Value Should Be is implemented, the error you are getting makes you think the element was found when in fact it was not because it was filtered out.
See https://github.com/robotframework/Selenium2Library/issues/547
In contrast, Input Text and Input Password have never filtered on element tag or attribute.
I would try Get Element Attribute instead to get the attribute named value instead. According to the API it should be
accountSettingFrom_email#value