Tools
Props in ink are standardized to work well with React Testing Library (RTL), which is widely used in Carta.
React Testing Library is built to work with the implementation side of testing, focusing on user interaction through mouse, trackpad and keyboard as well as assistive technologies.
To better work with RTL, ink components are built with accessibility in mind, having passed through accessibility audits and tests. All interactive elements inside ink components have aria-labels, roles, and accessible names that can be used for testing.
RTL is designed to interact with pages and components exactly as your users would, ensuring it can only access what they (or assistive technologies) can see.
RTL primary selects through interactive components such as buttons, inputs, and text. As a result, ink prioritizes those as selectors.
Interactive elements in RTL range from buttons to any text that can be seen on the screen by the user or screen readers, so selecting components really depends on what you're trying to test.
For example:
RTL makes very good use of accessible attributes, these attributes are (but not limited to): name
, role
, title
, aria-label
, alt
.
HTML elements have implicit roles, which means most ink components already have their respective accessible roles defined.
Another way to find all the roles present on the code you're testing is to run your test with an empty getByRole("")
as the test will show you all the available elements with roles in your code.
If you can't find a component's role, need help with testing, or want to let us know there's no way to select a specific element, reach out to the #ink channel.
Beyond roles, to select these other attributes you can use, for example:
aria-labels
;alt
attribute;One of the issues with using roles is when there are more than just one input or select on a given page, how can one be sure they are selecting the right one?
Many people will use queryByRole
and manually select one of the returning components using bracket notation ([]), however, this approach is incomplete and very prone to error. For example, in case ink changes the component's internal structure or there is a need to change the order of the components on the page, the test would break.
In order to properly select the specific component, you need to add options to your query, for example, the component's name
:
<Form><Field htmlFor="newinput-fullname" label="Full name"><NewInput id="newinput-fullname" /></Field><Field htmlFor="newinput-email" label="Email"><NewInput id="newinput-email" /></Field></Form>
Selecting the first input:
screen.getByRole("textbox", { name: /full name/i }); // You can also use the specific string instead of regex
Selecting the second input:
screen.getByRole("textbox", { name: /email/i })
We highly encourage users to select components using this technique as it is best practice, more readable, and also less prone to errors.
You can also find your element's name by running your test with an empty getByRole("")
. It will also show the named elements, alongside their roles.
Some images or elements might be hidden from screen readers for accessibility, which might pose a problem for some tests. To select these types of components, there's another option that can be used:
screen.getByRole("img", { name: "edit", hidden: true })
This will make sure the test can see your component and select it.
According to RTL's guiding principles, data-testid
s are considered the last resource for testing, and should be used sparingly.
To help with those cases, every ink component will have at least one data-testid
that can be used to select the outer most relevant wrapper element in the component. For example NewDatePicker
:
<NewDatePicker.Wrapper data-testid="your-testid"><NewDatePicker.Input /><NewDatePicker.Calendar /></NewDatePicker.Wrapper>
Some of ink's components might be too complex to have only one data-testid
so ink adds other relevant data-testid
s . For example SpreadsheetV2
has different data-testid
s for the Slider, the Menu, and the Table. But the user only needs to provide a single data-testid
and an id
that is modified internally to have respectivelly -slider
, -menu
, -table
at the end of the id
provided.
<SpreadsheetWrapper data-testid="your-testid" id="your-id"><SpreadsheetMenu data-testid="your-id-menu" /><SpreadsheetTable data-testid="your-id-table" /><SpreadsheetSlider data-testid="your-id-slider" /></SpreadsheetWrapper>
To select data-testid
s on tests, use .getByTestId()
ink, as does React Testing Library, suggests the use of userEvent instead of fireEvent
as it is a more complete solution and simulates entire interactions.
ink also recommends the use of act
around userEvent
when you are interacting with components that are not async
or await
based. This is because act
will make sure all the updates are flushed before the test continues, making it more reliable:
act(() => {userEvent.click(screen.getByText("Row 1"));})
Is this page helpful?