Code optimization advice

So the below code iterates over a large number of rows. There are only few rows which might have radio button and few have a link that needs to be extended. Currently I am writing it this way. The issue is this piece of code is taking a long time to execute. I have written it in multiple way but there seems to be something fundametally making it slow. Is there any optimization method you would suggest?

Get Label Value Data
[Documentation]    Extract data from label-value format
[Arguments]    ${index}
&{label_value_data}    Create Dictionary
@{labels}    Get WebElements    (//div[@data-automation-id="fieldSetContent"])[${index}]/div//label[@data-automation-id="formLabel"]
@{values}    Get WebElements    ((//div[@data-automation-id="fieldSetContent"])[${index}]//ul/li/div[2]/div/div)
FOR    ${label}    ${value}    IN ZIP   ${labels}    ${values}    mode=SHORTEST
    ${label_text}    Get Text    ${label}

    ${radio_exists}    Run Keyword And Return Status
    ...    Get Child Element Attribute
    ...    ${value}    .//input[@type="radio"]    checked

    ${list_element_exists}    Run Keyword And Return Status
    ...    Get Child WebElement
    ...    ${value}    .//div[@data-automation-id="wd-MoreLink"]

    IF    ${radio_exists}
        ${is_checked}    Get Child Element Attribute
        ...    ${value}    .//input[@type="radio"]    checked
        IF    '${is_checked}' == 'true'
            ${value_text}
            ...    Get Text
            ...    ((//div[@data-automation-id="fieldSetContent"])[${index}]//ul/li/div[2]/div/div)//div[@data-uxi-radio-button-selected="true"]//label
        ELSE
            ${value_text}    Set Variable    ${EMPTY}
        END
    ELSE IF    ${list_element_exists}
        Click Element    //div[@data-automation-id="wd-MoreLink"]
        @{list_items}    Get WebElements    ((//div[@data-automation-id="fieldSetContent"])[${index}]//ul/li/div[2]/div/div)//div[1]//ul/li[@role="presentation"]//div[@data-automation-id="promptOption"]
        @{value_list}    Create List
        FOR    ${item}    IN    @{list_items}
            ${item_text}    Get Text    ${item}
            IF    '${item_text}' != ''
                Append To List    ${value_list}    ${item_text}
            END
        END
        ${value_text}    Evaluate    ", ".join(${value_list})
    ELSE
        ${value_text}    Get Text    ${value}
    END
    Set To Dictionary    ${label_value_data}    ${label_text}=${value_text}
END

RETURN    ${label_value_data}

Try to collect first the elements to a list of objects and later have another FOR to collect the data.

I have tried this. Basically there are few radio elements and links that can come up in any row and I have to check each row for this for sure. I’m guessing this is what is increasing the time for execution. This did not increase of my execution by any significant amount!

Hi Swapneil,

For loops and if statement’s themselves run in sub miliseconds, they are not slow, but rather the actions contained within are what can be slow.

What you have is not bad, and is quite similar to what I would do initially.

For making it quicker I would look at the time taken for these 3 lines:

    ${label_text}    Get Text    ${label}

    ${radio_exists}    Run Keyword And Return Status
    ...    Get Child Element Attribute
    ...    ${value}    .//input[@type="radio"]    checked

    ${list_element_exists}    Run Keyword And Return Status
    ...    Get Child WebElement
    ...    ${value}    .//div[@data-automation-id="wd-MoreLink"]
  • If getting ${label_text} is it slowish (>100ms?) then ask yourself do you really need to know the label if it’s not a radio button or list? if not this would be the first prime candidate to move, but it inside the IF and ELSE IF, yes that means an extra line of code, but it also means that 100+ms is only happening when it’s needed rather than on every row of the table
  • Next look at the time to get ${list_element_exists}, again is it slowish (>100ms?) then ask yourself do you really need to know this for every row? based on your code it seems if the row has a radio button then it won’t have a list element?, so could you structure the if statement like this (again reducing the number of times you get ${list_element_exists}) :
Get Label Value Data
[Documentation]    Extract data from label-value format
[Arguments]    ${index}
&{label_value_data}    Create Dictionary
@{labels}    Get WebElements    (//div[@data-automation-id="fieldSetContent"])[${index}]/div//label[@data-automation-id="formLabel"]
@{values}    Get WebElements    ((//div[@data-automation-id="fieldSetContent"])[${index}]//ul/li/div[2]/div/div)
FOR    ${label}    ${value}    IN ZIP   ${labels}    ${values}    mode=SHORTEST
    ${label_text}    Get Text    ${label}

    ${radio_exists}    Run Keyword And Return Status
    ...    Get Child Element Attribute
    ...    ${value}    .//input[@type="radio"]    checked

    IF    ${radio_exists}
        ${is_checked}    Get Child Element Attribute
        ...    ${value}    .//input[@type="radio"]    checked
        IF    '${is_checked}' == 'true'
            ${value_text}
            ...    Get Text
            ...    ((//div[@data-automation-id="fieldSetContent"])[${index}]//ul/li/div[2]/div/div)//div[@data-uxi-radio-button-selected="true"]//label
        ELSE
            ${value_text}    Set Variable    ${EMPTY}
        END
    ELSE

        ${list_element_exists}    Run Keyword And Return Status
        ...    Get Child WebElement
        ...    ${value}    .//div[@data-automation-id="wd-MoreLink"]
         IF    ${list_element_exists}
            Click Element    //div[@data-automation-id="wd-MoreLink"]
            @{list_items}    Get WebElements    ((//div[@data-automation-id="fieldSetContent"])[${index}]//ul/li/div[2]/div/div)//div[1]//ul/li[@role="presentation"]//div[@data-automation-id="promptOption"]
            @{value_list}    Create List
            FOR    ${item}    IN    @{list_items}
                ${item_text}    Get Text    ${item}
                IF    '${item_text}' != ''
                    Append To List    ${value_list}    ${item_text}
                END
            END
            ${value_text}    Evaluate    ", ".join(${value_list})
        ELSE
            ${value_text}    Get Text    ${value}
        END
        Set To Dictionary    ${label_value_data}    ${label_text}=${value_text}
    END
END

RETURN    ${label_value_data}

If this helps, then I’m sure you can find further optimisations,

Dave.

3 Likes

To add to what Dave has given, the logs/reports will give you a much better idea which actions are taking the longest. This would also be a good place to analyse to then aid in knowing which are taking the longest. I’d imagine wait for status for when it returns false is one of those that will flag up.

1 Like

Hi,

There’re already very good hints :slight_smile:
Had some issues with tests time, and I wanted to optimize a lit bit.
Attached is a simple script with ResultVisitor to get Keywords mean time and call number into a csv for analysis:

KwdTime.py (2.4 KB)

You just have to specify “mainpath” folder, with “Inputs” subfolder containing .xml files.
It will iterate and build a merged .csv file with info for each one.

Also as your mentioning rows, I had issues with table/list while using FOR loops as this was very long.
I finally used an Execute Javascript command to get/drop the table/elements at once (instant), and filter depending of needed elements. Then work on it for verification.

Something like this:

${table_data}    Execute Javascript    return Array.from(document.querySelectorAll("table tr"))
...        .filter(row => {
...            if (....rest of your filters need and logic....)

Regards.
Charlie

2 Likes

Okay this did increase my speed of code execution. However, the real culprit was the master code was running with a set speed limit on selenium which caused the delays. Once removed this code worked faster than my previous code. I really appreciate it. Thank you!!

2 Likes

Browser library is faster than Selenium. If it would be possible to switch to that, also it would give more speed.