Async call in ember testing
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Asynchronous behavior is normal in Ember applications. Routes load data, components trigger tasks, and services talk to APIs. Tests only stay reliable if they wait for those operations in a way that matches Ember’s run loop and rendering lifecycle.
Modern Ember testing already does a lot of waiting for you. The important part is knowing when built-in helpers are enough and when custom async work needs an explicit waiter.
Let Ember Test Helpers Do the Waiting
The first rule is simple: if you are using official test helpers, await them. Helpers such as visit, click, fillIn, and render return promises that resolve after Ember reaches a settled state.
A rendering test might look like this:
The helper calls plus await settled() give Ember time to process promise callbacks, rerender the template, and finish queued work.
Testing Data Loading in Application Tests
Application tests often involve routing and network requests. In those tests, the cleanest solution is to stub the backend and then await navigation.
If your project uses Mirage or Pretender, that network layer is already integrated into the test environment, which helps keep tests deterministic.
When Built-In Settling Is Not Enough
Problems start when async work happens outside Ember’s normal awareness. Common examples include:
- Manual
fetchcalls not tracked by the test environment - Third-party SDK callbacks
- Timers or web socket events
- Custom promises stored in services
In those cases, the test can finish before the async work is done, leading to flaky assertions. The fix is to register a test waiter.
You can then wrap the custom async operation so Ember knows the test should keep waiting until that promise resolves.
Example with a Service
Suppose a service fetches data with a plain async call. Wrapping the operation with a waiter makes the test environment aware of it.
Now your tests can keep using normal helpers and await settled() instead of inserting arbitrary timeouts.
Avoid Time-Based Tests
It is tempting to solve async failures with await new Promise((r) => setTimeout(r, 100)). That usually makes tests slower and still does not guarantee correctness. Timeouts hide the real issue, which is that the test framework does not know what work it is supposed to wait for.
A better pattern is:
- Stub the async dependency
- Trigger the UI action
- Await the helper or
settled() - Assert on the final rendered state
That gives you deterministic tests that describe behavior instead of timing guesses.
Common Pitfalls
One common mistake is forgetting to await Ember helpers. click and visit are async, so un-awaited calls can cause assertions to run before the UI updates.
Another issue is mixing real network calls into tests. Tests should control the async boundary with stubs or mock servers; otherwise failures become dependent on environment and latency.
Custom async behavior outside Ember is the biggest source of flakiness. If settled() does not seem to wait, that usually means the work is not registered with Ember’s waiter system.
Finally, avoid asserting on transient loading states unless your test deliberately waits for that specific intermediate moment. Otherwise the test may race past it.
Summary
- In Ember tests, always
awaitofficial test helpers such asvisit,render, andclick. - '
settled()is useful when you need to wait for follow-up async work and rerenders.' - Stub API calls so tests stay deterministic and do not depend on real network timing.
- Use test waiters for async operations that Ember cannot detect automatically.
- Avoid raw timeouts; they usually hide synchronization problems instead of solving them.

