rofrischmann/fela

View on GitHub
website/docs/12.0.2/recipes/testing-components.mdx

Summary

Maintainability
Test Coverage
# Testing Components

There is no required library for testing Fela components. Since Fela is [framework-agnostic](intro/benefits#framework-agnostic), you may use any javascript testing library to test your components. Fela's source is already [fully tested](https://codeclimate.com/github/robinweser/fela/coverage), so your tests should only confirm that Fela's styles are interacting correctly with the components.

## Testing Rules

The most straight-forward way is to test our [rules](basics/rules) directly. This is the same regardless of which framework and bindings are used.<br />
[Rules are just pure functions](basics/rules). Eric Elliot, a respected Javascript instructor in the industry, [defines pure functions for us](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976). A pure function is a function which:

- Given the same input, will always return the same output.
- Produces no side effects.
- Relies on no external mutable state.

Since our rules will follow this definition, our tests can simply ensure our rules _output the correct styles for every input._

## Snapshot Testing

While testing pure rules is a nice way to ensure the styles are correctly computed, the benefits are quite limited. Instead, we should test the integration with our actual components.<br />
The best and most simple method to do so is [snapshot testing](https://facebook.github.io/jest/docs/en/snapshot-testing.html#content). We will use [Jest](https://facebook.github.io/jest/) to demonstrate that, but any other library to supports something similar to snapshot testing with just work fine as well.

A basic snapshot test for a React component looks something like this:

```jsx
import * as React from 'react'
import renderer from 'react-test-renderer'

import MyComponent from './MyComponent'

describe('<MyComponent />', () => {
  it('renders correctly', () => {
    const tree = renderer.create(<MyComponent>Hello</MyComponent>)
    const snapshot = tree.toJSON()
    expect(snapshot).toMatchSnapshot()
  })
})
```

### CSS Snapshots

The problem is that this snapshot only includes the rendered HTML markup as of now which only includes the class name references e.g.

```snapshot name=Snapshot nocopy
<div class="a b c d">Hello</div>
```

It **doesn't** include the rendered CSS output and thus is not sufficient for us to also test our styles accordingly.<br />
Luckily, there's yet another package to achieve that in seconds!

## jest-react-fela

The [jest-react-fela](https://github.com/robinweser/fela/tree/master/packages/jest-react-fela) package exports a single [createSnapshot](api/jest-react-fela/createSnapshot) function.

> **Note**: It is also available for [Preact](https://github.com/robinweser/fela/tree/master/packages/jest-preact-fela) and [Inferno](https://github.com/robinweser/fela/tree/master/packages/jest-inferno-fela).

We can replace our `react-test-renderer` code with a simple [createSnapshot](api/jest-react-fela/createSnapshot) call to get a reasonable snapshot with HTML and CSS markup.

```jsx
import * as React from 'react'
import { createSnapshot } from 'jest-react-fela'

import MyComponent from './MyComponent'

describe('<MyComponent />', () => {
  it('renders correctly', () => {
    const snapshot = createSnapshot(<MyComponent>Hello</MyComponent>)
    expect(snapshot).toMatchSnapshot()
  })
})
```

The snapshot might now look something like this:

```snapshot name=Snapshot nocopy
.a {
  padding-left: 10px
}

.b {
  color: red
}

.c {
  font-size: 16px
}

@media (min-width: 1024px) {
  .d {
    padding-left: 15px
  }
}

<div class="a b c d">Hello</div>
```

### Passing a Theme

[createSnapshot](api/jest-react-fela/createSnapshot) accepts a couple of additional arguments.<br />
Probably the most important one is the second argument which accepts a custom theme to be passed to the component.<br />
If your component renders styles depending on a theme, it will now automatically pick the passed one.

> Chek the API reference for more information on all accepted arguments.

```jsx
import * as React from 'react'
import { createSnapshot } from 'jest-react-fela'

const theme = {
  colors: {
    primary: 'red',
    secondary: 'blue',
  },
  breakpoints: {
    small: '@media (min-width: 480px)',
    large: '@media (min-width: 1024px)',
  },
}

describe('<MyComponent />', () => {
  it('renders correctly', () => {
    const snapshot = createSnapshot(<MyComponent>Hello</MyComponent>, theme)
    expect(snapshot).toMatchSnapshot()
  })
})
```