> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tappify.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# renderWithTap

> Renders a component against the mock bridge, so a widget, tab, page, row action or settings panel is testable outside Tappify.

```ts theme={null}
function renderWithTap(ui, options?): RenderWithTapResult;
```

Renders a component against the mock bridge, so a widget, tab, page, row action
or settings panel is testable outside Tappify.

## Parameters

### ui

`ReactElement`

### options?

[`RenderWithTapOptions`](/extensions/reference/testing-api/Interface.RenderWithTapOptions) = `{}`

## Returns

[`RenderWithTapResult`](/extensions/reference/testing-api/Interface.RenderWithTapResult)

## Remarks

It builds a mock from the same options `createTapMock` takes unless you pass
`mock`, wraps the component in the host provider and a `QueryClient` that does
not retry and does not cache between tests, and appends the mock's portal to the
rendered document so `TapDialog` has somewhere to go. It rewires
`tap.invalidate` onto that client, so a component calling it drops the right
cache entries. Scopes default to all of them, so pass `scopes` to cover the
refused path; a `handler` has to be built with `jwks: await testJwks()` and the
same `extensionId` the mock reports. Load
`@tappify/extension-sdk/testing/vitest` or `.../testing/jest` as a setup file
first: that installs the host CSS variables, registers the matchers and clears
the portal between tests.

## Example

```tsx theme={null}
import { TapStat, useTapQuery } from '@tappify/extension-sdk';
import { renderWithTap } from '@tappify/extension-sdk/testing';
import { screen, waitFor } from '@testing-library/react';
import { expect, it } from 'vitest';

function Crashes() {
  const crashes = useTapQuery({
    kind: 'crashes',
    range: { from: '2026-09-01', to: '2026-09-08' },
  });
  return <TapStat label="Issues" value={crashes.data?.issues.length ?? 0} />;
}

it('renders the issues the fixtures answer with', async () => {
  renderWithTap(<Crashes />, { scopes: ['ui:render', 'crashes:read'] });
  await waitFor(() => expect(screen.getByText('2')).toBeTruthy());
});
```
