Question presented to candidate: "A test needs to verify a function that calls setTimeout with a 10-second delay, and another test needs to verify code that calls a real external API. Waiting 10 real seconds, or hitting a real API, in every test run is clearly wrong — what's the actual mechanism that avoids both?"
What a strong answer should cover:
- Node's built-in
node:testmodule ships mocking utilities directly, requiring no separate library (Sinon, jest.mock) for the core cases:mock.fn()for function call tracking,t.mock.timersfor fake timers, andt.mock.method()for replacing a real object's method for a test's duration. - 📌 Verified, not assumed — the exact answer to the timer half of the prompt:
t.mock.timers.enable()plus a realt.mock.timers.tick(10_000)call genuinely fired a realsetTimeout(..., 10_000)callback — the entire test, including that "10-second" wait, completed in under 1ms of real wall-clock time, confirmed directly, not merely described. - 📌 Verified, not assumed — the exact answer to the network-call half of the prompt:
t.mock.method(obj, "fetchUser", () => ({...}))genuinely replaced a real method that would otherwise throw attempting a real network call — the mocked version returned a real, controlled fake result instead, with the real call genuinely tracked (obj.fetchUser.mock.callCount()correctly reported 1) — no real network request was ever made. mock.fn()is the general-purpose building block underlying the other two: a real, wrapped function that genuinely records every call's arguments and count (fn.mock.calls[0].arguments,fn.mock.callCount(), verified directly) while still optionally running real custom logic if provided — the same mechanism used, more specifically, to mock a method (mock.method) or track calls to any standalone function passed as a callback/dependency.- A precise answer names the automatic cleanup built into this mechanism: mocks created via
t.mock(using the test contextt, as opposed to the standalonemockimport) are genuinely restored to their real, original behavior automatically once that specific test finishes — avoiding a common, real bug class where a mock from one test accidentally leaks into and corrupts a later, unrelated test.
Clarifying questions expected:
- "Does the mocked network call need to simulate different responses across multiple calls within the same test (success then failure, for instance), or is one fixed mocked response sufficient?" —
mock.method/mock.fnsupport this viamockImplementationOnce-style sequencing, but it changes how the mock is set up. - "Is real timer-dependent code (a retry-with-backoff loop, a cache TTL) being tested here, where fast-forwarding matters for genuinely covering multiple time-based branches quickly?" — directly relevant to how aggressively fake timers should be leaned on.
Code / implementation expected: Yes — a real fake-timer test genuinely completing a "10-second" wait in under 1ms, plus a real method-mock replacing what would otherwise be a real network call, is the concrete, convincing proof of exactly how both halves of the prompt are solved.