You are targeting an application that takes a variable amount time to perform a certain action. After finishing the action, you have to check for the existence of an optional element.
You decide to use an Element Exists activity with a long timeout to wait for the optional element. This works fine when the element appears, but when it does not appear, the robot waits an unnecessarily long time.
- The target app takes a long time to start and you have to check for a certain configuration after it started (e.g. the Ribbon being shown in Excel)
- After clicking Save, the target app tries to write to a database, but might fail, rolling back the transaction and displaying an error message
- You kick off a report that takes a long time to load, but may display a data loading error randomly, at which point you want to retry a few times
As the name implies, this Situation can be handled by using a Find Element activity followed by an Element Exists.
Let’s have a look at the example from MS Office: The Ribbon where the Ribbon may or may not be collapsed when the robot opens the application. After starting Excel, it will take a variable length of time until the application is actually ready.
Now, if you only used Element Exists to wait for the collapse button to appear, its timeout would have to be the maximum amount you expect the opening process to take. Let’s say you decide to wait for up to 2 minutes.
When the robot runs, there are two possibilities:
- The Ribbon is expanded and the collapse button is there - Element Exists finishes early and everything is fine
- The Ribbon is collapsed and the collapse button is missing - Element Exists will always wait the full 2 minutes, no matter how quickly Excel is actually loaded
To make handling the latter case faster is why we put Find Element before Element Exists: we look for an element that is always there when Excel is open and assume that, after this element has appeared, the collapse button will also be loaded very shortly (e.g. within 500 ms).
So if Excel only takes 5 seconds to open, and you put in 1 second as the timeout for Element Exists, the robot will continue after 6 seconds instead of waiting the full 2 minutes. Pretty substantial speed-up, huh?
This is a good pattern whenever the described situation occurs, but you should verify that this is indeed the case. In particular, make sure that there is absolutely no way of finding out if the element will appear except waiting for it.
Any use of Element Exists is a bit of a code smell because you have to make assumptions about how long of a timeout will tell you for certain whether or not the optional element appeared.
So if you can differentiate mutually exclusive states (e.g. because you get a success message only when the error message doesn’t appear), you should prefer Pick instead.
- Add Find Element to the workflow, set the timeout to a value large enough to accomodate the action you want to perform in all cases
- Add Element Exists to the workflow, set its timeout to a short value, but not too short (extremely short values may fail randomly depending on the WaitForReady setting)
- Decide how you want to handle the result
- This pattern is fairly simple, but the abstraction step of splitting the Element Exists into two parts can be difficult to discover
- Make sure to adjust the timeout for Element Exists - it defaults to whatever you set in the project settings (30 s)
- You only get a speed-up in case the element you are looking for is not there. If that is very rarely the case, this pattern won’t hurt, but it also won’t really help
- True Exception: you can use Find Element surrounded by Try/Catch or as part of a Retry Loop instead of Element Exists if the optional element hides your other element and is a true exception
- Pick: see When not to use
The pattern can be used as part of simple retry loops:
In a real workflow, you should add an escape condition after a certain waiting time or a certain number of attempts. There are many ways to achieve this, but I find the easiest to be extracting the loop into its own workflow and setting a timeout on the Invoke Workflow in the parent workflow. You could also use a Retry Scope activity by Throwing an error message if the error exists, or roll your own timeout solution, however.
- Build the retry loop for the sandbox
- What changes when you use two instances of Find Element instead of Element Exists?
- Consider the Excel example: is the Find Element necessary when you use Open Application? How about opening Excel with Excel Application Scope?
- Could you solve the Sandbox with Pick instead of Element Exists?