-
Notifications
You must be signed in to change notification settings - Fork 454
Taiko's Wait Mechanism
One of the important visions of Taiko is to eliminate flakiness in UI automated end to end tests. Taiko tries to achieve that by implicitly waiting for readiness of elements and events triggered after action, and also provides better custom wait mechanisms for users to use. This helps in waiting for the right state of the page to perform any action instead of arbitrarily adding waits with time that leads to flakiness and increase in execution time. There are two types of waits in Taiko namely implicit and explicit waits.
Default element readiness timeout(retryTimeout) is 10 seconds.
-
Exists: Checks if an element is present in the DOM.
-
Visibility: Checks if an element is visible asserting its boundary on the document. https://github.com/getgauge/taiko/blob/f98acd6f70ae5c3ad76097455e3f78a9ec461d55/lib/elements/element.js#L40
-
Not disabled: Checks if an element is disabled by getting the
disabled
attribute. https://github.com/getgauge/taiko/blob/f98acd6f70ae5c3ad76097455e3f78a9ec461d55/lib/elements/element.js#L59 -
Writable: Check if an element is writable by asserting if it is not readonly or disabled and it is anyone of the following elements [Input, Select, Textarea, element with contentEditable attribute set true] https://github.com/getgauge/taiko/blob/f98acd6f70ae5c3ad76097455e3f78a9ec461d55/lib/handlers/runtimeHandler.js#L184
-
Not covered: Checks if an element on which the action has to be performed is the same element at point(x,y coordinate on screen). Asserts that by finding the center point of the element’s bounding box and checking document.getElementAtPoint() gives the same element or its parent or child. https://github.com/getgauge/taiko/blob/f98acd6f70ae5c3ad76097455e3f78a9ec461d55/lib/taiko.js#L1116
TODO: Connected and stability checks - https://github.com/getgauge/taiko/issues/1512 Making check consistent across actions - https://github.com/getgauge/taiko/issues/630
Default timeout(navigationTimeout) for events after action is 30 seconds. And that is done by a wrapper around all actions (https://github.com/getgauge/taiko/blob/master/lib/doActionAwaitingNavigation.js)
-
TargetCreated: When a new tab or window is created by an action, Taiko automatically makes a new remote debugging connection to the newly created target.
Events from CDP:
https://chromedevtools.github.io/devtools-protocol/tot/Target/#event-targetCreated \Implementation in Taiko:
https://github.com/getgauge/taiko/blob/master/lib/handlers/targetHandler.js
https://github.com/getgauge/taiko/blob/f98acd6f70ae5c3ad76097455e3f78a9ec461d55/lib/taiko.js#L238 \ -
Request: When an action is performed Taiko waits for a stipulated time (waitForStart) to gather any request being triggered after the after and waits for those to get completed.
Events from CDP:
Gather requests from https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-requestWillBeSent
Gathered requests are resolved either when loading finished or failed
https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-loadingFinished
https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-loadingFailed \Implementation in Taiko:
https://github.com/getgauge/taiko/blob/master/lib/handlers/networkHandler.js -
FrameLoad: When an action is performed Taiko waits for a stipulated time (waitForStart) to gather any frame load or frame navigation events that are triggered and waits for those to get completed.
Events from CDP:
Gather frame loads and navigation from
https://chromedevtools.github.io/devtools-protocol/tot/Page/#event-frameStartedLoading
https://chromedevtools.github.io/devtools-protocol/tot/Page/#event-frameScheduledNavigation
Gathered frame changes are resolved either when they are complete or cleared
https://chromedevtools.github.io/devtools-protocol/tot/Page/#event-frameNavigated
https://chromedevtools.github.io/devtools-protocol/tot/Page/#event-frameClearedScheduledNavigation
https://chromedevtools.github.io/devtools-protocol/tot/Page/#event-frameStoppedLoading \Implementation in Taiko:
https://github.com/getgauge/taiko/blob/master/lib/handlers/pageHandler.js \ -
PageLoad: For every action Taiko waits until page’s readyState becomes
complete
Implementation in Taiko:
https://github.com/getgauge/taiko/blob/f98acd6f70ae5c3ad76097455e3f78a9ec461d55/lib/doActionAwaitingNavigation.js#L126
Apart from the implicit waits mentioned above Taiko also provides various ways to do custom waits based on required to avoid arbitrary sleeps.
-
Customising default timeout: In some cases the default timeout may not be sufficient as page load or events might take more time. To address that default timeout can be update in two ways,
1] global - usesetConfig
api to set navigationTimeout, retryTimeout
2] local - set option to actions Eg: https://docs.taiko.dev/api/click/ -
Wait for events: Taiko emits CDP’s lifeCycleEvents ['DOMContentLoaded', 'loadEventFired', 'networkAlmostIdle', 'networkIdle', 'firstPaint', 'firstContentfulPaint', 'firstMeaningfulPaint'].
Chromium uses few heuristics to determine if the page has loaded meaningfully to the user. Taiko uses readyState to be complete as the default event to wait for which ensures page load. And there were issues where the firstMeaningfulPaint event was not triggered by the browser hence moved from using that as default letting users choose to use it as per need. -
Wait for element: There can be cases where a test's action has to be performed on a particular element only when another element exists. Taiko’s waitFor api can be used in this case with an element selector,
Example:await waitFor(button(‘submit’))
-
Wait for a predicate: There can be cases where a test's action has to be performed on a particular element only when some condition is satisfied. Taiko’s waitFor api can be used in this case with an predicate,
Example:await waitFor(() => button(‘submit’).isVisible())
-
Wait for a time period: As a last resort if none of the above implicit waits and explicit waits help, Tests can use waiting with time using Taiko’s waitFor api that takes time in milliseconds. Example:
await waitFor(10000)