[{"data":1,"prerenderedAt":102},["ShallowReactive",2],{"qa-\u002Freact\u002Ftesting\u002Fmocking-async":3},{"page":4,"siblings":86,"blog":99},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":77,"related":78,"seo":79,"seoDescription":80,"stem":81,"subtopic":6,"topic":82,"topicSlug":83,"updated":84,"__hash__":85},"qa\u002Freact\u002Ftesting\u002Fmocking-async.md","Mocking Async",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"hard","md","React","react",{},true,3,"\u002Freact\u002Ftesting\u002Fmocking-async",[23,28,32,37,41,45,49,53,57,61,65,69,73],{"id":24,"difficulty":25,"q":26,"a":27},"mock-fetch","medium","How do you mock `fetch` in React component tests?","The simplest approach is to replace `global.fetch` with a spy before\neach test and restore it after.\n\n```js\nimport { render, screen } from '@testing-library\u002Freact'\nimport { vi } from 'vitest'\nimport UserProfile from '.\u002FUserProfile'\n\nbeforeEach(() => {\n  global.fetch = vi.fn()\n})\n\nafterEach(() => {\n  vi.restoreAllMocks()\n})\n\ntest('displays user data after fetch', async () => {\n  global.fetch.mockResolvedValue({\n    ok: true,\n    json: async () => ({ id: 1, name: 'Alice', role: 'admin' }),\n  })\n\n  render(\u003CUserProfile userId={1} \u002F>)\n\n  expect(await screen.findByText('Alice')).toBeInTheDocument()\n  expect(screen.getByText('admin')).toBeInTheDocument()\n  expect(global.fetch).toHaveBeenCalledWith('\u002Fapi\u002Fusers\u002F1')\n})\n\ntest('shows error when fetch fails', async () => {\n  global.fetch.mockResolvedValue({ ok: false, status: 404 })\n\n  render(\u003CUserProfile userId={999} \u002F>)\n\n  expect(await screen.findByText(\u002Fuser not found\u002Fi)).toBeInTheDocument()\n})\n```\n\nThe downside: you're asserting the URL and response shape in every test.\nThis couples tests to the HTTP layer. For larger projects, prefer MSW\n(Mock Service Worker) which intercepts at the network level.\n\n**Rule of thumb:** Use `global.fetch` mocking for quick unit tests;\nswitch to MSW when you have more than a handful of API calls to test.\n",{"id":29,"difficulty":25,"q":30,"a":31},"msw-setup","What is Mock Service Worker (MSW) and how do you set it up with RTL?","**MSW** intercepts outgoing HTTP requests at the service-worker level\n(browser) or the Node.js `http` module level (tests), letting you define\nhandlers that return fake responses — without modifying `fetch` or\n`axios` in your source code.\n\nSetup for Vitest\u002FNode:\n\n**1. Install**\n```bash\nnpm install -D msw\n```\n\n**2. Define handlers (`src\u002Fmocks\u002Fhandlers.ts`)**\n```ts\nimport { http, HttpResponse } from 'msw'\n\nexport const handlers = [\n  http.get('\u002Fapi\u002Fusers\u002F:id', ({ params }) =>\n    HttpResponse.json({ id: params.id, name: 'Alice' })\n  ),\n  http.post('\u002Fapi\u002Flogin', async ({ request }) => {\n    const body = await request.json()\n    if (body.password === 'secret') {\n      return HttpResponse.json({ token: 'abc123' })\n    }\n    return new HttpResponse(null, { status: 401 })\n  }),\n]\n```\n\n**3. Create the server (`src\u002Fmocks\u002Fserver.ts`)**\n```ts\nimport { setupServer } from 'msw\u002Fnode'\nimport { handlers } from '.\u002Fhandlers'\n\nexport const server = setupServer(...handlers)\n```\n\n**4. Wire into test setup**\n```ts\n\u002F\u002F src\u002Ftest\u002Fsetup.ts\nimport { server } from '..\u002Fmocks\u002Fserver'\nimport { beforeAll, afterEach, afterAll } from 'vitest'\n\nbeforeAll(() => server.listen({ onUnhandledRequest: 'error' }))\nafterEach(() => server.resetHandlers())   \u002F\u002F clean up per-test overrides\nafterAll(() => server.close())\n```\n\nNow every test automatically intercepts matching requests without any\nper-test configuration.\n\n**Rule of thumb:** Set `onUnhandledRequest: 'error'` — it forces you to\nhandle every request explicitly, catching forgotten mocks before they\nsilently return `undefined`.\n",{"id":33,"difficulty":34,"q":35,"a":36},"loading-state-test","easy","How do you test loading states in a component that fetches data?","Assert the loading indicator is present *before* the data arrives, then\nassert it's gone once the data loads.\n\n```js\nimport { render, screen } from '@testing-library\u002Freact'\nimport { server } from '..\u002Fmocks\u002Fserver'\nimport { http, HttpResponse } from 'msw'\nimport UserList from '.\u002FUserList'\n\ntest('shows skeleton while loading, then data', async () => {\n  \u002F\u002F Default handler from server setup will respond eventually\n  render(\u003CUserList \u002F>)\n\n  \u002F\u002F Loading state should appear synchronously\n  expect(screen.getByRole('status', { name: \u002Floading\u002Fi }))\n    .toBeInTheDocument()\n  \u002F\u002F or: expect(screen.getByTestId('skeleton')).toBeInTheDocument()\n\n  \u002F\u002F Data appears after fetch completes\n  expect(await screen.findByText('Alice')).toBeInTheDocument()\n\n  \u002F\u002F Loading indicator is gone\n  expect(screen.queryByRole('status', { name: \u002Floading\u002Fi }))\n    .not.toBeInTheDocument()\n})\n```\n\nFor a slow network simulation, delay the MSW response:\n```js\nimport { delay } from 'msw'\n\nserver.use(\n  http.get('\u002Fapi\u002Fusers', async () => {\n    await delay(500)           \u002F\u002F artificial delay\n    return HttpResponse.json([{ id: 1, name: 'Alice' }])\n  })\n)\n```\n\n**Rule of thumb:** Always assert both the loading state AND the resolved\nstate in the same test — it proves the loading indicator appears and\ndisappears correctly.\n",{"id":38,"difficulty":34,"q":39,"a":40},"error-state-test","How do you test error states from failed API calls?","Override the MSW handler for the specific test to return an error\nresponse, then assert the error UI.\n\n```js\nimport { render, screen } from '@testing-library\u002Freact'\nimport { server } from '..\u002Fmocks\u002Fserver'\nimport { http, HttpResponse } from 'msw'\nimport UserList from '.\u002FUserList'\n\ntest('shows error message on 500', async () => {\n  server.use(\n    http.get('\u002Fapi\u002Fusers', () => new HttpResponse(null, { status: 500 }))\n  )\n  render(\u003CUserList \u002F>)\n  expect(await screen.findByRole('alert')).toHaveTextContent(\u002Fsomething went wrong\u002Fi)\n})\n\ntest('shows not-found message on 404', async () => {\n  server.use(\n    http.get('\u002Fapi\u002Fusers\u002F999', () => new HttpResponse(null, { status: 404 }))\n  )\n  render(\u003CUserProfile userId={999} \u002F>)\n  expect(await screen.findByText(\u002Fuser not found\u002Fi)).toBeInTheDocument()\n})\n\ntest('shows network error message', async () => {\n  server.use(\n    http.get('\u002Fapi\u002Fusers', () => HttpResponse.error())  \u002F\u002F simulates network failure\n  )\n  render(\u003CUserList \u002F>)\n  expect(await screen.findByText(\u002Fnetwork error\u002Fi)).toBeInTheDocument()\n})\n```\n\n`server.resetHandlers()` in `afterEach` ensures these one-off overrides\ndon't bleed into other tests.\n\n**Rule of thumb:** Test at least three HTTP outcomes: success, known error\n(400\u002F404), and unexpected server error (500). Each maps to a different\nuser-facing message.\n",{"id":42,"difficulty":14,"q":43,"a":44},"fake-timers","How do you test components that use `setTimeout` or `setInterval`?","Use Vitest's (or Jest's) fake timer API to control time without actually\nwaiting.\n\n```js\nimport { render, screen, act } from '@testing-library\u002Freact'\nimport { vi } from 'vitest'\n\nfunction Countdown({ seconds }) {\n  const [remaining, setRemaining] = React.useState(seconds)\n  React.useEffect(() => {\n    const id = setInterval(() => setRemaining(r => r - 1), 1000)\n    return () => clearInterval(id)\n  }, [])\n  return \u003Cp>{remaining}s remaining\u003C\u002Fp>\n}\n\ndescribe('Countdown', () => {\n  beforeEach(() => vi.useFakeTimers())\n  afterEach(() => vi.useRealTimers())\n\n  test('decrements every second', () => {\n    render(\u003CCountdown seconds={5} \u002F>)\n    expect(screen.getByText('5s remaining')).toBeInTheDocument()\n\n    act(() => vi.advanceTimersByTime(1000))\n    expect(screen.getByText('4s remaining')).toBeInTheDocument()\n\n    act(() => vi.advanceTimersByTime(3000))\n    expect(screen.getByText('1s remaining')).toBeInTheDocument()\n  })\n\n  test('cleans up interval on unmount', () => {\n    const clearIntervalSpy = vi.spyOn(global, 'clearInterval')\n    const { unmount } = render(\u003CCountdown seconds={3} \u002F>)\n    unmount()\n    expect(clearIntervalSpy).toHaveBeenCalled()\n  })\n})\n```\n\nWrapping `vi.advanceTimersByTime` in `act()` flushes any resulting React\nstate updates synchronously.\n\n**Rule of thumb:** Always call `vi.useRealTimers()` in `afterEach` —\nfake timers left running can cause cascading failures in later tests.\n",{"id":46,"difficulty":25,"q":47,"a":48},"module-mocking","How do you mock an entire module (e.g., an API client) in Vitest?","Use `vi.mock()` at the top of the test file (Vitest hoists it before\nimports). Then configure specific implementations with `vi.mocked()`.\n\n```js\nimport { render, screen } from '@testing-library\u002Freact'\nimport { vi } from 'vitest'\nimport * as api from '..\u002Fapi\u002FuserApi'   \u002F\u002F named imports\nimport UserProfile from '.\u002FUserProfile'\n\nvi.mock('..\u002Fapi\u002FuserApi')   \u002F\u002F auto-mocks all exports to vi.fn()\n\nconst mockedApi = vi.mocked(api)\n\nbeforeEach(() => {\n  mockedApi.fetchUser.mockResolvedValue({ id: 1, name: 'Alice' })\n})\n\nafterEach(() => vi.clearAllMocks())\n\ntest('fetches and displays user', async () => {\n  render(\u003CUserProfile userId={1} \u002F>)\n  expect(await screen.findByText('Alice')).toBeInTheDocument()\n  expect(mockedApi.fetchUser).toHaveBeenCalledWith(1)\n})\n\ntest('shows error when fetch throws', async () => {\n  mockedApi.fetchUser.mockRejectedValue(new Error('Network error'))\n  render(\u003CUserProfile userId={1} \u002F>)\n  expect(await screen.findByText(\u002Fnetwork error\u002Fi)).toBeInTheDocument()\n})\n```\n\nFor a partial mock (keep some real implementations):\n```js\nvi.mock('..\u002Futils\u002Fdate', async (importOriginal) => {\n  const real = await importOriginal()\n  return { ...real, formatDate: vi.fn().mockReturnValue('Jan 1') }\n})\n```\n\n**Rule of thumb:** Prefer MSW for HTTP mocking; use `vi.mock()` for\nnon-HTTP modules (analytics SDKs, third-party clients, browser APIs).\n",{"id":50,"difficulty":14,"q":51,"a":52},"react-query-testing","How do you test components that use React Query (`useQuery`, `useMutation`)?","Create a fresh `QueryClient` per test with `retry: false` (so failed\nqueries don't retry in tests), wrap the component in a\n`QueryClientProvider`, and let MSW handle the HTTP responses.\n\n```js\nimport { render, screen } from '@testing-library\u002Freact'\nimport { QueryClient, QueryClientProvider } from '@tanstack\u002Freact-query'\nimport userEvent from '@testing-library\u002Fuser-event'\nimport { server } from '..\u002Fmocks\u002Fserver'\nimport { http, HttpResponse } from 'msw'\nimport UserList from '.\u002FUserList'\n\nfunction createTestClient() {\n  return new QueryClient({\n    defaultOptions: {\n      queries: { retry: false },    \u002F\u002F don't retry on error in tests\n      mutations: { retry: false },\n    },\n  })\n}\n\nfunction renderWithQuery(ui) {\n  const client = createTestClient()\n  return render(\n    \u003CQueryClientProvider client={client}>{ui}\u003C\u002FQueryClientProvider>\n  )\n}\n\ntest('renders user list from query', async () => {\n  server.use(\n    http.get('\u002Fapi\u002Fusers', () =>\n      HttpResponse.json([{ id: 1, name: 'Alice' }])\n    )\n  )\n  renderWithQuery(\u003CUserList \u002F>)\n  expect(await screen.findByText('Alice')).toBeInTheDocument()\n})\n\ntest('mutation updates UI after success', async () => {\n  const user = userEvent.setup()\n  server.use(\n    http.get('\u002Fapi\u002Ftodos', () => HttpResponse.json([])),\n    http.post('\u002Fapi\u002Ftodos', () => HttpResponse.json({ id: 1, text: 'New todo' }))\n  )\n  renderWithQuery(\u003CTodoApp \u002F>)\n  await user.type(screen.getByRole('textbox'), 'New todo')\n  await user.click(screen.getByRole('button', { name: \u002Fadd\u002Fi }))\n  expect(await screen.findByText('New todo')).toBeInTheDocument()\n})\n```\n\n**Rule of thumb:** Always use a fresh `QueryClient` per test — a shared\nclient caches query results across tests and causes false passes or\nunexplained failures.\n",{"id":54,"difficulty":14,"q":55,"a":56},"debounce-throttle-test","How do you test debounced or throttled functions inside components?","Use fake timers to control the debounce delay without real waiting.\n\n```js\nimport { render, screen } from '@testing-library\u002Freact'\nimport userEvent from '@testing-library\u002Fuser-event'\nimport { vi } from 'vitest'\nimport SearchBox from '.\u002FSearchBox'  \u002F\u002F internally debounces onSearch by 300ms\n\ndescribe('SearchBox debounce', () => {\n  beforeEach(() => vi.useFakeTimers())\n  afterEach(() => vi.useRealTimers())\n\n  test('calls onSearch only after debounce delay', async () => {\n    const onSearch = vi.fn()\n    const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime })\n    render(\u003CSearchBox onSearch={onSearch} \u002F>)\n\n    await user.type(screen.getByRole('textbox'), 'react')\n\n    \u002F\u002F Before debounce fires — should not have been called\n    expect(onSearch).not.toHaveBeenCalled()\n\n    \u002F\u002F Advance time past debounce window\n    vi.runAllTimers()\n\n    expect(onSearch).toHaveBeenCalledTimes(1)\n    expect(onSearch).toHaveBeenCalledWith('react')\n  })\n\n  test('debounces rapid typing to a single call', async () => {\n    const onSearch = vi.fn()\n    const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime })\n    render(\u003CSearchBox onSearch={onSearch} \u002F>)\n\n    await user.type(screen.getByRole('textbox'), 'react')\n    await user.clear(screen.getByRole('textbox'))\n    await user.type(screen.getByRole('textbox'), 'hooks')\n\n    vi.runAllTimers()\n\n    \u002F\u002F Only the final value triggers the callback\n    expect(onSearch).toHaveBeenCalledTimes(1)\n    expect(onSearch).toHaveBeenCalledWith('hooks')\n  })\n})\n```\n\nKey: pass `{ advanceTimers: vi.advanceTimersByTime }` to `userEvent.setup()`\nso userEvent's internal delays use fake timers too.\n\n**Rule of thumb:** Always pair fake timers with `userEvent.setup({ advanceTimers })`\n— without it, userEvent's own async delays break fake-timer tests.\n",{"id":58,"difficulty":25,"q":59,"a":60},"localstorage-mock","How do you mock `localStorage` in tests?","The jsdom environment (used by Vitest\u002FJest with RTL) provides a real\n`localStorage` implementation, but it persists between tests unless\ncleared. The cleanest approach is to clear it after each test.\n\n```js\nafterEach(() => localStorage.clear())\n\ntest('persists theme preference to localStorage', async () => {\n  const user = userEvent.setup()\n  render(\u003CThemeToggle \u002F>)\n\n  await user.click(screen.getByRole('button', { name: \u002Fdark mode\u002Fi }))\n\n  expect(localStorage.getItem('theme')).toBe('dark')\n})\n\ntest('reads theme from localStorage on mount', () => {\n  localStorage.setItem('theme', 'dark')\n  render(\u003CThemeToggle \u002F>)\n  expect(screen.getByRole('button', { name: \u002Flight mode\u002Fi })).toBeInTheDocument()\n})\n```\n\nIf you need to test a case where `localStorage` is unavailable (private\nbrowsing), mock it with a spy:\n```js\nvi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => {\n  throw new DOMException('QuotaExceededError')\n})\n```\n\n**Rule of thumb:** Call `localStorage.clear()` in `afterEach`, not\n`beforeEach` — clearing before masks cleanup bugs from prior tests.\n",{"id":62,"difficulty":25,"q":63,"a":64},"async-act-warning","What does the \"act() warning\" mean and how do you fix it?","The `act()` warning appears when a state update happens *outside* of a\nReact `act()` call, meaning React's test utilities weren't notified that\nstate was about to change.\n\n```\nWarning: An update to Counter inside a test was not wrapped in act(...)\n```\n\n**Common causes and fixes:**\n\n**1. Async state update not awaited:**\n```js\n\u002F\u002F ❌ State update from async callback is not awaited\nfireEvent.click(button)\n\u002F\u002F The click triggers a fetch that updates state after the test ends\n\n\u002F\u002F ✅ Use findBy* which internally wraps in act\nawait screen.findByText('Loaded')\n```\n\n**2. Missing `await` on userEvent:**\n```js\n\u002F\u002F ❌\nuser.click(button)   \u002F\u002F forgot await\n\n\u002F\u002F ✅\nawait user.click(button)\n```\n\n**3. `useEffect` with a timer not cleaned up:**\n```js\n\u002F\u002F ❌ Timer fires after test cleanup\nReact.useEffect(() => {\n  setTimeout(() => setState('done'), 500)\n}, [])\n\n\u002F\u002F ✅ Cancel the timer in cleanup\nReact.useEffect(() => {\n  const id = setTimeout(() => setState('done'), 500)\n  return () => clearTimeout(id)\n}, [])\n```\n\n**4. Manually wrapping needed:**\n```js\nact(() => {\n  \u002F\u002F trigger some event that causes synchronous state updates\n  eventEmitter.emit('update', newData)\n})\n```\n\n**Rule of thumb:** The warning is always a signal that a state update\nescaped test control — find and `await` the async operation that triggered\nit.\n",{"id":66,"difficulty":34,"q":67,"a":68},"spy-console","How do you test that a component logs errors or warnings without polluting test output?","Spy on `console.error` or `console.warn` with `vi.spyOn()`, suppress the\noutput by replacing the implementation, assert the call, then restore.\n\n```js\nimport { vi } from 'vitest'\n\ntest('logs validation error for invalid prop', () => {\n  const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})\n\n  render(\u003CDatePicker value=\"not-a-date\" \u002F>)\n\n  expect(consoleSpy).toHaveBeenCalledWith(\n    expect.stringContaining('Invalid date format')\n  )\n\n  consoleSpy.mockRestore()\n})\n```\n\nFor error boundaries that log the error:\n```js\ntest('error boundary shows fallback and logs', () => {\n  const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})\n\n  render(\n    \u003CErrorBoundary>\n      \u003CThrowingComponent \u002F>\n    \u003C\u002FErrorBoundary>\n  )\n\n  expect(screen.getByText(\u002Fsomething went wrong\u002Fi)).toBeInTheDocument()\n  expect(errorSpy).toHaveBeenCalled()\n\n  errorSpy.mockRestore()\n})\n```\n\nIf you want to assert `console.error` is NOT called (no unexpected\nerrors):\n```js\nconst consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})\nrender(\u003CCleanComponent \u002F>)\nexpect(consoleSpy).not.toHaveBeenCalled()\nconsoleSpy.mockRestore()\n```\n\n**Rule of thumb:** Always `mockRestore()` after spy assertions — leaving\nthe spy in place will swallow real errors in subsequent tests.\n",{"id":70,"difficulty":14,"q":71,"a":72},"polling-test","How do you test a component that polls an API at a regular interval?","Combine fake timers with MSW to control both the clock and the server\nresponses. Advance time in steps and assert updated data between steps.\n\n```js\nimport { render, screen } from '@testing-library\u002Freact'\nimport { act } from '@testing-library\u002Freact'\nimport { vi } from 'vitest'\nimport { server } from '..\u002Fmocks\u002Fserver'\nimport { http, HttpResponse } from 'msw'\nimport LivePriceWidget from '.\u002FLivePriceWidget'  \u002F\u002F polls \u002Fapi\u002Fprice every 5s\n\ndescribe('LivePriceWidget', () => {\n  beforeEach(() => vi.useFakeTimers())\n  afterEach(() => {\n    vi.useRealTimers()\n    server.resetHandlers()\n  })\n\n  test('updates price after each poll interval', async () => {\n    let price = 100\n\n    server.use(\n      http.get('\u002Fapi\u002Fprice', () => HttpResponse.json({ value: price }))\n    )\n\n    render(\u003CLivePriceWidget \u002F>)\n    expect(await screen.findByText('$100')).toBeInTheDocument()\n\n    \u002F\u002F Simulate a price change on the server\n    price = 150\n    await act(async () => {\n      vi.advanceTimersByTime(5000)  \u002F\u002F trigger next poll\n    })\n\n    expect(await screen.findByText('$150')).toBeInTheDocument()\n  })\n})\n```\n\nThe `await act(async () => { ... })` pattern flushes both the timer\ncallback and the resulting async state update.\n\n**Rule of thumb:** For polling tests, wrap `vi.advanceTimersByTime`\nin `await act(async () => { ... })` to ensure React processes both the\ntimer expiry and the subsequent promise resolution.\n",{"id":74,"difficulty":14,"q":75,"a":76},"race-condition-test","How do you test that a component handles race conditions — e.g., only showing the result of the latest request?","Use MSW handlers with controlled response ordering (via `delay`) to\nsimulate an older request resolving after a newer one.\n\n```js\nimport { render, screen } from '@testing-library\u002Freact'\nimport userEvent from '@testing-library\u002Fuser-event'\nimport { server } from '..\u002Fmocks\u002Fserver'\nimport { http, HttpResponse, delay } from 'msw'\nimport SearchResults from '.\u002FSearchResults'\n\ntest('shows result of latest search, ignoring stale responses', async () => {\n  let requestCount = 0\n\n  server.use(\n    http.get('\u002Fapi\u002Fsearch', async ({ request }) => {\n      const q = new URL(request.url).searchParams.get('q')\n      requestCount++\n\n      if (requestCount === 1) {\n        \u002F\u002F First request (stale) — slow response\n        await delay(500)\n        return HttpResponse.json({ query: q, results: ['Stale result'] })\n      }\n      \u002F\u002F Second request (latest) — fast response\n      return HttpResponse.json({ query: q, results: ['Fresh result'] })\n    })\n  )\n\n  const user = userEvent.setup()\n  render(\u003CSearchResults \u002F>)\n\n  \u002F\u002F Type first query, then quickly change it\n  await user.type(screen.getByRole('textbox'), 'slow')\n  await user.clear(screen.getByRole('textbox'))\n  await user.type(screen.getByRole('textbox'), 'fast')\n\n  \u002F\u002F Should show fresh result only\n  expect(await screen.findByText('Fresh result')).toBeInTheDocument()\n  expect(screen.queryByText('Stale result')).not.toBeInTheDocument()\n})\n```\n\nThis test verifies the component cancels or ignores stale requests\n(typically via `AbortController` or a flag in `useEffect`).\n\n**Rule of thumb:** Test race conditions by controlling response timing\nin MSW handlers; if the test passes even without abort logic, the\ntiming simulation isn't strict enough.\n",13,null,{"description":11},"React async testing interview questions — mocking fetch, MSW setup, testing loading and error states, fake timers, vi.mock, React Query testing, debounce\u002Fthrottle, and localStorage mocking.","react\u002Ftesting\u002Fmocking-async","Testing","testing","2026-06-24","4qnBXsczPivanIvp--w3X85AcXTAYLr32BCFDvmr2qo",[87,91,94,95],{"subtopic":88,"path":89,"order":90},"RTL Basics","\u002Freact\u002Ftesting\u002Frtl-basics",1,{"subtopic":92,"path":93,"order":12},"Component Interaction Testing","\u002Freact\u002Ftesting\u002Fcomponent-interaction-testing",{"subtopic":6,"path":21,"order":20},{"subtopic":96,"path":97,"order":98},"Testing Custom Hooks","\u002Freact\u002Ftesting\u002Ftesting-custom-hooks",4,{"path":100,"title":101},"\u002Fblog\u002Freact-mocking-async-guide","Mocking Async in React Tests — Complete Guide",1782244101390]