React - Testing (Advanced)
Overview
Estimated time: 20–30 minutes
Extend the simple in-browser test harness to cover async behavior and user-driven interactions.
Try it: Async component tests
View source
function assert(name, condition){
const el = document.getElementById('results-adv');
const li = document.createElement('li'); li.textContent = `${condition ? 'PASS' : 'FAIL'} - ${name}`; li.style.color = condition ? 'limegreen' : 'salmon'; el.appendChild(li);
}
function sleep(ms){ return new Promise(r => setTimeout(r, ms)); }
function Counter(){
const [n, setN] = React.useState(0);
async function incAsync(){ await sleep(50); setN(x => x+1); }
return (<div><span id="val">{n}</span> <button onClick={incAsync}>+</button></div>);
}
async function runTests(){
const root = document.getElementById('sandbox-adv');
const r = ReactDOM.createRoot(root); r.render(<Counter />);
assert('initial is 0', root.querySelector('#val').textContent === '0');
root.querySelector('button').click();
await sleep(60);
assert('increments after async', root.querySelector('#val').textContent === '1');
}
Syntax primer
- Wrap tests in async functions and await UI updates driven by timers or promises.
- Arrange → Act → Assert: render the component (arrange), fire an interaction (act), then check expectations (assert).
- Use small helpers like
sleep(ms)
when simulating async work (timeouts, network).
Vocabulary
- Assertion: a check that must be true for the test to pass.
- Async test: a test that awaits an operation that completes later (e.g., a Promise).
- Act: the step where you simulate user input or time passing.
Common pitfalls
- Racing assertions before the UI updates; always await the condition change.
- Triggering React state updates outside React without giving React a chance to flush (await microtasks or small timeouts as needed).
Exercises
- Extend the Counter to support a "−" button with an async decrement and add a passing test.
- Add a loading indicator ("Saving…") shown while the async increment runs; assert it appears and then disappears.
- Write a retry button that increments only after two clicks (simulate by counting clicks) and test the behavior.
Checks for Understanding
- What pattern helps structure tests for readability?
- Why do async UI tests require awaiting updates?
Show answers
- Arrange → Act → Assert clarifies setup, interaction, and expectations.
- Because state updates and DOM changes happen later; without awaiting, assertions can run too early.