Core concepts
Waiting and promises
Most waiting is already done for you. This is the rest of it — Wait For Condition, and how to run keywords in parallel with Promise To.
Most of the waiting you would write by hand is already happening. This page is about the part that is not, and about the opposite problem: when you need two things to happen at the same time.
What waits for you already
Three separate mechanisms, and it is worth knowing which is which, because when a test is flaky the fix depends on it.
| Mechanism | Waits for | Governed by |
|---|---|---|
So this is already a wait, and the most common one you will write:
And this is not — no operator, so it reads once and returns whatever is there:
That difference is the single most useful thing to know about waiting in this library. A getter with an assertion retries; a getter without one does not.
Both settings can be changed at import, and at runtime with Set Browser Timeout
and Set Retry Assertions For — each of which takes a scope, so you can widen
them for one test without widening them for the suite.
When that is not enough
The built-in waiting covers the element you are about to touch and the value you are about to check. What it does not cover is everything else the page might be doing: a spinner that has to disappear, an animation that has to finish, a framework that has to declare itself ready.
Two keywords do that job, and they are siblings. The difference is which side of the wire the condition lives on.
| Keyword | Evaluates | Reach for it when |
|---|---|---|
If you can already write a Get … assertion for it, use the first. If you would
have to open devtools to see it, use the second.
Wait For Condition
The rule is simple enough that you do not have to learn anything new. Write the
assertion as an ordinary getter first, get it passing, and then take the Get
off the front:
Everything after the condition name is that getter's own arguments, so anything you already know how to assert, you already know how to wait for.
Most getters that take an assertion can be used, but not all — the id getters,
the storage getters, Console Log, Page Errors and Aria Snapshot are not
among them, and passing one fails with a conversion error rather than waiting.
The keyword documentation lists the exact set.
The pairing that does most of the work
Get Element States returns the set of states an element is in right now, and
that is what makes it the most useful condition of the lot: one keyword covers
every "wait until this element is…" case, including the ones no dedicated
keyword exists for.
The states come in opposites, which is the part worth internalising:
| If you are waiting for | Wait for the state |
|---|---|
So the four cases you will actually hit:
contains means all of these are true, so you can list as many as you need.
== means the set is exactly that, which is why == detached is the honest
way to wait for something to disappear: an element that is gone reports
detached and nothing else.
Wait For Function
The other half of the pair. Where Wait For Condition asks a Browser getter,
this one runs JavaScript inside the page and keeps running it until it
returns something truthy.
Reach for it when the thing you are waiting for is not in the DOM in any way a selector can express — it is in the application's own state:
That last one is the flavour of problem this keyword exists for: nothing about
"every image has settled" is expressible as a selector, and no getter returns
it. Note what complete actually means — loading finished, including having
failed. If you need them to have loaded successfully, add
&& i.naturalWidth > 0.
Waiting on one element
Pass a selector and it is resolved and handed to your function as its first
argument. The condition then becomes a question about that element, evaluated
in the page where the real computed values live:
Two things to know about that first one. element.style is the inline style
attribute, not the computed value — it only sees a width the application wrote
onto the element itself, never one that came from a stylesheet. And computed
values are not out of reach for the sibling keyword either: Wait For Condition
with Style reads getComputedStyle, and with BoundingBox it reads geometry.
Canvas pixels are the genuine case where only JavaScript will do.
Polling
By default it polls on requestAnimationFrame — once per frame, which is the
right choice for anything visual, because it re-checks exactly when the browser
repaints. Give polling a time instead when you are waiting on something slow
and want to stop burning frames on it:
Two things that catch people
Truthy is JavaScript's truthy. 0, '', null and undefined all read as
"not yet", so element => element.children.length waits for a non-empty list
without you writing the comparison, and () => document.querySelector('.x')
waits for the element to exist, because a missing one is null. If your function
takes the element, declare the parameter — a bare element inside a zero-argument
arrow is not defined and, thanks to the next paragraph, costs you the whole
timeout before it says so.
Any error is treated as "not yet", for the length of the timeout. That is
what makes () => window.myApp.ready safe to run before myApp exists — but it
applies to every error, not only the one you were expecting. A typo in your
JavaScript, or a selector that matches two elements, is retried silently for the
full timeout and only then surfaces.
Choosing between them
| You are waiting for | Use |
|---|---|
Prefer the first wherever it fits. A condition written against a getter fails with a message naming what the value actually was; a JavaScript one that simply stayed false fails with a timeout and leaves you to work out why.
Promises
Everything above waits for something to become true. Promises are the opposite: they let a keyword run while your test carries on doing something else.
The idea, if it is new
A promise is a placeholder for a result that does not exist yet.
Normally a keyword blocks: the test stops until it finishes, then continues with
the answer. Promise To breaks that in half. It starts the keyword and
hands you back a token immediately. The keyword goes on running in the
background while your test does the next thing. Later you present the token and
collect the result — waiting at that point only if it has not finished yet.
The reason this matters is that some things can only be observed while something else happens. To catch a network response you have to be listening before the click that triggers it — but if you start listening with an ordinary keyword, the test never reaches the click. The listening and the clicking have to overlap, and that is what a promise is for.
The call order
Always three steps, in this order:
Promise Tostarts the keyword and returns the promise. It waits until the promised keyword's thread is actually running before returning, which removes the worst of the race — though it does not wait for the browser-side listener itself to be registered.- The thing that triggers it — a click, a navigation, whatever.
Wait Forcollects the result, blocking only if it is not ready.
Getting the order wrong is the usual mistake: click first and the response has come and gone before anything was listening.
Collecting several
Wait For takes any number of promises and returns their results in the order
you passed them, not the order they finished:
With one promise you get the result itself; with several you get a list.
Wait For All Promises waits for everything created and not yet collected,
which is what you want when you do not need the results:
Any Browser keyword can be promised
This is the part people miss. Promise To is not limited to a handful of
"async" keywords — it takes any keyword in this library, with its normal
arguments:
Which means two slow waits can overlap instead of queueing:
Both getters retry independently, so the test waits about as long as the slower one rather than the sum of the two. Promises run on a thread pool — up to 256 at once — so they really are in flight together rather than taking turns.
The two purpose-built promises
Downloads and uploads both need something in place before the click that starts them, so they have dedicated keywords rather than being wrapped by hand:
Promise To Upload File waits for the file chooser dialog to appear, so the
click that opens it has to come after the promise — the same order as everything
else on this page. It fails immediately if the path is not an existing file.
If you can set the file directly, Upload File By Selector does it in one
keyword and avoids the ordering question entirely.
In short
- A getter with an assertion operator is a wait. Without one, it reads once.
- Two keywords cover the rest, and they are siblings:
Wait For Conditionasks a Browser getter,Wait For Functionasks the page. If you can write theGet …assertion, use the first. Wait For Conditionneeds no new syntax — write the getter assertion, then drop theGet.Wait For Condition+Element Statesis the one that handles most cases; the states come in opposites, and== detachedis how you wait for something to be gone.Wait For Functionis for what only the page knows: readiness flags, animations, computed geometry, application state that never reaches the DOM. A throw counts as "not yet", so it is safe to poll for something that does not exist yet.- Promises are start-now, collect-later. The order is always
Promise To→ trigger →Wait For. - Any Browser keyword can be promised, and promises really do run in parallel —
promise the getters rather than
Wait For Condition.