[{"data":1,"prerenderedAt":115},["ShallowReactive",2],{"qa-\u002Freact\u002Ftesting\u002Frtl-basics":3},{"page":4,"siblings":99,"blog":112},{"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":89,"related":90,"seo":91,"seoDescription":92,"stem":93,"subtopic":94,"topic":95,"topicSlug":96,"updated":97,"__hash__":98},"qa\u002Freact\u002Ftesting\u002Frtl-basics.md","Rtl Basics",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","React","react",{},true,1,"\u002Freact\u002Ftesting\u002Frtl-basics",[23,28,32,36,40,44,48,52,56,60,64,68,72,76,80,85],{"id":24,"difficulty":25,"q":26,"a":27},"rtl-philosophy","easy","What is React Testing Library and what is its core testing philosophy?","**React Testing Library (RTL)** is a lightweight testing utility built on\ntop of `@testing-library\u002Fdom`. Its core philosophy comes from a single\nguiding principle:\n\n> *\"The more your tests resemble the way your software is used, the more\n> confidence they can give you.\"* — Kent C. Dodds\n\nThis means RTL deliberately does **not** expose component internals\n(state, instance methods, refs). Instead, every query and assertion goes\nthrough the same DOM the user sees.\n\n```js\n\u002F\u002F ❌ Enzyme-style (tests implementation details)\nwrapper.state('isOpen')          \u002F\u002F couples test to internal state name\nwrapper.instance().handleClick() \u002F\u002F calls method directly, bypassing UI\n\n\u002F\u002F ✅ RTL-style (tests user-visible behavior)\nexpect(screen.queryByRole('dialog')).not.toBeInTheDocument()\nawait userEvent.click(screen.getByRole('button', { name: \u002Fopen\u002Fi }))\nexpect(screen.getByRole('dialog')).toBeInTheDocument()\n```\n\nThe practical consequences:\n- Queries find elements by **role, label, text, or test-id** — things real\n  users and assistive technology rely on.\n- Interactions go through `userEvent` or `fireEvent`, which dispatch real\n  DOM events rather than calling handlers directly.\n- If you can't test it without accessing internals, the API is probably\n  missing something worth exposing.\n\n**Rule of thumb:** If your test would still pass after a complete internal\nrefactor (renaming state, changing the component hierarchy), it's a good\nRTL test.\n",{"id":29,"difficulty":25,"q":30,"a":31},"render-api","What does `render()` do and what does it return?","`render()` mounts a React component into a detached `\u003Cdiv>` that is\nappended to `document.body`, runs all effects and state updates, then\nreturns a bag of query helpers bound to that container.\n\n```js\nimport { render, screen } from '@testing-library\u002Freact'\n\nconst { getByText, queryByRole, findByLabelText, container, unmount, rerender } =\n  render(\u003CLoginForm \u002F>)\n\n\u002F\u002F Most common keys:\n\u002F\u002F container   — the raw DOM node wrapping the rendered output\n\u002F\u002F unmount()   — tear down the component (called automatically after each test)\n\u002F\u002F rerender()  — re-render with new props\n\u002F\u002F All getBy*\u002FqueryBy*\u002FfindBy* helpers (scoped to this render)\n```\n\nIn practice the bound helpers from the return value are rarely used\ndirectly. The **`screen`** object exports the same queries but always\noperates on `document.body`, which works even if multiple renders exist\nin one test.\n\n```js\nrender(\u003CLoginForm \u002F>)\n\u002F\u002F Prefer screen.* over the returned object\nconst button = screen.getByRole('button', { name: \u002Fsign in\u002Fi })\n```\n\nAfter each test, `@testing-library\u002Freact` calls `cleanup()` automatically\n(via an `afterEach` it registers), which unmounts the component and removes\nthe container from `document.body`.\n\n**Rule of thumb:** Always use `screen.*` for queries and keep the return\nvalue only when you need `rerender`, `unmount`, or `container`.\n",{"id":33,"difficulty":14,"q":34,"a":35},"query-variants","What are the three query variants — `getBy`, `queryBy`, `findBy` — and when should you use each?","RTL provides three prefixes for every query, each with different behavior\non missing elements and async awareness.\n\n| Variant | Not found | Multiple found | Async? |\n|---------|-----------|----------------|--------|\n| `getBy` | throws | throws | No |\n| `queryBy` | returns `null` | throws | No |\n| `findBy` | rejects (Promise) | rejects | Yes (retries until timeout) |\n\n```js\n\u002F\u002F getBy — use when element MUST exist right now\nconst heading = screen.getByRole('heading', { name: \u002Fdashboard\u002Fi })\n\n\u002F\u002F queryBy — use to assert element is ABSENT (toBeNull \u002F not.toBeInTheDocument)\nexpect(screen.queryByText('Error')).not.toBeInTheDocument()\n\n\u002F\u002F findBy — use when element appears AFTER an async operation\nconst item = await screen.findByText('Data loaded')  \u002F\u002F polls until found or timeout\n```\n\nAll three have `All` variants (`getAllBy`, `queryAllBy`, `findAllBy`) that\nreturn arrays and only throw when *no* elements are found (for `getAllBy`\nand `findAllBy`).\n\nCommon mistakes:\n- Using `getBy` to assert absence — it throws before you can check.\n- Forgetting `await` on `findBy` — returns a Promise, not the element.\n- Using `findBy` when the element is already there — wastes the polling\n  overhead.\n\n**Rule of thumb:** Get → exists now. Query → might not exist. Find → will\nexist soon.\n",{"id":37,"difficulty":25,"q":38,"a":39},"screen-object","What is `screen` and why is it preferred over the queries returned by `render()`?","`screen` is a re-export from `@testing-library\u002Fdom` that exposes the same\nfull query set but always targets `document.body` rather than a scoped\ncontainer.\n\n```js\nimport { render, screen } from '@testing-library\u002Freact'\n\nrender(\u003CApp \u002F>)\n\n\u002F\u002F Both work, but screen.* is preferred\nconst { getByRole } = render(\u003CApp \u002F>)   \u002F\u002F ❌ scoped to this render's container\nscreen.getByRole('navigation')           \u002F\u002F ✅ searches all of document.body\n```\n\nAdvantages of `screen`:\n1. **No destructuring** — one import, always available.\n2. **Works across renders** — if a component portals into `document.body`\n   outside the container, `screen` still finds it.\n3. **`screen.debug()`** — prints the current DOM to the console for\n   quick inspection without needing the return value.\n\n```js\nscreen.debug()                     \u002F\u002F prints full document.body\nscreen.debug(screen.getByRole('dialog'))  \u002F\u002F prints just the dialog node\n```\n\n**Rule of thumb:** Always import and use `screen`; only keep the\n`render()` return value when you need `rerender`, `unmount`, or the raw\n`container` node.\n",{"id":41,"difficulty":14,"q":42,"a":43},"query-priority","In what priority order should you choose RTL queries, and why?","RTL's official priority list (from the docs) guides you toward queries\nthat reflect how real users and accessibility tools discover elements:\n\n1. **By role** (`getByRole`) — matches ARIA roles; works for buttons,\n   headings, links, inputs, dialogs, etc. Preferred for almost everything.\n2. **By label** (`getByLabelText`) — finds the form control associated\n   with a `\u003Clabel>`. Best for inputs, selects, textareas.\n3. **By placeholder** (`getByPlaceholderText`) — fallback when there is\n   no visible label.\n4. **By text** (`getByText`) — finds nodes by their text content.\n   Good for paragraphs, list items, non-interactive elements.\n5. **By display value** (`getByDisplayValue`) — current value of an\n   input\u002Fselect\u002Ftextarea.\n6. **By alt text** (`getByAltText`) — for images.\n7. **By title** (`getByTitle`) — `title` attribute.\n8. **By test id** (`getByTestId`) — only when nothing above is practical;\n   requires adding `data-testid` attributes to the DOM.\n\n```js\n\u002F\u002F ✅ Tier 1 — most accessible, most like how a user would find it\nscreen.getByRole('button', { name: \u002Fsubmit\u002Fi })\nscreen.getByRole('textbox', { name: \u002Femail\u002Fi })\n\n\u002F\u002F ✅ Tier 2 — great for forms with proper labels\nscreen.getByLabelText(\u002Fpassword\u002Fi)\n\n\u002F\u002F ⚠️ Last resort — opaque, requires markup change\nscreen.getByTestId('submit-btn')\n```\n\nThe deeper reason: queries that would break if you changed a class name\nor state field are brittle. Queries that break only when the visible UI\nchanges are meaningful.\n\n**Rule of thumb:** Reach for `getByRole` first; add `aria-label` or\n`aria-labelledby` to make otherwise unlabelled elements queryable before\nfalling back to `data-testid`.\n",{"id":45,"difficulty":14,"q":46,"a":47},"user-event-vs-fire-event","What is the difference between `userEvent` and `fireEvent`?","Both simulate user interactions, but at very different levels of fidelity.\n\n**`fireEvent`** dispatches a single synthetic DOM event and returns\nimmediately. It is synchronous and low-level.\n\n**`userEvent`** (from `@testing-library\u002Fuser-event`) simulates the *full\nsequence* of events a real user triggers: pointer down, pointer up, focus,\nkeydown, input, change, click, blur, etc. Since v14 it is async.\n\n```js\nimport userEvent from '@testing-library\u002Fuser-event'\nimport { fireEvent, render, screen } from '@testing-library\u002Freact'\n\nrender(\u003CSearchBox \u002F>)\n\n\u002F\u002F fireEvent — fires one 'change' event, skips pointer\u002Fkeyboard events\nfireEvent.change(screen.getByRole('textbox'), { target: { value: 'react' } })\n\n\u002F\u002F userEvent — types character by character, fires keydown\u002Fkeypress\u002Finput\u002Fkeyup per char\nconst user = userEvent.setup()\nawait user.type(screen.getByRole('textbox'), 'react')\n```\n\nWhen to use each:\n- **userEvent** for anything the user actually does: typing, clicking,\n  selecting, hovering, tabbing. It is the right default.\n- **fireEvent** when you need to simulate an event that userEvent does not\n  support, or in unit tests where you want a specific event without the\n  full browser sequence.\n\nSetup pattern (v14+):\n```js\n\u002F\u002F Call setup once per test, not inside loops\nconst user = userEvent.setup()\nawait user.click(button)\nawait user.keyboard('{Enter}')\n```\n\n**Rule of thumb:** Default to `userEvent`; use `fireEvent` only when\n`userEvent` doesn't cover the event you need.\n",{"id":49,"difficulty":14,"q":50,"a":51},"waitfor","What is `waitFor` and when should you use it?","`waitFor` repeatedly executes a callback until it stops throwing (or the\ntimeout expires). It is used when an assertion depends on something that\nhasn't happened yet — a state update, an effect, or an async API call.\n\n```js\nimport { render, screen, waitFor } from '@testing-library\u002Freact'\n\ntest('shows success message after save', async () => {\n  render(\u003CSaveButton \u002F>)\n  await userEvent.setup().click(screen.getByRole('button', { name: \u002Fsave\u002Fi }))\n\n  \u002F\u002F The success message appears after a state update triggered by an API call\n  await waitFor(() => {\n    expect(screen.getByText('Saved!')).toBeInTheDocument()\n  })\n})\n```\n\nKey options:\n```js\nawait waitFor(callback, {\n  timeout: 3000,   \u002F\u002F default 1000 ms\n  interval: 50,    \u002F\u002F polling interval, default 50 ms\n})\n```\n\n`waitFor` vs `findBy*`:\n- `findBy*` is syntactic sugar for `waitFor(() => getBy*(...))` — use it\n  when you're waiting for a single element to appear.\n- `waitFor` is for more complex assertions (multiple elements, negative\n  assertions, or checking a value, not just presence).\n\nCommon mistake — putting multiple assertions in one `waitFor`:\n```js\n\u002F\u002F ❌ If the first passes then the second fails, waitFor retries the whole block\nawait waitFor(() => {\n  expect(a).toBeInTheDocument()\n  expect(b).toBeInTheDocument()  \u002F\u002F a keeps re-asserting, masking failures\n})\n\n\u002F\u002F ✅ Wait for the first, then assert synchronously\nawait screen.findByText('A')\nexpect(screen.getByText('B')).toBeInTheDocument()\n```\n\n**Rule of thumb:** Use `findBy*` for single async element appearances;\nuse `waitFor` for complex multi-assertion async scenarios.\n",{"id":53,"difficulty":25,"q":54,"a":55},"jest-dom-matchers","What does `@testing-library\u002Fjest-dom` provide and what are the most useful matchers?","`@testing-library\u002Fjest-dom` extends Jest\u002FVitest's `expect` with custom\nDOM matchers that produce clearer error messages than raw Jest assertions.\n\nSetup (once in your test setup file):\n```js\n\u002F\u002F vitest.config.ts \u002F jest.setup.ts\nimport '@testing-library\u002Fjest-dom'\n\u002F\u002F or\nimport '@testing-library\u002Fjest-dom\u002Fvitest'\n```\n\nMost useful matchers:\n\n```js\n\u002F\u002F Presence\nexpect(el).toBeInTheDocument()\nexpect(el).not.toBeInTheDocument()\n\n\u002F\u002F Visibility\nexpect(el).toBeVisible()           \u002F\u002F not hidden via CSS\nexpect(el).toBeEnabled()           \u002F\u002F not disabled\nexpect(el).toBeDisabled()\n\n\u002F\u002F Content\nexpect(el).toHaveTextContent('Hello')\nexpect(el).toHaveTextContent(\u002Fhello\u002Fi)\n\n\u002F\u002F Form state\nexpect(checkbox).toBeChecked()\nexpect(input).toHaveValue('react')\nexpect(select).toHaveDisplayValue('Option A')\n\n\u002F\u002F Attributes & classes\nexpect(el).toHaveAttribute('href', '\u002Fhome')\nexpect(el).toHaveClass('active')\n\n\u002F\u002F Focus\nexpect(input).toHaveFocus()\n```\n\nWithout jest-dom you'd write `expect(el).not.toBeNull()` instead of\n`expect(el).toBeInTheDocument()` — the latter produces a far more\ndescriptive failure message.\n\n**Rule of thumb:** Always import `@testing-library\u002Fjest-dom` in your\nglobal setup file so every test file gets the matchers automatically.\n",{"id":57,"difficulty":14,"q":58,"a":59},"within","What is `within()` and when is it useful?","`within()` scopes all queries to a specific DOM node, letting you select\nelements inside a particular region when multiple similar elements exist\non the page.\n\n```js\nimport { render, screen, within } from '@testing-library\u002Freact'\n\nrender(\n  \u003Cul>\n    \u003Cli>\n      \u003Cspan>Alice\u003C\u002Fspan>\n      \u003Cbutton>Delete\u003C\u002Fbutton>\n    \u003C\u002Fli>\n    \u003Cli>\n      \u003Cspan>Bob\u003C\u002Fspan>\n      \u003Cbutton>Delete\u003C\u002Fbutton>\n    \u003C\u002Fli>\n  \u003C\u002Ful>\n)\n\n\u002F\u002F Without within — ambiguous: two \"Delete\" buttons exist\n\u002F\u002F screen.getByRole('button', { name: \u002Fdelete\u002Fi }) — throws (multiple found)\n\n\u002F\u002F With within — unambiguous\nconst aliceRow = screen.getByText('Alice').closest('li')\nwithin(aliceRow).getByRole('button', { name: \u002Fdelete\u002Fi }).click()\n```\n\nCommon use cases:\n- Tables with per-row actions\n- Lists where each item has the same repeated controls\n- Modals\u002Fdialogs — scope queries to just the dialog content\n\n```js\nconst dialog = screen.getByRole('dialog')\nexpect(within(dialog).getByRole('heading')).toHaveTextContent('Confirm')\nawait userEvent.setup().click(within(dialog).getByRole('button', { name: \u002Fcancel\u002Fi }))\n```\n\n**Rule of thumb:** When `getBy*` throws because multiple matching elements\nexist, use `within()` to narrow the search to the relevant container.\n",{"id":61,"difficulty":14,"q":62,"a":63},"async-testing-patterns","How do you test a component that fetches data on mount?","The standard pattern: render the component, assert the loading state,\nthen await the resolved state.\n\n```js\nimport { render, screen } from '@testing-library\u002Freact'\nimport { rest } from 'msw'        \u002F\u002F Mock Service Worker (preferred)\nimport { setupServer } from 'msw\u002Fnode'\n\nconst server = setupServer(\n  rest.get('\u002Fapi\u002Fusers', (req, res, ctx) =>\n    res(ctx.json([{ id: 1, name: 'Alice' }]))\n  )\n)\n\nbeforeAll(() => server.listen())\nafterEach(() => server.resetHandlers())\nafterAll(() => server.close())\n\ntest('shows users after fetch', async () => {\n  render(\u003CUserList \u002F>)\n\n  \u002F\u002F Assert loading state first (optional but good practice)\n  expect(screen.getByText(\u002Floading\u002Fi)).toBeInTheDocument()\n\n  \u002F\u002F Wait for data to appear\n  expect(await screen.findByText('Alice')).toBeInTheDocument()\n\n  \u002F\u002F Assert loading indicator is gone\n  expect(screen.queryByText(\u002Floading\u002Fi)).not.toBeInTheDocument()\n})\n\ntest('shows error on fetch failure', async () => {\n  server.use(\n    rest.get('\u002Fapi\u002Fusers', (req, res, ctx) => res(ctx.status(500)))\n  )\n  render(\u003CUserList \u002F>)\n  expect(await screen.findByText(\u002Fsomething went wrong\u002Fi)).toBeInTheDocument()\n})\n```\n\nWithout MSW you can mock `fetch` directly:\n```js\nglobal.fetch = vi.fn().mockResolvedValue({\n  ok: true,\n  json: async () => [{ id: 1, name: 'Alice' }],\n})\n```\n\n**Rule of thumb:** Prefer MSW for HTTP mocking — it intercepts at the\nnetwork level, so the same handlers work in both tests and the browser\nduring development.\n",{"id":65,"difficulty":25,"q":66,"a":67},"setup-vitest","How do you set up React Testing Library with Vitest?","Four steps:\n\n**1. Install dependencies**\n```bash\nnpm install -D vitest @vitest\u002Fui jsdom \\\n  @testing-library\u002Freact @testing-library\u002Fuser-event \\\n  @testing-library\u002Fjest-dom\n```\n\n**2. Configure Vitest (`vitest.config.ts`)**\n```ts\nimport { defineConfig } from 'vitest\u002Fconfig'\nimport react from '@vitejs\u002Fplugin-react'\n\nexport default defineConfig({\n  plugins: [react()],\n  test: {\n    environment: 'jsdom',          \u002F\u002F simulate the browser DOM\n    setupFiles: ['.\u002Fsrc\u002Ftest\u002Fsetup.ts'],\n  },\n})\n```\n\n**3. Create setup file (`src\u002Ftest\u002Fsetup.ts`)**\n```ts\nimport '@testing-library\u002Fjest-dom\u002Fvitest'   \u002F\u002F custom matchers\nimport { cleanup } from '@testing-library\u002Freact'\nimport { afterEach } from 'vitest'\n\nafterEach(() => cleanup())  \u002F\u002F auto-cleanup (RTL registers this automatically, but explicit is safer)\n```\n\n**4. Write a test**\n```ts\nimport { render, screen } from '@testing-library\u002Freact'\nimport userEvent from '@testing-library\u002Fuser-event'\nimport { describe, it, expect } from 'vitest'\nimport Counter from '.\u002FCounter'\n\ndescribe('Counter', () => {\n  it('increments on click', async () => {\n    render(\u003CCounter \u002F>)\n    await userEvent.setup().click(screen.getByRole('button', { name: \u002Fincrement\u002Fi }))\n    expect(screen.getByText('1')).toBeInTheDocument()\n  })\n})\n```\n\n**Rule of thumb:** Set `environment: 'jsdom'` and import `jest-dom` in\nyour setup file — those two steps cover 90% of RTL configuration.\n",{"id":69,"difficulty":14,"q":70,"a":71},"rerender","How do you test a component that should update when its props change?","Use the `rerender` function returned by `render()`. It re-renders the same\ncomponent with new props without unmounting\u002Fremounting.\n\n```js\nimport { render, screen } from '@testing-library\u002Freact'\n\nfunction Greeting({ name }) {\n  return \u003Ch1>Hello, {name}!\u003C\u002Fh1>\n}\n\ntest('updates when name prop changes', () => {\n  const { rerender } = render(\u003CGreeting name=\"Alice\" \u002F>)\n  expect(screen.getByRole('heading')).toHaveTextContent('Hello, Alice!')\n\n  rerender(\u003CGreeting name=\"Bob\" \u002F>)\n  expect(screen.getByRole('heading')).toHaveTextContent('Hello, Bob!')\n})\n```\n\n`rerender` is also useful for testing prop-driven animations or conditional\nrendering toggled from outside:\n\n```js\ntest('hides content when visible prop is false', () => {\n  const { rerender } = render(\u003CDrawer visible={true}>\u003Cp>Content\u003C\u002Fp>\u003C\u002FDrawer>)\n  expect(screen.getByText('Content')).toBeVisible()\n\n  rerender(\u003CDrawer visible={false}>\u003Cp>Content\u003C\u002Fp>\u003C\u002FDrawer>)\n  expect(screen.queryByText('Content')).not.toBeInTheDocument()\n})\n```\n\n**Rule of thumb:** Use `rerender` to test prop changes; use `userEvent`\nto test changes driven by user interaction.\n",{"id":73,"difficulty":14,"q":74,"a":75},"wrapping-providers","How do you render a component that requires context providers or a router?","Pass a `wrapper` option to `render()` that wraps the component under test\nwith any necessary providers.\n\n```js\nimport { render, screen } from '@testing-library\u002Freact'\nimport { MemoryRouter } from 'react-router-dom'\nimport { ThemeProvider } from '.\u002FThemeContext'\n\n\u002F\u002F Inline wrapper\nrender(\u003CNavBar \u002F>, {\n  wrapper: ({ children }) => (\n    \u003CMemoryRouter initialEntries={['\u002Fdashboard']}>\n      \u003CThemeProvider theme=\"dark\">\n        {children}\n      \u003C\u002FThemeProvider>\n    \u003C\u002FMemoryRouter>\n  ),\n})\n```\n\nFor reuse across many tests, create a custom `render` helper:\n\n```js\n\u002F\u002F test\u002Futils.tsx\nimport { render } from '@testing-library\u002Freact'\nimport { MemoryRouter } from 'react-router-dom'\nimport { QueryClient, QueryClientProvider } from '@tanstack\u002Freact-query'\n\nfunction AllProviders({ children }) {\n  const client = new QueryClient({ defaultOptions: { queries: { retry: false } } })\n  return (\n    \u003CQueryClientProvider client={client}>\n      \u003CMemoryRouter>{children}\u003C\u002FMemoryRouter>\n    \u003C\u002FQueryClientProvider>\n  )\n}\n\nconst customRender = (ui, options) =>\n  render(ui, { wrapper: AllProviders, ...options })\n\nexport * from '@testing-library\u002Freact'  \u002F\u002F re-export everything\nexport { customRender as render }        \u002F\u002F override render\n```\n\nThen import from `test\u002Futils` instead of `@testing-library\u002Freact` in\nevery test file.\n\n**Rule of thumb:** Create a single `customRender` helper with all app-wide\nproviders so tests don't repeat provider boilerplate.\n",{"id":77,"difficulty":25,"q":78,"a":79},"debug-failing-tests","What tools does RTL provide to debug failing tests?","RTL offers several built-in debugging tools:\n\n**`screen.debug()`** — prints the current DOM state to the console:\n```js\nrender(\u003CComplexForm \u002F>)\nscreen.debug()                          \u002F\u002F prints all of document.body\nscreen.debug(screen.getByRole('form'))  \u002F\u002F prints just that subtree\n```\n\n**`screen.logTestingPlaygroundURL()`** — generates a URL to the\nTesting Playground website pre-loaded with the current DOM, so you can\ninteractively explore which query to use:\n```js\nscreen.logTestingPlaygroundURL()\n\u002F\u002F Logs: https:\u002F\u002Ftesting-playground.com\u002F#markup=...\n```\n\n**`prettyDOM()`** — programmatic version of debug, returns a string:\n```js\nimport { prettyDOM } from '@testing-library\u002Freact'\nconsole.log(prettyDOM(document.body))\nconsole.log(prettyDOM(someElement, 5000))  \u002F\u002F second arg: max length\n```\n\n**Query suggestion in error messages** — when a query fails, RTL v13+\nsuggests alternative queries that would have matched:\n```\nTestingLibraryElementError: Unable to find an accessible element with the\nrole \"button\" and name \"Submit\"\n\nHere are the accessible roles:\n  button:\n    Name \"submit\":\n    \u003Cbutton>submit\u003C\u002Fbutton>  ← hint: case-sensitive name option used\n```\n\n**Rule of thumb:** When a test fails with \"Unable to find element,\" call\n`screen.debug()` immediately to see the actual DOM at that point.\n",{"id":81,"difficulty":82,"q":83,"a":84},"custom-queries","hard","Can you create custom RTL queries, and when would you need one?","Yes. Custom queries follow the same `getBy`\u002F`queryBy`\u002F`findBy` contract\nand are useful when none of the built-in queries fit your domain — for\nexample, querying by a data attribute specific to your component library.\n\n```js\nimport { buildQueries, queryHelpers } from '@testing-library\u002Freact'\n\n\u002F\u002F Step 1 — the raw queryAll function\nconst queryAllByDataCy = (container, id) =>\n  queryHelpers.queryAllByAttribute('data-cy', container, id)\n\n\u002F\u002F Step 2 — build the full query family from queryAll\nconst [\n  queryByDataCy,\n  getAllByDataCy,\n  getByDataCy,\n  findAllByDataCy,\n  findByDataCy,\n] = buildQueries(\n  queryAllByDataCy,\n  (c, id) => `Found multiple elements with data-cy=\"${id}\"`,\n  (c, id) => `Unable to find element with data-cy=\"${id}\"`\n)\n\nexport { queryByDataCy, getAllByDataCy, getByDataCy, findAllByDataCy, findByDataCy }\n```\n\nWire them into a custom render:\n```js\nconst customRender = (ui, options) =>\n  render(ui, {\n    queries: { ...queries, getByDataCy, findByDataCy },\n    ...options,\n  })\n```\n\nIn practice, the need for custom queries is rare. Common triggers:\n- Your component library uses a non-standard attribute as the accessible\n  identifier and you can't change it.\n- You need to query by a complex compound condition.\n\n**Rule of thumb:** Exhaust all built-in queries (especially `getByRole`\nwith `name` and `within`) before writing custom ones — they're extra\nmaintenance overhead.\n",{"id":86,"difficulty":14,"q":87,"a":88},"render-hook","When should you use `renderHook` instead of rendering a component?","`renderHook` is for testing **custom hooks in isolation** — when the hook\nlogic is complex enough to warrant direct tests but you don't want to\ncreate a throwaway wrapper component manually.\n\n```js\nimport { renderHook, act } from '@testing-library\u002Freact'\nimport { useCounter } from '.\u002FuseCounter'\n\ntest('increments the counter', () => {\n  const { result } = renderHook(() => useCounter(0))\n\n  \u002F\u002F result.current holds the hook's return value\n  expect(result.current.count).toBe(0)\n\n  act(() => {\n    result.current.increment()\n  })\n\n  expect(result.current.count).toBe(1)\n})\n```\n\nIt also accepts a `wrapper` for context:\n```js\nconst { result } = renderHook(() => useAuth(), {\n  wrapper: ({ children }) => \u003CAuthProvider>{children}\u003C\u002FAuthProvider>,\n})\n```\n\nWhen **not** to use `renderHook`:\n- When the hook is trivial and already covered by component tests.\n- When you'd rather test the hook through the component that uses it\n  (integration test) — usually the better approach.\n\n**Rule of thumb:** Use `renderHook` when a custom hook encapsulates\nmeaningful logic (state machines, async flows, caching) that deserves\ndirect tests beyond what component-level tests catch.\n",16,null,{"description":11},"React Testing Library interview questions — render, screen, queries, userEvent, waitFor, jest-dom matchers, async testing, and the RTL testing philosophy.","react\u002Ftesting\u002Frtl-basics","RTL Basics","Testing","testing","2026-06-24","FQwmpxfpp_kNFH3s3_yIPSe9cgpVhuzelX5XtQbSoOE",[100,101,104,108],{"subtopic":94,"path":21,"order":20},{"subtopic":102,"path":103,"order":12},"Component Interaction Testing","\u002Freact\u002Ftesting\u002Fcomponent-interaction-testing",{"subtopic":105,"path":106,"order":107},"Mocking Async","\u002Freact\u002Ftesting\u002Fmocking-async",3,{"subtopic":109,"path":110,"order":111},"Testing Custom Hooks","\u002Freact\u002Ftesting\u002Ftesting-custom-hooks",4,{"path":113,"title":114},"\u002Fblog\u002Freact-rtl-basics-guide","React Testing Library — Complete Interview Guide",1782244101313]