Assigning to variables inside Run Keyword If - robotframework

\ Run Keyword If ${i} == 7 log to console Testing Variant 1
\ ${is visible}= Run Keyword And Return Status Element Should Be Visible (//li[#class='_8HqL0'])[${i}]
\ Run Keyword If ${is visible} Run keywords
\ ... Scroll Element Into View (//li[#class='_8HqL0'])[${i}]
\ ... AND Click Element (//li[#class='_8HqL0'])[${i}]
\ ... AND sleep 2s
\ ... set variable ${Ad_Path} Get Text //*[#class='rui-3blDo _1Uh38 _27AdP']
\ ... AND log to console ${Ad_Path}
Hi i want to use the GET TEXT activity inside a IF block in FOR but its giving an error stating keyword name cannot be empty help

You can't have a construct ${variable}= Returned Value From Keyword inside a Run Keyword/Run Keyword If because the latter expects everything passed to it to be a keyword - and it considers ${variable} also to be one.
There is one "workaround" - Run Keyword If propagates back up the last returned value in its keyword, and that can be set to a variable. E.g. you can do this:
${variable}= Run Keyword If ${condition} Returned Value From Keyword ELSE Set Variable other value
Mind the ELSE in this construct - without it, if the condition is false the variable will be undefined - will be left with a value None (the data type).
Naturally, if the Run Keyword If has more than one steps (like your console logs) you'll have to break it up - a block that "does things", and another (or others) that "assigns values".
I've typed "workaround" in quotes because it isn't really such - it's the way the keyword is designed to be used.

Related

Robot-framework: How do I run keyword and its variables stored in a list?

I am currently trying to pass a keyword and its arguments as a List to an another keyword, which then runs it, like this.
Keyword That Runs:
[Arguments] #{keyword_to_run_with_parameters}
Run Keyword #{keyword_to_run_with_parameters}
For demo I created a parameter in the following way to test it:
#{to_analyze}= Create List Should Be Equal ${True} ${True}
Which gave me the following:
No keyword with name 'keyword_to_run_with_parameters = ['Should Be Equal', True, True]' found.
I have tried creating the list in different ways, but this was the only one that worked. I also tried running it with ${keyword_to_run_with_parameters}, but did not run.
I tried to search StackOverflow for any suggestion, but did not find appropriate ones.
Edit:
I am working with GUI and I want to create a new Keyword which takes screenshots when a non-selinium keyword fails. This is currently not working, because I cannot handle the list as a container for keywords and their arguments. A solution could be to only call this function if the keyword already failed, but I'm curious about other approaches.
Capture Screenshot On Failure
[Documentation] Captures screenshot on failure of a keyword, then fails the test with custom message if any is given.
... Needed because RobotFramework/Selinium only takes screenshot if a RobotFramework/Selinium command fails.
... param: keywords: #{keywords}= Create List Keyword Arguments
[Arguments] ${failmessage}=Basic feedback for failiure. Picture is above. #{keywords}
${good} = Run Keyword And Return Status #{keywords}
Run Keyword If not ${good} Run Keywords
... Capture Page Screenshot
... AND Fail ${failmessage}

How to fix "Escaping empty cells with '\' before line continuation marker '...' is deprecated" error in Robot Framework?

I keep on getting this error when running my Robot Framework script:
"Escaping empty cells with '\' before line continuation marker '...' is deprecated. Remove escaping before Robot Framework 3.2."
Here is a sample code:
*** Test Cases ***
Debug
${Str} = Set Variable Rose
: FOR ${Ctr} IN RANGE 1 5
\ Run Keyword If '${Str}' == 'Test' Log Test
\ ... ELSE Log Not Test
I searched for a solution and I only got this link: https://gerrit.openbmc-project.xyz/#/c/openbmc/openbmc-test-automation/+/22245/
I can see that they used FOR/END instead of :FOR (which was working fine before).
FOR ${userid} IN RANGE 2 16
${user_info}= Get User Info ${userid}
Run Keyword If "${user_info['user_name']}" != ""
... Run IPMI Standard Command user set name ${userid} ""
END
However, when I try to change my code to use FOR/END, RIDE automatically changes it back to :FOR.
I use RIDE heavily and would like to continue to do so I need it to work around this error. My RIDE is the latest one so upgrade won't work. Any help would be appreciated.
The syntax for the FOR-loop is changed. From the documentation:
Not closing loops with END, escaping keywords inside loops with \, and
using :FOR instead of FOR are all going to be deprecated in Robot
Framework 3.2. Users are advised to switch to the new syntax as soon
as possible.
With your code I can still run the test, but the deprecation warning is shown. To remove the warning this worked for me in Eclipse:
Debug
${Str} = Set Variable Rose
:FOR ${Ctr} IN RANGE 1 5
\ Run Keyword If '${Str}' == 'Test' Log Test
... ELSE Log Not Test
When you remove the escape character in the ELSE line the warning is no longer shown. This is a workaround though, untill a new version of RIDE comes along I guess.

Robot Framework: How to sort by

I have a webpage with a combobox to sort a list by Price, Name,... The list is in many pages, so I need to get all elements first and after, I will sort by and check if the elements are correct. Right?
I am trying to do it and navigate for all pages and get all elements. But it is only taking the elements in first page. I am totally new in Robot framework.
Does anyone have a suggestion how I can do it?
${name_list_actual} Create List
${cnt_pages}= Get Element Count //div[#class='container index-new-p']/div/nav[#class='text-center']/ul/li/*
Log To Console ${cnt_pages}
:FOR ${n} IN RANGE 1 ${cnt_pages}
\ Click link //div[#class='container index-new-p']/div/nav/ul/li[${n}]/a
\ ${cnt}= Get Element Count //*[#class="title"]/*
:FOR ${i} IN RANGE 1 ${cnt}
\ ${get_names} Get Element Attribute //table[#class='result-table']/tbody/tr[${i}]/td/div/div[2]/div/a text
\ Append To List ${name_list_actual} ${get_names}
${get_names}= Select All From List //table[#class='result-table']/tbody/tr[${i}]/td/div/div[2]/div/a
\ Log To Console ${name_list_actual}
\ Continue For Loop
Thanks so much
First and foremost, by your code sample's indent it looks like you're doing nested for loops - an outer one for the changing the pages, and an inner that'll get the text in each row. The thing is - Robot Framework doesn't support nested for loops - see the documentation.
What happened on execution is the first loop (the pagination) ran with just two statements and finished:
\ Click link //div[#class='container index-new-p']/div/nav/ul/li[${n}]/a
\ ${cnt}= Get Element Count //*[#class="title"]/*
Then all the rest were executed as part of the second.
A solution would be to have a keyword "Get All Values In The Table" that'll hold the inner loop, and call it in the current outer, which will paginate.
Another issue - you're using IN RANGE, passing 1 as start and ${cnt} as end; if it had value of 4, you probably expect the tracking variable to get all values from 1 to 4.
Yet range works with the first argument inclusive, and up to - but not getting to - the second argument; thus it covers the range 1 to 3. To salvage that, you'd need to set the upper bound to cnt+1, e.g. ${cnt + 1}.
Minor stuff:
You have a statement that's within the loop block, but not prefixed with \:
${get_names}= Select All From List //table[#class='result-table']/tbody/tr[${i}]/td/div/div[2]/div/a
I'm surprised it didn't give you a syntax error - it effectively breaks the loop, and the framework should complain the next lines are prefixed as if in a loop, but one is not started.
-
When you are changing the pages by the click, you are not making sure the UI has loaded the data for the new page. If this happens through ajax calls, you may very well be working with the previous page's data, thinking it is the new one - the selenium click returns control very fast, and the operands for getting the text are running - while the UI still waits for the new data and is displaying the previous one.
-
In RF version 3.1 the loop syntax is different - the block members are not prefixed with \, and it's closed with an END statement.
I'd suggest to migrate to it - a) the current one is going to be eventually deprecated, and b) in the new one the nesting would have been marked as syntax error (you're starting a new loop without END-ing the running one), instead of silently passing with unexpected behavior.

Getting Variable accessing error after upgrading the Python and Robot framework version

Below mentioned script has been worked in old python (2.7.x) and Robotframework version .
The same code is not being worked ,after upgrading the python version from 2.7 to 3.7.2 and the robot version to 3.1.1.
I'm getting this error while executing script:
Variable '${var}' is string, not list or dictionary, and thus
accessing item '${var}' from it is not possible.
Code :
${loc} xpath=(//*[contains(#class,"c3-legend-item ")])
: FOR ${row} IN RANGE 1 ${Count}
\ ${Exp_Name} = Get Text ${loc}[${row}]
\ Log ${Exp_Name}
In robot version 3.1 there was a backwards-incompatible change. From the release notes:
Square brackets after variable like ${var}[xxx] is considered item access
Syntax like ${var}[xxx] is now considered variable item access (#2601), not variable ${var} followed by a literal string [xxx]. If the latter is desired, escaping like ${var}[xxx] is needed.
In your specific case you're using ${loc}[${row}], where you're expecting [${row}] to be appended to ${loc}. In 3.1 robot thinks that [${row}] is an index into ${loc}.
The fix, as suggested in the release notes, is to escape the opening square bracket:
\ ${Exp_Name} = Get Text ${loc}\[${row}]
Use catenate to build dynamic xpath. This will work for you.
${loc} xpath=(//*[contains(#class,"c3-legend-item ")])
: FOR ${row} IN RANGE 1 ${Count}
\ ${dynamic_xpath}= Catenate SEPARATOR= ${loc} [${row}]
\ ${Exp_Name} = Get Text ${dynamic_xpath}

How to loop on a table column?

Badly need your help. In Vehicle ID column, I would like to find a vehicle and once it finds it, it will click on it... How can I do that in Robot Framework? What approach should i be using?
For looping in table you can use xpath easily:
*** Test Cases ***
Stackoverflow Test
[Tags] #InDevelop
Go To https://www.w3schools.com/html/html_tables.asp
Wait Until Element Is Visible id=customers ${global_timeout}
:FOR ${index} IN RANGE 2 8
\ Wait Until Element Is Visible xpath=//*[#id="customers"]/tbody/tr[${index}]/td[1] ${global_timeout}
\ ${var} = Get Text xpath=//*[#id="customers"]/tbody/tr[${index}]/td[1]
\ Log ${var}
In order to click the correct element, you probably need to compare the variable content with your expected value. That can be done this way:
${areYouMyLine} = Run Keyword and Return Status Should Be Equal As Strings ${var} Island Trading
Run Keyword If ${areYouMyLine} Click Elementxpath=//*[#id="customers"]/tbody/tr[${index}]/td[1]
And also don't forget to Exit your For Loop since you found your element.
Exit For Loop
However this is not the best practice. You probably should go to your product team asking for some data attributes which will help you to find your line. Alternatively, if you know your table content, put it into a list and use For In Loop instead. Good stuff about loops can be found here: https://blog.codecentric.de/en/2013/05/robot-framework-tutorial-loops-conditional-execution-and-more/

Resources