An action results in more than one possible outcome, but only one of them may happen for any given process run.Check it out in the Sandbox
- You press a save button, the app performs a validation, and then displays either a success or an error message
- You try to load a file, but the app cannot find it and therefore display an error message. If the file is found, it continues to the next screen
- After entering username + password, you are either redirected to the correct page, or the app displays an error message
Find Element Exists is a similar pattern that deals with optional pop-ups
Pick searches - in parallel - for multiple alternative Trigger elements, but only executes one Action: the one whose trigger finished first. All other triggers are then cancelled.
Pick should be considered the default solution for this problem. It is usually the best choice unless otherwise indicated
The only element you can find in any of the Pick Branches is unreliable. For example, the element is always present in the background (and FindVisible doesn’t work), loads multiple times, or has very unstable selectors. In this case, using Element Exists may be a better choice
Optional pop-ups. That is, the background always loads and events are not mutually exclusive. In this case, you have little choice but to use Element Exists. Note that this is, strictly speaking, a different Situation.
- Add Pick to the workflow
- Drag two Pick Branches onto the Pick activity
- Drag one Find Element onto the Trigger section of each Pick Branch. Configure as appropriate
- Configure the Action section of each Pick Branch as befits your project
- It is strongly recommended to set the timeout for all triggers to the same value. Otherwise you may run into a timeout exception in one trigger when perhaps another one would still have worked
- The pseudo-parallel execution of the triggers can be a bit hard to understand. Brush up on it if you run into weird problems.
- Make sure you test all branches. It’s very easy to miss one, especially if more than two different things can happen.
- Triggers cannot be empty, but they can contain empty sequences and commented-out sections. This can be useful for debugging branch actions by commenting out the trigger.
- You can put other activities than Find Element into the Trigger. The action of the trigger activity that finishes first will be executed. See Variants below
- Do not use part of the action as the trigger (e.g. do not use a Click activity as the trigger). This makes the code harder to read and debug.
- Some caution is in order, as not all activities can be gracefully canceled.
- Other triggers: The most useful alternatives to Find Element are its close cousins, such as Find Image, Find Text, Wait Element Vanish, etc.
- Default trigger: Sometimes, using a delay in one of the branches as a default action makes sense (if there’s a possibility that nothing happens)
- Loop trigger: You can enhance the power of triggers with custom loops, for example to check for an element having a certain text with Get Text in a Do While loop. In this case, it is recommended to extract the loop into a subworkflow so you can add a timeout
- Add a third Pick Branch to the sandbox in case nothing happens
- Think about an application where you can get an error message (say, the UiPath login page). Is there any way you could build an automated test case for each branch?
- How could you handle a situation where a loading bar or spinner animation stopping is the only indication of success?
- How could you perform the same action for multiple different Pick Branches? (There are several solutions)
Element Exists looks for an element - if found, it immediately returns true. If not found, it will wait until its timeout is exceeded, then return false.
Optional pop-ups. Because Element Exists does not need to be guaranteed to find anything, it can be used for optional pop-ups that may or may not appear when the other parts of the app don’t change
For mutually exclusive options
- Add Element Exists to the workflow and set its Target to the pop-up
- Set the timeout to a value after which you are sure the pop-up should have appeared
- Create a new variable popUpExists for the result
- Add an If activity with popUpExists in the condition
- In the Then branch of If, perform your action for the pop-up
- Make sure to check out Find Element Exists in case that is closer to the situation at hand
- It is not recommended to sequentially chain multiple Element Exists because the timeouts add up. If you feel like doing that, consider Pick instead or at least use Parallel to execute them at the same time
- In the optional pop-up situation, there is a trade-off between waiting a long time in case the pop-up doesn’t appear and possibly running into an error because you prematurely assumed the pop-up would not appear. So which timeout you should choose depends on the typical latency of the application as well as on how often the pop-up appears.
This combo can be an option if all of the mutually exclusive options write text to the same place.
Much rarer than the above solutions but good to have in your tool belt.
You get an error message and a success/confirmation message in the same place. This can happen often in terminal automation or in certain GUI apps, such as SAP WinGUI
- Add Get Text or a similar activity to read the status message
- Add Switch and set the TypeArgument to String
- Add the different text options with appropriate actions
- If: Use a series of If statements (or Flow Decisions) instead of Switch in case you want to do fancier checks such as regular expressions or substring comparison. This is less bad than with Element Exists because the operations are usually fast.
- Data Scraping: Sometimes the result will be displayed in a table alongside other information. In this case, using Data Scraping can help.
- Get Attribute: If you need to use another attribute than text. This is particularly useful for things such as images (think warning icons and the like), which may have a src or class attribute, especially in web apps
In theory you can fake a behavior similar to what Element Exists does by adding a Click inside the Try block of a Try/Catch and another Click in the Catch block for the error option.
A common way this can come about is if you run into “unexplained” SelectorNotFound exceptions because the error case was not in the specification. As a stopgap, you added the Try/Catch and a recovery, but later found out that there is an error message when this happens.
The problem with the Try/Catch is that it is very opaque as the error case is usually not “exceptional”. In combination with the annoying folding UiPath does for its Try/Catch designer, this leads to poor readability.
Furthermore, and probably more importantly, the Try/Catch solution shares the potentially long waiting time of the Element Exists solution for the case you put into Catch.
I would suggest to refactor this into the Pick solution unless it really is an exception.
This is a mistake I see many rookies make: you implement an automation in a certain way, because that seems like the only relevant way to do the process. So it feels natural to use your knowledge of how the process is supposed to run to predict which of the different options that are theoretically possible is going to happen.
But unless you are positive that there can never be exceptions, such as, for example, bad user input, this often turns out to be a bad idea. Try to develop workflows by making as few assumptions as possible - this is called “defensive programming”. Within reason, of course, as some assumptions are necessary or simplify things immensely
That doesn’t mean that you need to add special handling for every possible case, but adding at least a single catch-all error case is usually a good idea in cases such as hitting a save button. As a general rule of thumb, I would say that if more than 2% of cases are likely exceptions, I would start adding an error case.