Integration & Coverage
Chapter 1's testing pyramid named "integration tests" as its middle layer, but Chapters 2–7 have stayed mostly at the component level. This chapter finally writes a genuine integration test, then turns to two different topics: what code coverage actually measures (and where it misleads), and the accessibility-testing tool that closes the loop back to web-accessibility1.
From Component Tests to Integration Tests
A component test renders one component, often with mocked props/children. An integration test renders a parent alongside its real children, exercising how they actually communicate — using Chapter 6's MSW to fake the underlying API, since the point is exercising the real component wiring, not a real network:
Neither SearchForm nor SearchResults is mocked — the test proves they genuinely work together, not just individually.
Code Coverage: What It Measures
jest --coverage reports what percentage of lines, branches, functions, and statements were executed during the test run — useful as a rough signal for finding obviously untested code, not as proof of correctness.
Why 100% Coverage Can Be Misleading
A line being executed says nothing about whether it was actually asserted on correctly. Consider a genuinely hollow test:
This test contributes real coverage percentage while catching precisely zero bugs. 100% coverage is neither necessary nor sufficient for a genuinely well-tested codebase — coverage finds obviously neglected code (0% on an entire file is a real red flag), it doesn't validate that the tests which do exist are meaningful.
Setting Sensible Coverage Thresholds
Jest's coverageThreshold config option fails the test run if coverage drops below a set percentage — a practical floor (commonly 70–80%) that catches obviously-neglected code, not a target chased for its own sake. A team mandate of "100% coverage or the PR is blocked" actively incentivizes exactly the hollow test shown above.
Accessibility Testing with jest-axe
jest-axe runs automated accessibility checks — missing labels, invalid ARIA usage, and more — against rendered output, closing the loop directly to web-accessibility1:
Automated checks like axe catch only a subset of real accessibility problems — structural/markup issues, not things like whether an error message makes logical sense in the order a screen reader announces it. Manual testing, exactly as web-accessibility1 covers, is still necessary — axe is a floor, not a substitute.
Coverage as a Signal vs. Coverage as a Target
As a Signal
Flags obviously untested files/branches — a useful early-warning tool.
As a Target
Chasing 100% actively rewards hollow, assertion-free tests that inflate the number without catching bugs.
Integration Test
A parent rendered with its real children, exercising actual communication between them.
Coverage Report
What percentage of code ran during tests — a signal for gaps, not a correctness proof.
coverageThreshold
A practical floor (e.g. 70–80%) that fails builds below it — not a 100% mandate.
jest-axe
Automated, structural accessibility checks — a floor, not a replacement for manual review.
axe-core (the engine behind jest-axe) has bindings across the ecosystem — cypress-axe, framework-agnostic axe-core usage in Vue/Angular/Svelte test suites. The same automated-accessibility-as-a-floor approach transfers across frameworks, exactly like Chapter 7's core testing philosophy did.
axe only catches automatically detectable issues — missing alt text, invalid ARIA, certain contrast problems. It cannot catch whether an error message's reading order actually makes sense to a screen reader user, or whether a keyboard-only flow is genuinely usable end to end. Treating a green jest-axe result as "done" directly contradicts web-accessibility1's own point: automated tools are a floor, never a ceiling.
Coding Challenges
Write an integration test for a TodoApp component containing a real AddTodoForm and a real TodoList: typing a new todo and submitting should make it appear in the list, using no mocks for either child component.
📄 View solutionExplain, with a concrete example different from this chapter's own, how a test could achieve 100% line coverage of a function while still failing to catch an obvious bug in that function's logic.
📄 View solutionWrite a jest-axe test for a component, then describe one realistic accessibility problem it would NOT catch, and briefly explain why axe is structurally unable to detect it.
📄 View solutionChapter 8 Quick Reference
- Integration test — a parent rendered with its real children, no mocking of the components themselves
jest --coverage— reports line/branch/function/statement execution, not correctness- 100% coverage is neither necessary nor sufficient — a hollow, assertion-free test still counts toward it
- coverageThreshold — set a practical floor (70-80%), not a 100% mandate that incentivizes hollow tests
- jest-axe —
axe(container)+toHaveNoViolations()for automated accessibility checks - Automated accessibility checks are a floor — manual testing (per web-accessibility1) is still required
- Both the coverage-as-target trap and the axe-is-enough trap share one lesson: automated numbers are a signal, not a substitute for real review
- Next chapter: Capstone — a complete test suite for a real feature, combining every tool from this course