import { Meta } from '@storybook/addon-docs/blocks';

<Meta title="Docs/Getting Started/Testing" />

# Testing

Tests are performed with Jest and React Testing Library, and must be present for each component/atom in the component's test subdirectory, for example `src/components/my-component/MyComponent/tests/MyComponent.test.jsx`

To run tests, type `npm run test` in the terminal, in the root directory of the project. The code is linted before the test execution.

For more information about the testing libraries, see:
- [jest](https://jestjs.io/docs/en/getting-started) for general information on how to write tests
- [testing-library queries](https://testing-library.com/docs/queries/about/) for selecting elements in the rendered dom
- [jest-dom](https://github.com/testing-library/jest-dom) for testing the state of the dom

## Adding test IDs to elements

The most common way to access elements in the rendered dom is through test IDs. The `createNamespace` util has a method to add test IDs to rendered elements so that you can access and inspect them afterward.

```jsx
const n = createNamespace('MyComponent');
return <div {...n('foo').withTestId().props}>Hello</div>;
```

In the test file, access the element like this:

```jsx
const { getByTestId } = render(<MyComponent />);
const foo = getByTestId('myComponent:foo')
expect(foo).toHaveTextContent('Hello');
```

### Custom IDs

It is also possible to add custom test IDs to the elements, if for example multiple elements would have the same class (or no class at all) but would need to be targeted distinctly in the tests.

```jsx
const n = createNamespace('MyComponent');
<div {...n().withTestId('myCustomTest').props}>Hello</div>
```

In the test file, access the element like this:

```jsx
const { getByTestId } = render(<MyComponent />);
const foo = getByTestId('myComponent:myCustomTest')
expect(foo).toHaveTextContent('Hello');
```

## Minimal tests required

There are no rules for writing tests, but minimally we recommend that you test the following:

- Component renders without errors when no props are passed
- Component renders its basic parts when typical props are passed
- Component renders correct number of children, if applicable
- Each setting's effect, if component has settings
- Local effects (for example, clicking a button changes the state of the component) 
- Global effects (for example, clicking a button calls a global function)

### Accessibility

We recommend that you also test for accessibility (a11y), whose tests should be in a separate file named with the pattern `MyComponent.a11y.test.jsx`. Tests for a11y are performed with the `jest-axe`, and should minimally test that there are no a11y violations in the components.

## How to test CSS

There are no CSS tests as such, but we recommend that you test the presence of certain indicators depending on settings or data. For example, if a setting has a visual effect on the component through the addition of a modifier to an element's class, test the presence of that modifier.

### Modifiers

You can test CSS modifiers added through `namingTools` like this:

```jsx
const n = createNamespace('MyComponent');
return <div {...n('foo', 'bar').withTestId().props}>Hello</div>;
```

```jsx
const { getByTestId } = render(<MyComponent />);
expect(getByTestId('myComponent:foo')).toHaveClass('myComponent_foo--bar');
```

### CSS variables

CSS variables are passed as props of the `style` prop of dom elements, therefore you can test them by inspecting this prop.

```jsx
const n = createNamespace('MyComponent');
return <div {...n('foo').withVariables({'my-var': '3px'}).withTestId().props}>Hello</div>;
```

```jsx
const { getByTestId } = render(<MyComponent />);
expect(getByTestId('myComponent:foo')).toHaveStyle('--my-var: 3px');
```

#### Casing

Because CSS variables are added as attributes to dom elements, and those attributes are lower-case only, CSS variables are automatically rewritten as lowercase by the device's rendering engine. Therefore, a snakeCase variable in an element would not trigger an error, but it would make it untestable directly. For example:

```jsx
return <div {...n().withVariables({myVar: '3px'}).props}>Hello</div>;
```

results in 

```html
<div style="--myvar: 3px">Hello</div>
```

For that reason, we recommend that you avoid snakeCase in CSS variables and use kebab-case instead.


