Testing & QA

Assertions and matchers — what a good assertion actually checks

A test can pass while checking almost nothing meaningful — the gap between a real assertion and a weak one is one of the most common ways a test suite quietly stops protecting anything.

Beginner

3 min read

A test that passes without actually verifying the thing it claims to

test("returns the user's full name", () => {
  const result = getFullName({ first: "Ada", last: "Lovelace" });
  expect(result).toBeTruthy(); // passes for "Ada", "wrong", "x", literally any non-empty string
});

toBeTruthy() passes for any non-empty, non-zero, non-null value — it would pass just as happily if getFullName had a bug and returned "undefined undefined" or the wrong name entirely, as long as something non-empty came back. This test's name promises "returns the full name," but its assertion actually checks "returns something," which is a much weaker claim than the test's own name suggests — the exact gap that makes weak assertions dangerous: the test looks like coverage in a test report, but doesn't actually protect the behavior it claims to.

The fix: assert the specific expected value

test("returns the user's full name", () => {
  const result = getFullName({ first: "Ada", last: "Lovelace" });
  expect(result).toBe("Ada Lovelace"); // now a wrong implementation actually fails this test
});

toBe() (or toEqual() for objects/arrays) checks the exact expected value, which means a real bug in getFullName — wrong order, missing space, wrong casing — now actually fails the test. The rule of thumb: an assertion should be specific enough that if you deliberately broke the function being tested, this exact test would be the one that caught it. If you can imagine a real bug that would still sail through the assertion unnoticed, the assertion isn't specific enough yet.

toBe vs toEqual: reference equality vs structural equality

const expected = { name: "Ada", role: "admin" };
 
expect(getUser()).toBe(expected);   // fails even for an IDENTICAL-looking object —
                                     // toBe checks reference equality (===)
expect(getUser()).toEqual(expected); // passes if the CONTENTS match, regardless of reference

This is the same reference-vs-structural-equality distinction that shows up throughout JavaScript (and gets its own dedicated treatment in this platform's React domain, where it drives useEffect dependency comparisons): toBe is ===, which for objects and arrays means "the exact same object in memory," not "looks the same." Using toBe on an object or array almost always fails for the wrong reason — not because the data is wrong, but because it's a different (if identical-looking) object. toEqual compares structure — every key and value — which is what you actually want for objects and arrays in the overwhelming majority of tests.

Asserting on the right level of detail

// Too loose — barely tests anything
expect(response.status).toBeLessThan(500);
 
// Too brittle — breaks on any unrelated field ever being added to the response
expect(response.body).toEqual({
  id: 123, name: "Ada", createdAt: "2026-08-31T10:00:00.000Z", updatedAt: "2026-08-31T10:00:00.000Z",
});
 
// Right level — checks exactly what this test is actually about
expect(response.status).toBe(200);
expect(response.body.name).toBe("Ada");

Asserting on an entire object when the test is really only about one field means the test breaks every time an unrelated field is added or a timestamp changes — a real, common source of the "flaky test" problem the next-but-one lesson covers, and a reason contributors learn to distrust a suite that fails on unrelated changes. Assert precisely what the test's name claims it's checking, and nothing more.

Further reading

Check your understanding

A quick comprehension check — not tracked, not graded, just for you.

1. Why is `expect(result).toBeTruthy()` often a weak assertion?

2. What's the actual difference between `toBe` and `toEqual`?

3. Why can asserting on an entire response object instead of just the relevant field make a test suite less trustworthy over time?