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

---
id: 17891a89-1a58-4744-9b4f-456fd08916b0
---

# Testing utilities reference

> API reference for the UI extensions SDK testing utilities.

Below are the available functions and types for the UI extensions SDK testing utilities.

## createRenderer

`createRenderer()`

Creates a [`Renderer`](#renderer) object with methods for rendering UI extension components and querying the rendered output.

**Parameters:**

* `extensionPointLocation`: [`ExtensionPointLocation`](#extensionpointlocation): the extension point location (e.g., `'crm.record.tab'`, `'settings'`, `'home'`). This determines which extension point-specific APIs are available in the automatically created mocks for `context`, `actions`, and `runServerlessFunction`.

**Return:** [`Renderer`](#renderer)

**Import:**

```ts theme={null}
import { createRenderer } from '@hubspot/ui-extensions/testing';
```

**Example:**

```tsx theme={null}
import { Button } from "@hubspot/ui-extensions";
import { createRenderer } from '@hubspot/ui-extensions/testing';

const { render } = createRenderer('crm.record.tab');
render(<Button variant="primary">Click me</Button>);
```

## Common query methods

The following query methods are available on [`Renderer`](#renderer) and select node types ([`RenderedRootNode`](#renderedrootnode), [`RenderedElementNode`](#renderedelementnode), [`RenderedFragmentNode`](#renderedfragmentnode)):

**Common parameters:**

* `component`: [`HubSpotReactComponent`](#hubspotreactcomponent): the component type to find.
* `matcher?`: [`ElementMatcher`](#elementmatcher): an optional matcher to filter the elements.

### find

`find()`

Find a single element matching the component type. Throws an error if not found or multiple matches exist.

**Parameters:**

* `component`: [`HubSpotReactComponent`](#hubspotreactcomponent)
* `matcher?`: [`ElementMatcher`](#elementmatcher)

**Return:** [`RenderedElementNode`](#renderedelementnode)

### findAll

`findAll()`

Find all elements matching the component type. Returns an array.

**Parameters:**

* `component`: [`HubSpotReactComponent`](#hubspotreactcomponent)
* `matcher?`: [`ElementMatcher`](#elementmatcher)

**Return:** [`RenderedElementNode`](#renderedelementnode)`[]`

### findChild

`findChild()`

Find a direct child element matching the component type. Throws an error if not found or multiple matches exist.

**Parameters:**

* `component`: [`HubSpotReactComponent`](#hubspotreactcomponent)
* `matcher?`: [`ElementMatcher`](#elementmatcher)

**Return:** [`RenderedElementNode`](#renderedelementnode)

### findAllChildren

`findAllChildren()`

Find all direct child elements matching the component type. Returns an array.

**Parameters:**

* `component`: [`HubSpotReactComponent`](#hubspotreactcomponent)
* `matcher?`: [`ElementMatcher`](#elementmatcher)

**Return:** [`RenderedElementNode`](#renderedelementnode)`[]`

### maybeFind

`maybeFind()`

Find a single element matching the component type. Returns `null` if not found or multiple matches exist.

**Parameters:**

* `component`: [`HubSpotReactComponent`](#hubspotreactcomponent)
* `matcher?`: [`ElementMatcher`](#elementmatcher)

**Return:** [`RenderedElementNode`](#renderedelementnode)` | null`

### maybeFindChild

`maybeFindChild()`

Find a direct child element matching the component type. Returns `null` if not found or multiple matches exist.

**Parameters:**

* `component`: [`HubSpotReactComponent`](#hubspotreactcomponent)
* `matcher?`: [`ElementMatcher`](#elementmatcher)

**Return:** [`RenderedElementNode`](#renderedelementnode)` | null`

## Renderer

`Renderer`

The object returned by `createRenderer()` with the following methods and properties:

### render

`render()`

Renders a UI extension component and returns the root node.

**Parameters:**

* `node: ReactNode`: the React component to render

**Return:** [`RenderedRootNode`](#renderedrootnode)

### Query methods

All [common query methods](#common-query-methods) are available: `find()`, `findAll()`, `findChild()`, `findAllChildren()`, `maybeFind()`, `maybeFindChild()`

### findByTestId

`findByTestId()`

Find a component by its `testId` prop. This is the recommended way to find components when you have control over the component's props.

**Parameters:**

* `component`: [`HubSpotReactComponent`](#hubspotreactcomponent): the component type to find.
* `testId: string`: the test ID to search for.

**Return:** [`RenderedElementNode`](#renderedelementnode)

**Throws:**

* `ComponentNotFoundByTestIdError` if no component with the specified `testId` is found.
* `ComponentMismatchedByTestIdError` if a component with the `testId` exists but the component type doesn't match.
* `FindInvalidComponentError` if the target component is invalid.

**Example:**

```tsx theme={null}
const { render, findByTestId } = createRenderer('crm.record.tab');
render(
  <>
    <Button variant="primary" testId="submit-button">Submit</Button>
    <Button variant="secondary" testId="cancel-button">Cancel</Button>
  </>
);

const submitButton = findByTestId(Button, 'submit-button');
expect(submitButton.props.variant).toEqual('primary');
```

### maybeFindByTestId

`maybeFindByTestId()`

Find a component by its `testId` prop. Returns `null` if no match is found. Still throws an error if the test ID exists but the component type doesn't match.

**Parameters:**

* `component`: [`HubSpotReactComponent`](#hubspotreactcomponent): the component type to find.
* `testId: string`: the test ID to search for.

**Return:** [`RenderedElementNode`](#renderedelementnode)` | null`

**Throws:**

* `ComponentMismatchedByTestIdError` if a component with the `testId` exists but the component type doesn't match.
* `FindInvalidComponentError` if the target component is invalid.

**Example:**

```tsx theme={null}
const { render, maybeFindByTestId } = createRenderer('crm.record.tab');
render(<Alert title="My Alert" testId="my-alert" />);

const button = maybeFindByTestId(Button, 'submit-button'); // Returns null
expect(button).toBeNull();

const alert = maybeFindByTestId(Alert, 'my-alert');
expect(alert?.props.title).toEqual('My Alert');
```

### waitFor

`waitFor()`

Wait for an async condition to be met (useful for testing async updates).

**Parameters:**

* `check: () => void`: a function that throws an error if the condition is not met.
* `options?:` [`WaitForOptions`](#waitforoptions): optional configuration options.

**Return:** `Promise<void>`

### debugLog

`debugLog()`

Log the rendered tree to the console for debugging.

**Parameters:**

* `label?: string`: an optional label for the log output.

**Return:** `void`

### getRootNode

`getRootNode()`

Get the root node of the rendered tree.

**Return:** [`RenderedRootNode`](#renderedrootnode)

### mocks

Object containing mock implementations and spies (see [Mocking](/apps/developer-platform/add-features/ui-extensions/tools/testing/mocking) for detailed usage).

**Properties:**

* `mocks.useCrmProperties()`: [`FunctionSpy`](#functionspy) for the `useCrmProperties()` hook.
* `mocks.useAssociations()`: [`FunctionSpy`](#functionspy) for the `useAssociations()` hook.
* `mocks.context`: mock `context` object for the [Extension Point API](#extensionpointlocation)
* `mocks.actions`: object containing [`FunctionSpy`](#functionspy) instances for [Extension Point API](#extensionpointlocation) actions.
* `mocks.runServerlessFunction()`: [`FunctionSpy`](#functionspy) for the `runServerlessFunction()` function.

## FunctionSpy

`FunctionSpy`

Each mocked function (hooks, actions, `runServerlessFunction()`) is a [tinyspy](https://github.com/tinylibs/tinyspy) spy that provides inspection and control over function calls.

### called

`called`

Boolean indicating if the function was called at least once.

**Type:** `boolean`

### callCount

`callCount`

Number of times the function was called.

**Type:** `number`

### calls

`calls`

Array of argument arrays for each call. Access arguments via `spy.calls[0][0]`, `spy.calls[0][1]`, etc.

**Type:** `any[][]`

### results

`results`

Array of tuples representing each call's result:

* Success: `['ok', returnValue]`
* Error: `['error', errorValue]`

**Type:** `(['ok', any] | ['error', any])[]`

### returns

`returns`

Array of return values for each successful call (shorthand for filtering `results` by `'ok'`).

**Type:** `any[]`

### nextResult

`nextResult()`

Set the return value for the next invocation only.

**Parameters:**

* `value: any`: the value to return on the next call.

**Return:** `FunctionSpy`

### willCall

`willCall()`

Replace the mock implementation with a custom function.

**Parameters:**

* `fn: Function`: the custom implementation function

**Return:** `FunctionSpy`

### reset

`reset()`

Clear all call history while preserving the mock implementation.

**Return:** `FunctionSpy`

### restore

`restore()`

Restore the spy to its original default implementation and clear call history.

**Return:** `FunctionSpy`

**Example:**

```ts theme={null}
const renderer = createRenderer('crm.record.tab');

// Mock return value
renderer.mocks.useCrmProperties().nextResult({
  propertyName: { value: 'Test Value' }
});

// Check if called
expect(renderer.mocks.useCrmProperties().called).toBe(true);
expect(renderer.mocks.useCrmProperties().callCount).toBe(1);

// Check arguments
const [propertyNames] = renderer.mocks.useCrmProperties().calls[0];
expect(propertyNames).toEqual(['firstName', 'lastName']);
```

## HubSpotReactComponent

`HubSpotReactComponent`

Any of the HubSpot UI component types exported by the UI Extensions SDK. These are used with query methods to find rendered components.

**Import:**

```ts theme={null}
import { Alert, Button, Text, Box, Flex, /* etc. */ } from '@hubspot/ui-extensions';
```

**Example:**

```ts theme={null}
const renderer = createRenderer('crm.record.tab');
renderer.render(<Button variant="primary">Click me</Button>);

const button = renderer.find(Button);
expect(button.props.variant).toBe('primary');
```

## RenderedElementNode

`RenderedElementNode`

Represents a rendered HubSpot UI component element in the tree.

### nodeType

`nodeType`

Always [`RenderedNodeType`](#renderednodetype)`.Element`

**Type:** `RenderedNodeType.Element`

### name

`name`

Component name (e.g., `'Button'`, `'Text'`).

**Type:** `string`

### props

`props`

Component props object (fragments in props are converted to [`RenderedFragmentNode`](#renderedfragmentnode)).

**Type:** `Record<string, any>`

### text

`text`

Concatenated text content of all descendant text nodes, or `null` if none.

**Type:** `string | null`

### childNodes

`childNodes`

Array of child nodes.

**Type:** [`RenderedNode`](#renderednode)`[]`

### Query methods

All [common query methods](#common-query-methods) are available: `find()`, `findAll()`, `findChild()`, `findAllChildren()`, `maybeFind()`, `maybeFindChild()`

### isMatch

`isMatch()`

Check if this node matches a component type and optional matcher.

**Parameters:**

* `component:` [`HubSpotReactComponent`](#hubspotreactcomponent)
* `matcher?:` [`ElementMatcher`](#elementmatcher)

**Return:** `boolean`

### trigger

`trigger()`

Trigger an event handler prop (e.g., `node.trigger('onClick')`).

**Parameters:**

* `eventPropName: string`: the name of the event handler prop.
* `eventArg?: any`: an optional argument to pass to the event handler.

**Return:** `void`

### debugLog

`debugLog()`

Log the element tree to the console for debugging.

**Parameters:**

* `label?: string`: an optional label for the log output

**Return:** `void`

### toString

`toString()`

Get string representation of the node.

**Return:** `string`

## RenderedFragmentNode

`RenderedFragmentNode`

Represents the root of the rendered fragment.

### nodeType

`nodeType`

Always [`RenderedNodeType`](#renderednodetype)`.Fragment`

**Type:** `RenderedNodeType.Fragment`

### childNodes

`childNodes`

Array of child nodes.

**Type:** [`RenderedNode`](#renderednode)`[]`

### Query methods

All [common query methods](#common-query-methods) are available: `find()`, `findAll()`, `findChild()`, `findAllChildren()`, `maybeFind()`, `maybeFindChild()`

### isMatch

`isMatch()`

Check if this node matches a component type and optional matcher (will always return `false`).

**Parameters:**

* `component:` [`HubSpotReactComponent`](#hubspotreactcomponent)
* `matcher?:` [`ElementMatcher`](#elementmatcher)

**Return:** `boolean`

### debugLog

`debugLog()`

Log the element tree to the console for debugging.

**Parameters:**

* `label?: string`: an optional label for the log output.

**Return:** `void`

### toString

`toString()`

Get string representation of the node.

**Return:** `string`

## RenderedRootNode

`RenderedRootNode`

Represents the root of the entire rendered tree. This is the node returned by `renderer.render()`.

### nodeType

`nodeType`

Always [`RenderedNodeType`](#renderednodetype)`.Root`

**Type:** `RenderedNodeType.Root`

### childNodes

`childNodes`

Array of child nodes.

**Type:** [`RenderedNode`](#renderednode)`[]`

### Query methods

All [common query methods](#common-query-methods) are available: `find()`, `findAll()`, `findChild()`, `findAllChildren()`, `maybeFind()`, `maybeFindChild()`

### isMatch

`isMatch()`

Check if this node matches a component type and optional matcher (will always return `false`).

**Parameters:**

* `component:` [`HubSpotReactComponent`](#hubspotreactcomponent)
* `matcher?:` [`ElementMatcher`](#elementmatcher)

**Return:** `boolean`

### debugLog

`debugLog()`

Log the element tree to the console for debugging.

**Parameters:**

* `label?: string`: an optional label for the log output.

**Return:** `void`

### toString

`toString()`

Get string representation of the node.

**Return:** `string`

## RenderedTextNode

`RenderedTextNode`

Represents a text node in the rendered tree. Text nodes are leaf nodes automatically created when rendering string content in your components.

**Note:** Text nodes do not have `childNodes` or query methods since they are leaf nodes.

### nodeType

`nodeType`

Always [`RenderedNodeType`](#renderednodetype)`.Text`

**Type:** `RenderedNodeType.Text`

### text

`text`

The text content as a string.

**Type:** `string`

### isMatch

`isMatch()`

Check if this node matches a component type and optional matcher (will always return `false`).

**Parameters:**

* `component:` [`HubSpotReactComponent`](#hubspotreactcomponent)
* `matcher?:` [`ElementMatcher`](#elementmatcher)

**Return:** `boolean`

### toString

`toString()`

Get string representation of the node.

**Return:** `string`

## RenderedNode

`RenderedNode`

Union type representing any node in the rendered tree:

```ts theme={null}
type RenderedNode =
  | RenderedElementNode<any>
  | RenderedRootNode
  | RenderedFragmentNode
  | RenderedTextNode;
```

(See [`RenderedElementNode`](#renderedelementnode), [`RenderedRootNode`](#renderedrootnode), [`RenderedFragmentNode`](#renderedfragmentnode), [`RenderedTextNode`](#renderedtextnode))

## RenderedNodeType

`RenderedNodeType`

Enum of all possible node types in the rendered tree:

```ts theme={null}
enum RenderedNodeType {
  Root = 'root',
  Fragment = 'fragment',
  Element = 'element',
  Text = 'text',
}
```

## ElementMatcher

`ElementMatcher`

Optional parameter for query methods to filter elements beyond just component type.

A matcher can be:

* **Partial props object**: matches if the element has all specified prop values
* **Predicate function**: matches if the function returns `true` for the element node

**Examples:**

```ts theme={null}
// Match by partial props
const primaryButton = renderer.find(Button, { variant: 'primary' });

// Match using predicate function
const disabledButtons = renderer.findAll(
  Button,
  (node) => node.props.disabled === true
);

// Match by multiple props
const specificText = renderer.find(Text, {
  format: 'bold',
  variant: 'microcopy'
});
```

## ExtensionPointLocation

`ExtensionPointLocation`

A string literal union type representing valid extension point locations where UI extensions can be rendered.

**Type definition:**

```ts theme={null}
type ExtensionPointLocation =
  | 'crm.preview'
  | 'crm.record.sidebar'
  | 'crm.record.tab'
  | 'helpdesk.sidebar'
  | 'settings'
  | 'home';
```

The extension point location determines which extension point-specific APIs are available in the automatically created mocks for `context`, `actions`, and `runServerlessFunction`.

**Example:**

```ts theme={null}
// Creating a renderer for a CRM record tab extension
const renderer = createRenderer('crm.record.tab');

// Creating a renderer for a settings page extension
const settingsRenderer = createRenderer('settings');

// Creating a renderer for an app home extension
const homeRenderer = createRenderer('home');
```

## WaitForOptions

`WaitForOptions`

Options for the `waitFor()` function.

### timeoutInMs

`timeoutInMs`

Maximum time to wait in milliseconds (default: `1000`).

**Type:** `number | undefined`

**Default:** `1000`

## Utility Functions

Type guard functions for narrowing TypeScript types of rendered nodes and checking component matches.

**Import:**

```ts theme={null}
import {
  isRenderedElementNode,
  isRenderedTextNode,
  isRenderedRootNode,
  isRenderedFragmentNode,
  isMatch
} from '@hubspot/ui-extensions/testing';
```

### isRenderedElementNode

`isRenderedElementNode()`

Check if a node is a [`RenderedElementNode`](#renderedelementnode) and narrow its type.

**Parameters:**

* `node:` [`RenderedNode`](#renderednode)` | null | undefined`

**Return:** `node is RenderedElementNode`

### isRenderedTextNode

`isRenderedTextNode()`

Check if a node is a [`RenderedTextNode`](#renderedtextnode) and narrow its type.

**Parameters:**

* `node:` [`RenderedNode`](#renderednode)` | null | undefined`

**Return:** `node is RenderedTextNode`

### isRenderedRootNode

`isRenderedRootNode()`

Check if a node is a [`RenderedRootNode`](#renderedrootnode) and narrow its type.

**Parameters:**

* `node:` [`RenderedNode`](#renderednode)` | null | undefined`

**Return:** `node is RenderedRootNode`

### isRenderedFragmentNode

`isRenderedFragmentNode()`

Check if a node is a [`RenderedFragmentNode`](#renderedfragmentnode) and narrow its type.

**Parameters:**

* `node:` [`RenderedNode`](#renderednode)` | null | undefined`

**Return:** `node is RenderedFragmentNode`

### isMatch

`isMatch()`

Check if a node matches a specific component type and optional matcher criteria, narrowing to [`RenderedElementNode`](#renderedelementnode)`<TProps>`. Also available as a method on all rendered nodes.

**Type Parameters:**

* `TProps`: the props type of the component.

**Parameters:**

* `node:` [`RenderedNode`](#renderednode)` | null | undefined`
* `component:` [`HubSpotReactComponent`](#hubspotreactcomponent)
* `matcher?:` [`ElementMatcher`](#elementmatcher)

**Return:** `node is RenderedElementNode<TProps>`

**Example:**

```ts theme={null}
const nodes = renderer.getRootNode().childNodes;

for (const node of nodes) {
  if (isRenderedElementNode(node)) {
    // TypeScript knows node is RenderedElementNode here
    console.log(node.name, node.props);
  } else if (isRenderedTextNode(node)) {
    // TypeScript knows node is RenderedTextNode here
    console.log(node.text);
  }
}

// Using isMatch for component-specific type narrowing
const maybeButton = renderer.maybeFind(Button);
if (isMatch(maybeButton, Button, { variant: 'primary' })) {
  // TypeScript knows maybeButton is RenderedElementNode<ButtonProps>
  console.log(maybeButton.props.variant); // 'primary'
}
```
