robocorp / rpaframework

Collection of open-source libraries and tools for Robotic Process Automation (RPA), designed to be used with both Robot Framework and Python
https://www.rpaframework.org/
Apache License 2.0
1.17k stars 225 forks source link

Trying to iterate over an empty `RPA.Windows.Get Elements` result has unexpected behavior #1146

Closed kkotenko closed 9 months ago

kkotenko commented 9 months ago

MWE:

*** Settings ***
Library     RPA.Windows     WITH NAME    Windows

*** Test Cases ***
Test
    Windows Run    Calc
    Control window      subname:Rechner
    ${children}=    Run keyword and continue on failure
    ...    Get elements    class:whatever    timeout=0.1
    FOR   ${child}   IN   ${children}
       Get attribute    ${child}    Name
    END

Expectation:

1) ${children} is the empty list [] (Per documentation, Get Elements returns "A list of matching WindowsElement objects."). 2) The for-loop does not get run

Actual result:

1) ${children} is None 2) one iteration is produced where ${child} is None

(I am aware no. 2 is probably a problem of Robot Framework, so I will also report it there.)

For what it's worth, the Python behavior is:

empty_list = []
for x in empty_list:
    print(x)      
# this loop is not run

none_list = None
for x in none_list:
    print(x)
# TypeError: 'NoneType' object is not iterable
mikahanninen commented 9 months ago

You are wrapping Get Elements to be run with Run keyword and continue on failure. Latter does not return anything.

I would use in your case TRY/EXCEPT instead of Run keyword and continue on failure

*** Settings ***
Library     RPA.Windows     WITH NAME    Windows

*** Test Cases ***
Test
    Windows Run    Calc
    Control window      subname:Rechner
    TRY
          ${children}=    Get elements    class:whatever    timeout=0.1
          FOR   ${child}   IN   ${children}
             Get attribute    ${child}    Name
          END
    EXCEPT    AS    ${error_message}
        Log    FAILED: ${error_message}   
    END
    # Continue with other stuff
kkotenko commented 9 months ago

You are wrapping Get Elements to be run with Run keyword and continue on failure. Latter does not return anything.

Hm. Okay, then the documentation for Run keyword and continue on failure is not precise enough on this point. It says that "The keyword name and arguments work as with Run Keyword", which I took to mean that the return value of the keyword would be passed through to Run keyword and continue on failure (as it is for Run keyword). Which is an issue I will raise in the Robot Framework repository.

However, the documentation for Get elements says "Get a list of elements matching the locator.", so I would expect it to return an empty list instead of throwing an ElementNotFoundError (in my point of view, the empty list is the default value if the documentation says "get a list"). I understand that at this stage that cannot be easily changed, but what do you think of explicitly stating that the keyword will fail if no elements are found (and will, in fact, not return a list in this case)?

Thanks for your suggestion for my use case, it works beautifully.

mikahanninen commented 9 months ago

The issues with Robot Framework builtin libraries should be reported @ https://github.com/robotframework/robotframework repository as they are not under our control.