Assertion Outside a Test Case
ID |
javascript.assertion_outside_test |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
JavaScript |
Tags |
assertion, reliability, testing |
Description
Reports an assertion in a spec file that does not run inside a test case or a lifecycle hook: one written at the file’s top level, or directly in a describe(…) callback.
A suite callback runs once, while the runner is collecting the file — before any hook has set anything up, and outside any test.
An assertion inside any other function is not reported: a custom matcher, a shared assertCartEmpty(cart) helper or a callback handed to the code under test all assert from inside a function that a test calls, which is the normal way to factor a suite. One finding is reported per assertion chain.
Rationale
// Bad
describe('cart', () => {
let cart;
beforeEach(() => {
cart = new Cart();
});
expect(cart.total).toBe(0); // runs at collection time, when cart is undefined
it('starts empty', () => {
expect(cart.total).toBe(0); // runs as part of the test
});
});
-
The assertion sees the state before any hook has run, so it reads
undefinedwhere the test would read a fixture. -
A failure at collection time is not attributed to a test: the runner reports an error against the whole file, and every test in that file is dropped. One misplaced line takes out a suite.
-
Because it runs exactly once, it cannot check anything a test does — it observes the module’s own load-time state, which is not what the suite is about.
-
When it happens to pass, it does so silently and stays, and the next person to add a hook finds a failure that no test name points at.
Remediation
Move the assertion into the test it belongs to, or into a hook if it is a precondition every test shares.
// Good
describe('cart', () => {
let cart;
beforeEach(() => {
cart = new Cart();
expect(cart.total).toBe(0); // a precondition, checked before every test
});
it('starts empty', () => {
expect(cart.items).toHaveLength(0);
});
});