Real Bug Clinic
Start from the production symptom, not the JavaScript term.
Choose a real problem like flaky tests, slow APIs, memory growth, frozen UI, worker-pool pressure, or stream failures. Then open the visual case that teaches the fix.
Real Bug Clinic
Start from the symptom you actually have, then open the case that teaches the fix.
Testing - Risk High
My async test is flaky
Flaky tests waste team time and hide real regressions because nobody trusts the suite.
Likely cause: Timers, promises, and assertions are not being flushed in the same order as the real runtime.
Diagnose
- - Check whether the test advances timers but forgets promise continuations.
- - Look for setTimeout(..., 0), Promise.then, await, and fake timers in the same test.
- - Write the expected output order before changing the test.
Fix direction
- - Flush microtasks before asserting timer effects.
- - Prefer awaiting user-visible outcomes instead of implementation timers.
- - Keep retry/debounce timing behind one helper.
Verify
- - Run the test repeatedly.
- - Run the same test with real timers if possible.
- - Remove arbitrary waits after the order is explicit.
Related learning cases
Concepts behind this bug
Concept breakdown
Why output order changes
Synchronous code runs first, microtasks drain before timers, and Node adds extra queues like nextTick and check.
Mental model: Do not read async code only from top to bottom. First ask where each callback is placed: current stack, microtask queue, timer queue, Node nextTick, I/O, or check.
Common wrong assumption: Assuming setTimeout(..., 0) means run immediately, or assuming promises and timers share the same queue.
Real-world signals
- - Console output differs from source order.
- - Tests need mysterious waits.
- - Cleanup runs later than expected.
- - setImmediate and setTimeout order feels inconsistent.
Debug questions
- - What runs on the current stack?
- - Which callbacks enter microtasks?
- - Which callbacks enter timers or Node-specific queues?
- - Is this browser behavior or Node behavior?
Concept breakdown
Why await did not wait
await pauses only the current async function. Missing await, async forEach, and unreturned promises let code continue too early.
Mental model: Every async operation must be either awaited, returned, or intentionally allowed to run in the background with error handling.
Common wrong assumption: Calling an async function like a normal function and assuming later code waits for it.
Real-world signals
- - Success UI appears before save finishes.
- - Bulk work logs complete too early.
- - A test finishes before setup completes.
- - The next .then receives undefined.
Debug questions
- - Is the promise awaited or returned?
- - Is async work inside forEach?
- - Does every .then return the value needed later?
- - Where are errors caught?
Learn this with