Asynchronous code where the timing is the behaviour. Under this runner the clock is virtual, so how long the retries waited is something a test can assert on exactly — which means the delay is not an implementation detail you are allowed to leave unchecked.
The module under test
| 1 | export function delay(ms) { | ||
| 2 | return new Promise((resolve) => setTimeout(resolve, ms)); | ||
| 3 | } | ||
| 4 | |||
| 5 | export async function retry(operation, options) { | ||
| 6 | const attempts = options.attempts; | ||
| 7 | const baseDelay = options.baseDelay; | ||
| 8 | let lastError = null; | ||
| 9 | for (let attempt = 1; attempt <= attempts; attempt++) { | ||
| 10 | try { | ||
| 11 | return await operation(attempt); | ||
| 12 | } catch (error) { | ||
| 13 | lastError = error; | ||
| 14 | if (attempt === attempts) { | ||
| 15 | break; | ||
| 16 | } | ||
| 17 | await delay(baseDelay * Math.pow(2, attempt - 1)); | ||
| 18 | } | ||
| 19 | } | ||
| 20 | throw lastError; | ||
| 21 | } | ||
| 22 |
Your tests
Mutants
0%
Mutation score
- Survived
- 0
- Killed
- 0 / 0
- Line coverage
- —
- Tests
- 0
- Assertion width
- —
- Cycle
- —
survivedkilledtimed outequivalentnot run