Snapshot Inside A Polled Callback
ID |
javascript.snapshot_in_async_utility |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
JavaScript |
Tags |
async, reliability, snapshot, testing |
Description
Reports a snapshot assertion inside a waitFor callback.
waitFor runs its callback again and again until it stops throwing. A snapshot matcher is the one assertion that must not be run that way, because it does not just compare — it also records.
The triage wrote this rule as "inside a waitFor or findBy* callback". The findBy* half does not exist: those queries take a matcher and an options object, never a callback. What is checked is the polling utilities, which are the ones that run a callback repeatedly.
Rationale
// Bad
await waitFor(() => {
expect(container).toMatchSnapshot(); // written once per poll
});
-
Snapshots are matched positionally within a test, so each poll asks for a different one: the first attempt writes snapshot 1, the second writes snapshot 2, and a test that polls five times leaves five entries where the author wrote one.
-
On the next run the counter lines up differently and the test fails for reasons unrelated to the component.
-
Where nothing is written, the first mismatch throws,
waitForreads that as "not ready yet" and retries until the timeout — so a real snapshot difference is reported as a timeout, with the diff that would have explained it never shown. -
An inline snapshot is worse still: the update pass rewrites the literal in the source from whichever retry happened to be last.