Lesson 3 of 5
Synchronization
18 min
Listen to this lesson
Most flaky Fiori scripts are not wrong about what to click. They are wrong about when. A UI5 app is asynchronous all the way through: views load lazily, OData requests run in the background, tables fill in batches, dialogs animate, the launchpad navigates between apps without reloading the page. A human waits until the screen settles without thinking. A script that does not wait clicks a button that is still disabled, reads a table before its rows arrive, or asserts on a message that has not been rendered yet.
What the app is busy doing
- OData requests: the app reads metadata, entity sets and value help, and posts changes, often bundled in
$batchrequests. - Busy states: controls or the whole app show a busy indicator while data loads. SAP's busy indication guidance notes that a busy control is covered by a block layer, so clicks and keyboard input do not reach it.
- Rendering and UI updates: after data arrives, controls re-render; growing tables add rows when the user scrolls or presses More.
- Animations and transitions: dialogs, popovers and navigation containers animate in and out.
- Timers and promises: debounced search fields and delayed work scheduled by the app or the framework.
- Navigation: routing inside an app, and cross-app navigation in the launchpad.
Why fixed sleeps fail
The tempting fix is a sleep: wait five seconds after every click. It fails in both directions. On a fast day the script wastes most of its runtime; on a slow day, during a month-end load or after a cache reset, five seconds is not enough and the script fails anyway. Sleeps also hide real performance problems, because nobody notices that a step now takes 4.9 seconds instead of 0.8. The right pattern is to wait for a condition with a timeout: until the control exists, is visible, is enabled and is not busy, and until UI5 has no pending work.
| Approach | How it waits | Typical result |
|---|---|---|
| Fixed sleep | Always waits N seconds | Slow on good days, flaky on bad days, hides performance drift |
| Wait for an element in the HTML | Polls until a DOM node appears | Better, but the node may exist while the control is busy or disabled |
| Wait for the control state | Polls for the UI5 control with matchers: visible, enabled, not busy | Reliable for the step at hand |
| Wait for UI5 to be idle | Waits until requests, timers, promises, animations and navigation have settled | Most reliable; the basis of UI5-aware tools |
How OPA5 and UI5-aware tools wait
OPA5 polls in every waitFor until its conditions are met or a timeout expires; the older API reference documents defaults of a 15-second timeout and a 400-millisecond polling interval, both overridable per call. Since UI5 1.42 OPA5 also has an autoWait option, off by default. The source documentation describes it: with autoWait, waitFor will not run its success step while there is pending asynchronous work such as open XMLHttpRequests, scheduled delayed work and promises, or unfinished UI navigation, and the control has to be enabled. The UI5 source tree contains separate waiters for XHR and fetch requests, timeouts, promises, navigation containers, UI updates, CSS and JavaScript animations and module loading.
The same machinery is exposed outside OPA5. RecordReplay's waitForUI5 waits for UI5 to complete processing, polling until all asynchronous work is finished or a timeout expires. This is what makes UI5-aware end-to-end tools reliable: before each interaction they ask UI5 itself whether it is idle. When you evaluate a browser automation approach for Fiori, this is the question to ask: does it synchronize with UI5, or does it only wait for HTML elements?
- LocateFind the control by selector (view and ID, or type plus matchers).
- Wait for idleNo pending requests, timers, promises, animations or navigation.
- Check interactableControl is visible, enabled and not covered by a busy indicator.
- ActPress, enter text, select. One business action at a time.
- Wait for outcomeAssert on the resulting state, not on time passing: message toast, new row, new view.
Special cases
- Asserting a busy state: the OPA5 cookbook notes that with autoWait on you cannot test a control in its busy state, because autoWait waits for it to become interactable. Switch autoWait off for that one step.
- Message toasts: toasts disappear after a few seconds; the cookbook recommends turning autoWait off only on the waitFor calls that check them, so the toast is not gone before the check runs.
- Growing tables: never assert "row 25 exists" until the table has loaded that many rows; assert on the count text or filter to the row you need.
- Draft saves: Fiori elements apps save drafts in the background as the user types; wait for the save to finish before pressing Save or the final activation can race with a draft update.
What would you do?
Maria reports that the automated Manage Sales Orders regression fails about one run in five at the step that reads the net value after adding an item for 50 CMC-ALT-100. The script waits three seconds after pressing Enter. What should the automation engineer change?
- Fiori apps are asynchronous: OData calls, busy states, rendering, animations, timers and navigation.
- Wait for conditions, not time: control state plus UI5 idle.
- OPA5 polls in waitFor; autoWait (off by default) waits for pending requests, timers, promises and navigation.
- RecordReplay waitForUI5 brings the same idle check to end-to-end tools; ask whether your tool synchronizes with UI5.
- Handle busy-state, toast and draft cases deliberately, and log which condition a timeout failed on.
Check your understanding · not graded
Lesson check
1. Why is a fixed five-second sleep after each click a poor synchronization strategy?
2. With OPA5 autoWait switched on, what does waitFor wait for before running its success step?
3. A script must verify that a table shows a busy indicator while loading. What is the catch with autoWait?
4. What should a good timeout failure log record?