Skip to main content

Patterns in RTL

See below some common patterns in RTL. Note that these examples are not complete code and may not work in all scenarios.

Arranging

Basic rendering is accomplished by replacing the mount or shallow functions with the render function. You must import the render function from the @jutro/test package.

render(<Component />);

The example below shows TranslatorProvider, but ModalNextProvider, ThemeProvider, BreakpointTrackerProvider and router are also included.

render(<Component />);

When passing props into a context, you must specify a second argument to render that takes in render options. The full list of options can be found here.

You can also configure context providers using the providers variable, as shown below. You can pass props to the provider, disable the provider, or substitute it with your own custom provider. There are five providers that you can configure:

  • router
  • globalization
  • modalNext
  • theme
  • breackpointTracker
render(<Component />, {
providers: {
globalization: {
props: {
defaultLocale: someLocale,
},
},
},
});

Acting

Simulating a click event in RTL is simple:

userEvent.click(button);

Simulating entering a value into a field is much simpler in RTL. The userEvent.clear function clears the field and the userEvent.type function types characters into it. See the userEvent docs for more info about userEvent utility.

userEvent.clear(input);
userEvent.type(input, 'myValue{enter}');

There is no way in RTL to directly focus or blur a given element, but you can easily emulate a "tab" key press.

Note: this will only work if the button is the first focusable item on the page. If it's the second focusable item, three tab key presses would be needed: two to focus the button, and a third to blur it.

userEvent.tab();
userEvent.tab();

Asserting

How to check whether an input has the desired value:

expect(screen.getByRole('textbox')).toHaveValue('foo');

How to check whether a button exists and has a properly translated aria-label:

const myButton = screen.getByLabelText(getTranslation(messageProps.myBtnLabel));

expect(myButton).toBeInTheDocument();

The following example illustrates that assertions are identical when using mocks. The only difference would be in the action code:

const callbackSpy = jest.fn();

// some actions happen

expect(callbackSpy).toHaveBeenCalledWith(
newValue,
undefined,
expect.anything()
);

The className matcher has a different name in @testing-library/jest-dom. You can find the list of all available matchers here.

expect(element).toHaveClass('someClass');

How to check whether an element with given text exists:

expect(screen.getByText(getTranslation('myText'))).toBeInTheDocument();

How to check whether a checkbox is checked:

const checkbox = screen.getByRole('checkbox');

expect(checkbox).toBeChecked();

The following shows how to check whether the input is accessibly disabled. Note that .toBeDisabled() cannot be used here because it does not not take into account the presence or absence of the aria-disabled attribute.

expect(input).toHaveAttribute('aria-disabled', 'true');