primitives
primitives copied to clipboard
Tabs: Snapshot tests for Components with Tab.Content are often flaky
Bug report
I like to use snapshot tests to verify my React components. Given a certain input or state I can verify the expected result and catch regressions if anything changes. I have a minimal example below to demonstrate the issue. Vitest/jest/other testing framework doesn't affect the issue.
Current Behavior
As we see in the snapshot, when it renders the div for Tab.Content it inserts the line style="animation-duration: 0s;"
. The problem is that sometimes when running these tests, especially on a slower or faster system it flips between the aforementioned style and style=""
.
I believe this is because it adds some extra style when mounting (https://github.com/radix-ui/primitives/blob/main/packages/react/tabs/src/Tabs.tsx#L257).
This means that occasionally any component containing Tab.Content renders slightly different which breaks the test.
Expected behavior
Ideally, the component should render consistently so that it would match the snapshot every time.
Reproducible example
Some component:
import React from "react";
import * as Tabs from "@radix-ui/react-tabs";
export const Example = () => (
<Tabs.Root>
<Tabs.List>
<Tabs.Trigger>First</Tabs.Trigger>
<Tabs.Trigger>Second</Tabs.Trigger>
</Tabs.List>
<Tabs.Content>
<p>This is the first</p>
</Tabs.Content>
<Tabs.Content>
<p>This is the second</p>
</Tabs.Content>
</Tabs.Root>
);
Some test:
import { expect, describe, it } from "vitest";
import { render } from "@testing-library/react";
import { Example } from "./Example";
describe("<Example>", () => {
it("should render consistently", () => {
const { container } = render(<Example />);
expect(container).toMatchSnapshot();
});
});
resulting in the following snapshot:
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`<Example> > should render consistently 1`] = `
<div>
<div
data-orientation="horizontal"
dir="ltr"
>
<div
aria-orientation="horizontal"
data-orientation="horizontal"
role="tablist"
style="outline: none;"
tabindex="0"
>
<button
aria-controls="radix-:r0:-content-undefined"
aria-selected="true"
data-orientation="horizontal"
data-radix-collection-item=""
data-state="active"
id="radix-:r0:-trigger-undefined"
role="tab"
tabindex="-1"
type="button"
>
First
</button>
<button
aria-controls="radix-:r0:-content-undefined"
aria-selected="true"
data-orientation="horizontal"
data-radix-collection-item=""
data-state="active"
id="radix-:r0:-trigger-undefined"
role="tab"
tabindex="-1"
type="button"
>
Second
</button>
</div>
<div
aria-labelledby="radix-:r0:-trigger-undefined"
data-orientation="horizontal"
data-state="active"
id="radix-:r0:-content-undefined"
role="tabpanel"
style="animation-duration: 0s;"
tabindex="0"
>
<p>
This is the first
</p>
</div>
<div
aria-labelledby="radix-:r0:-trigger-undefined"
data-orientation="horizontal"
data-state="active"
id="radix-:r0:-content-undefined"
role="tabpanel"
style="animation-duration: 0s;"
tabindex="0"
>
<p>
This is the second
</p>
</div>
</div>
</div>
`;
Suggested solution
I'm not sure how to solve this in practice. Part of the reason I'm filing this is to see if there are any suggestions or workarounds. I've tried searching both the bug tracker and online in general, but to my surprise haven't found any others with this problem.
Normally in snapshot tests, if the component has interactive or async elements, one can use waitFor
to see if some specific element or text is present in the document. This is slightly trickier to do when it comes to style properties, especially when once it's loaded the property is set to undefined so I don't have anything to check for.
Some workarounds we have tried:
- Mocking the Tab.Content import and replace it with a div. The snapshot doesn't break anymore, but we lose a couple of other things :(
- In some testsuites we have added an extra line to sleep for an additional 100ms before checking the snapshot. This seems to give more consistent results but is of course rather hacky.
Additional context
Your environment
Software | Name(s) | Version |
---|---|---|
Radix Package(s) | react-tabs | 1.0.4 |
React | n/a | 18.2.0 |
Browser | ||
Assistive tech | ||
Node | n/a | 16.x / 18.x |
npm/yarn | ||
Operating System |
@hansjoachim did you find any workaround for this?
Not really found any workarounds beyond those mentioned in the original report.