Promise Passed To An Event Dispatch
ID |
javascript.promise_in_fire_event |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
JavaScript |
Tags |
async, reliability, testing |
Description
Reports a promise handed to fireEvent or userEvent as an argument. Both take a DOM node and, optionally, an event-init object; neither awaits anything it is given, so a promise in either position is used as the object it is.
Three shapes of argument are read as a promise, all of them stated in the source: a findBy* or findAllBy* query, a chain ending in .then() / .catch() / .finally(), and a Promise.*(…) or new Promise(…).
An argument that is a call to a locally declared async function is left to javascript.missing_await, which resolves the callee and already reports a promise consumed as a value in any position.
Rationale
// Bad
fireEvent.click(screen.findByRole('button')); // clicks a Promise
-
The asynchronous queries look almost exactly like the synchronous ones —
getByRolereturns the button,findByRolereturns a promise of the button — so the missingawaitreads as correct code. -
Dispatching at a Promise object hits nothing: it has no event target, no handler runs, and no error is raised.
-
The interaction simply does not happen, and the assertion that follows fails for a reason that points nowhere near the missing keyword.
-
In the event-init position the same mistake produces an event whose properties are all undefined, which handlers read as a default event rather than the one the test described.