Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docs] Update testing guide #21863

Merged
merged 4 commits into from
Jul 22, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 11 additions & 157 deletions docs/src/pages/guides/testing/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,166 +2,20 @@

<p class="description">Write tests to prevent regressions and write better code.</p>

Examples in this guide use [global methods from Mocha](https://mochajs.org/api/global.html), not [Jest](https://jestjs.io/docs/en/api).

## Internal

Material-UI has **a wide range** of tests so we can
iterate with confidence on the components, for instance, the visual regression tests provided by [Argos-CI](https://www.argos-ci.com/mui-org/material-ui) have proven to be really helpful.
To learn more about the internal tests, you can have a look at the [README](https://github.com/mui-org/material-ui/blob/next/test/README.md).

## Userspace

What about writing tests in userspace? The Material-UI styling infrastructure uses some helper functions built on top of [enzyme](https://github.com/airbnb/enzyme) to make the process easier, which we are exposing. You can take advantage of them if you so choose.
We use almost exclusively full DOM rendering APIs. We encourage you to do the same especially
if your components rely on custom themes. Tests using shallow rendering APIs become more brittle
with the amount of provider components they require.

### Full DOM rendering

Full DOM rendering is ideal for use cases where you have components that may interact with DOM APIs or may require the full lifecycle in order to fully test the component (e.g., `componentDidMount` etc.).

The `createMount()` function is provided for this situation.
Aside from wrapping the enzyme API, it provides a `cleanUp` function.

### Shallow rendering

Shallow rendering is useful to constrain your testing to a component as a unit. This also ensures that your tests aren't indirectly asserting behavior of child components.
Shallow rendering was created to test components in isolation. This means without leaking child implementation details such as the context.

The `createShallow()` function can be used for this situation. Aside from wrapping the enzyme API, it provides a `dive` and `untilSelector` option.

### Render to string

Rendering to a string is useful to test the behavior of the components that are used on the server.
You can take advantage of this to assert the generated HTML string.

The `createRender()` function is ideal for this. This is just an alias for the enzyme API, which is only exposed for consistency.

## API

### `createMount([options]) => mount`

Generate an enhanced mount function with the needed context.
Please refer to the [enzyme API documentation](https://airbnb.io/enzyme/docs/api/mount.html) for further details on the `mount` function.

#### Arguments

1. `options` (_Object_ [optional])

- `options.mount` (_Function_ [optional]): The mount function to enhance, it uses **enzyme by default**.
- The other keys are forwarded to the options argument of `enzyme.mount()`.

#### Returns

`mount` (_mount_): A mount function.

#### Examples

```jsx
import { createMount } from '@material-ui/core/test-utils';
import { ThemeProvider } from '@material-ui/core/styles';

describe('<MyComponent />', () => {
let mount;

function MySuccessButton({ children }) {
return (
<ThemeProvider
theme={{
success: { main: '#fff' },
}}
>
{children}
</ThemeProvider>
);
}
It's generally recommended to test your application without tying the tests too closely to Material-UI.
This is how Material-UI components are tested internally.
A library that has a first-class API for this approach is [`@testing-library/react`](https://testing-library.com/docs/react-testing-library/intro).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this sentence should come at the end of the section, after the approach has been fully explained? The prior sentences only allude to what not to do...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes more sense 👍 I moved it after the example.


before(() => {
mount = createMount();
});
For example, when rendering a `TextField` your test should not need to query for the specific Material-UI instance of the `TextField` but rather for the `input`, or `[role="textbox"]`.

after(() => {
mount.cleanUp();
});
By not relying on the React component tree you make your test more robust against internal changes in Material-UI or, if you need snapshot testing, adding additional wrapper components such as context providers.
We don't recommend snapshot testing though.
["Effective snapshot testing" by Kent C. Dodds](https://kentcdodds.com/blog/effective-snapshot-testing) goes into more details why snapshot testing might be misleading for React component tests.

it('should work', () => {
const wrapper = mount(
<MockedTheme>
<MySuccessButton />
</MockedTheme>,
);
});
});
```

### `createShallow([options]) => shallow`

Generate an enhanced shallow function with the needed context.
Please refer to the [enzyme API documentation](https://airbnb.io/enzyme/docs/api/shallow.html) for further details on the `shallow` function.

#### Arguments

1. `options` (_Object_ [optional])

- `options.shallow` (_Function_ [optional]): The shallow function to enhance, it uses **enzyme by default**.
- `options.untilSelector` (_String_ [optional]): Recursively shallow renders the children until it can find the provided selector. It's useful to drill down higher-order components.
- `options.dive` (_Boolean_ [optional]): Shallow function renders the one non-DOM child of the current wrapper, and returns a wrapper around the result.
- The other keys are forwarded to the options argument of `enzyme.shallow()`.

#### Returns

`shallow` (_shallow_): A shallow function.

#### Examples

```jsx
import { createShallow } from '@material-ui/core/test-utils';

describe('<MyComponent />', () => {
let shallow;

before(() => {
// This is Mocha; in Jest, use beforeAll
shallow = createShallow();
});

it('should work', () => {
const wrapper = shallow(<MyComponent />);
});
});
```

### `createRender([options]) => render`

Generate a render to string function with the needed context.
Please refer to the [enzyme API documentation](https://airbnb.io/enzyme/docs/api/render.html) for further details on the `render` function.

#### Arguments

1. `options` (_Object_ [optional])

- `options.render` (_Function_ [optional]): The render function to enhance, it uses **enzyme by default**.
- The other keys are forwarded to the options argument of `enzyme.render()`.

#### Returns

`render` (_Function_): A render to string function.

#### Examples

```jsx
import { createRender } from '@material-ui/core/test-utils';

describe('<MyComponent />', () => {
let render;

before(() => {
render = createRender();
});
## Internal

it('should work', () => {
const wrapper = render(<MyComponent />);
});
});
```
Material-UI has **a wide range** of tests so we can
iterate with confidence on the components, for instance, the visual regression tests provided by [Argos-CI](https://www.argos-ci.com/mui-org/material-ui) have proven to be really helpful.
To learn more about the internal tests, you can have a look at the [README](https://github.com/mui-org/material-ui/blob/next/test/README.md).