Skip to content
Vy logo
  • Identitet
  • Spor
  • Resources
Guides

Tests and Storybook

Testing is a crucial part of development. This guide will walk you through writing tests for Spor components to ensure quality, accessibility, and reliability.

🔍 How We Test

We use Vitest, Testing Library, and Axe to test our code in Spor. This combination makes it easy to write tests that also check for universal accessibility compliance. If you're new to these tools, it's worth taking a quick look at their documentation:

  • VitestEkstern lenke
  • Testing LibraryEkstern lenke
  • Axe for AccessibilityEkstern lenke

📝 Writing Your First Test

Create the test file

Component tests are located under the __test__ folder in the spor-react directory.

To get started, find the component you want to test. In this example, we will test a radio button component.

Create a new test file in the __test__ folder: radio.test.tsx

The .test.tsx naming convention indicates that this file contains tests for a TypeScript React component.

Create the component to test

Before writing the actual tests, you need to create the component that you want to test. Remember to wrap the component in a SporProvider.

...
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, test } from "vitest";
const value1 = "My first value";
const label1 = "World's best radio label";
const value2 = "Life changing value";
const label2 = "Radio label of the year";
// This will be the test-component that the tests will interact with.
const RadioGroupTest = (
props: JSX.IntrinsicAttributes &
Omit<RadioGroupRootProps, "colorPalette" | "size" | "variant"> & {
ref?: Ref<HTMLDivElement>;
},
) => (
<SporProvider>
<RadioGroup {...props}>
<Radio value={value1}>{label1}</Radio>
<Radio value={value2}>{label2}</Radio>
</RadioGroup>
</SporProvider>
);

Writing the tests

Use Vitest's describe and test functions to organize your tests. Then, use React Testing Library's render function to render the component created in the previous step. From there one you can use React Testing Library’s helperfunctions for testing visibility, states, user interaction, and more.

describe("RadioGroup and Radio", () => {
test("handles state correctly", async () => {
const user = userEvent.setup();
render(<RadioGroupTest />);
const input1 = screen.getByRole("radio", {
name: label1,
}) as HTMLInputElement;
const input2 = screen.getByRole("radio", {
name: label2,
}) as HTMLInputElement;
expect(input1.checked).toBe(false);
expect(input2.checked).toBe(false);
await user.click(screen.getByRole("radio", { name: label2 }));
expect(input1.checked).toBe(false);
expect(input2.checked).toBe(true);
});
});

Helper-functions for setup

describe

The describe function groups related tests together to make it easier to organize and understand the test results. In this example, all of the tests inside the block are related to the Radio component.

describe('Radio', () => { // Radio tests go here })

test

The test function defines an individual test. The first argument describes what the test should verify.

For example:

test('handles state correctly’, () => { // Test code goes here })

Try to describe the expected behavior rather than how the component is implemented. This makes tests easier to understand and maintain.

render

The render function comes from React Testing Library. It renders the React component in a test environment so that you can interact with it and make assertions about what the user sees.

Helper-functions for testing the component

screen

React Testing Library provides the screen object to query elements that have been rendered.

userEvents

Component tests should not only verify that a component renders correctly. You should also test how the component behaves when a user interacts with it. To simulate user interaction, use userEvent from React Testing Library:

♿ Testing for Accessibility

Axe helps ensure your code meets accessibility standards. Here’s how you can test it:

it("is accessible", async () => {
const { container } = render(<Button variant="primary">Click me</Button>);
expect(await axe(container)).toHaveNoViolations();
});

🔹 It’s a good idea to run this multiple times in different component states.

🚀 Test Smarter, Not Harder

🔹 Accessibility testing is tricky—even with Axe, only about 20% of accessibility bugs get caught automatically. Always test with a screen reader and keyboard navigation.

🔹 You don’t need 100% test coverage. Full test coverage can make refactoring difficult. Instead, write a few broad tests that cover most critical user flows efficiently.

🔧 Adding Tests to a Package That Doesn't Have Them

Not all Spor packages currently support testing. If you need to add test support to a package, follow these steps:

1. Add the required dependencies to package.json:

"devDependencies": {
"@testing-library/react": "^latest",
"vitest": "^latest",
"vitest-axe": "^latest"
}

2. Create a __tests__ directory inside the package.

3. Write a test file (e.g., ComponentName.test.tsx).

4. Run tests using:

pnpm test

By following these guidelines, you’ll help ensure that Spor components remain reliable, accessible, and easy to maintain! 🚀

📙 Storybook

Spor’s Storybook-application is a tool that makes it easier to build, test and showcase individual UI components in isolation. It uses the React Storybook packageEkstern lenke.

The Storybook contains multiple “stories”, where one story represent a simple component. The stories are co-located with the components in the packages/spor-react/src directory.

When introducing a new component it should receive an associated story. Start with creating a file named <component>.stories.tsx. Then, create a Story that can be used for testing:

import type { Meta, StoryObj } from "@storybook/react";
import { MyComponent } from "@vygruppen/spor-react";
const meta = {
title: "Components/MyComponent",
component: MyComponent,
} satisfies Meta<typeof MyComponent>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
// pass props here
},
};