Skip to main content
Below are the available functions and types for the UI extensions SDK testing utilities.

createRenderer

createRenderer() Creates a Renderer object with methods for rendering UI extension components and querying the rendered output. Parameters:
  • 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 Import:
import { createRenderer } from '@hubspot/ui-extensions/testing';
Example:
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 and select node types (RenderedRootNode, RenderedElementNode, RenderedFragmentNode): Common parameters:

find

find() Find a single element matching the component type. Throws an error if not found or multiple matches exist. Parameters: Return: RenderedElementNode

findAll

findAll() Find all elements matching the component type. Returns an array. Parameters: Return: RenderedElementNode[]

findChild

findChild() Find a direct child element matching the component type. Throws an error if not found or multiple matches exist. Parameters: Return: RenderedElementNode

findAllChildren

findAllChildren() Find all direct child elements matching the component type. Returns an array. Parameters: Return: RenderedElementNode[]

maybeFind

maybeFind() Find a single element matching the component type. Returns null if not found or multiple matches exist. Parameters: Return: RenderedElementNode | null

maybeFindChild

maybeFindChild() Find a direct child element matching the component type. Returns null if not found or multiple matches exist. Parameters: Return: 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

Query methods

All 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: the component type to find.
  • testId: string: the test ID to search for.
Return: 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:
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: the component type to find.
  • testId: string: the test ID to search for.
Return: 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:
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: 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

mocks

Object containing mock implementations and spies (see Mocking for detailed usage). Properties:

FunctionSpy

FunctionSpy Each mocked function (hooks, actions, runServerlessFunction()) is a 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:
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:
import { Alert, Button, Text, Box, Flex, /* etc. */ } from '@hubspot/ui-extensions';
Example:
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.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). 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[]

Query methods

All 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: 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.Fragment Type: RenderedNodeType.Fragment

childNodes

childNodes Array of child nodes. Type: RenderedNode[]

Query methods

All 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: 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.Root Type: RenderedNodeType.Root

childNodes

childNodes Array of child nodes. Type: RenderedNode[]

Query methods

All 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: 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.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: Return: boolean

toString

toString() Get string representation of the node. Return: string

RenderedNode

RenderedNode Union type representing any node in the rendered tree:
type RenderedNode =
  | RenderedElementNode<any>
  | RenderedRootNode
  | RenderedFragmentNode
  | RenderedTextNode;
(See RenderedElementNode, RenderedRootNode, RenderedFragmentNode, RenderedTextNode)

RenderedNodeType

RenderedNodeType Enum of all possible node types in the rendered tree:
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:
// 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:
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:
// 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:
import {
  isRenderedElementNode,
  isRenderedTextNode,
  isRenderedRootNode,
  isRenderedFragmentNode,
  isMatch
} from '@hubspot/ui-extensions/testing';

isRenderedElementNode

isRenderedElementNode() Check if a node is a RenderedElementNode and narrow its type. Parameters: Return: node is RenderedElementNode

isRenderedTextNode

isRenderedTextNode() Check if a node is a RenderedTextNode and narrow its type. Parameters: Return: node is RenderedTextNode

isRenderedRootNode

isRenderedRootNode() Check if a node is a RenderedRootNode and narrow its type. Parameters: Return: node is RenderedRootNode

isRenderedFragmentNode

isRenderedFragmentNode() Check if a node is a RenderedFragmentNode and narrow its type. Parameters: Return: node is RenderedFragmentNode

isMatch

isMatch() Check if a node matches a specific component type and optional matcher criteria, narrowing to RenderedElementNode<TProps>. Also available as a method on all rendered nodes. Type Parameters:
  • TProps: the props type of the component.
Parameters: Return: node is RenderedElementNode<TProps> Example:
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'
}