# Testing Promises and async/await — Jest, Vitest & Testing Library

Source: https://www.skillbyai.com/en/javascript-testing/a-promises

> Return or await, and test rejections too.

## The runner must wait for the promise

If a test starts async work and finishes without waiting, the runner marks it passed before the assertion runs, or the failure surfaces in a later test. Make the test function `async` and `await` the code, or `return` the promise. For the happy path, `await` and assert on the value, or use `await expect(promise).resolves.toEqual(...)`. For failures, use `await expect(promise).rejects.toThrow('...')`; forgetting the `await` here is a classic bug that makes the test pass no matter what. `expect.assertions(n)` asserts that exactly n assertions ran, which guards `try/catch` style tests where the catch might never execute.

## Make the clock and the network do what you say

Asynchronous code and time-dependent code become deterministic when the test controls promises, timers, dates and randomness.

![Three ideas: promises, fake timers, dates and randomness.](assets/figures/javascript-testing/section-3-map.svg) — Figure 3.1 — Await promises, fake the timers, pin dates and random values.

## Resolves, rejects and assertion counting

fetchUser returns a promise.

```typescript
import { it, expect } from 'vitest';
import { fetchUser, parseAge } from './users';

it('loads a user', async () => {
  const user = await fetchUser('42');
  expect(user.name).toBe('Asha');
});

it('loads a user (resolves form)', async () => {
  await expect(fetchUser('42')).resolves.toMatchObject({ id: '42' });
});

it('rejects an unknown id', async () => {
  await expect(fetchUser('missing')).rejects.toThrow('User not found');
  //  ^ without this await the test can pass even if fetchUser resolves
});

it('reports a parse error', async () => {
  expect.assertions(1);
  try {
    await parseAge('abc');
  } catch (err) {
    expect(err).toBeInstanceOf(RangeError);
  }
});
```

## Turn on the floating-promise lint

The typescript-eslint rule `no-floating-promises` flags an `expect(...).rejects` (or any promise) that is not awaited or returned, catching this bug before the test ever runs.

**Quiz:** What happens if you forget await before expect(p).rejects.toThrow()?

- [x] The test can finish and pass before the assertion is checked
- [ ] The runner automatically awaits it
- [ ] TypeScript refuses to compile
- [ ] The promise is cancelled

*Answer:* The test can finish and pass before the assertion is checked. Always await or return async assertions.
