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] Add testing section #7101

Merged
merged 1 commit into from
Jun 11, 2017
Merged
Show file tree
Hide file tree
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
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ instead of Github issues. There is a StackOverflow tag called "material-ui"
that you can use to tag your questions.

# [Material-UI](http://www.material-ui.com/)
[![npm package](https://img.shields.io/npm/v/material-ui.svg?style=flat-square)](https://www.npmjs.org/package/material-ui)
[![CircleCI](https://circleci.com/gh/callemall/material-ui/tree/next.svg?style=svg)](https://circleci.com/gh/callemall/material-ui/tree/next)
[![Gitter](https://img.shields.io/badge/gitter-join%20chat-f81a65.svg?style=flat-square)](https://gitter.im/callemall/material-ui?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Coverage Status](https://coveralls.io/repos/github/callemall/material-ui/badge.svg?branch=next)](https://coveralls.io/github/callemall/material-ui?branch=next)

[![PeerDependencies](https://img.shields.io/david/peer/callemall/material-ui.svg?style=flat-square)](https://david-dm.org/callemall/material-ui#info=peerDependencies&view=list)
[![Dependencies](https://img.shields.io/david/callemall/material-ui.svg?style=flat-square)](https://david-dm.org/callemall/material-ui)
[![DevDependencies](https://img.shields.io/david/dev/callemall/material-ui.svg?style=flat-square)](https://david-dm.org/callemall/material-ui#info=devDependencies&view=list)
[![npm package](https://img.shields.io/npm/v/material-ui.svg)](https://www.npmjs.org/package/material-ui)
[![CircleCI](https://img.shields.io/circleci/project/github/callemall/material-ui/next.svg)](https://circleci.com/gh/callemall/material-ui/tree/next)
[![Gitter](https://img.shields.io/badge/gitter-join%20chat-f81a65.svg)](https://gitter.im/callemall/material-ui?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Coverage Status](https://img.shields.io/codecov/c/github/callemall/material-ui/next.svg)](https://codecov.io/gh/callemall/material-ui/branch/next)

[![PeerDependencies](https://img.shields.io/david/peer/callemall/material-ui.svg)](https://david-dm.org/callemall/material-ui#info=peerDependencies&view=list)
[![Dependencies](https://img.shields.io/david/callemall/material-ui.svg)](https://david-dm.org/callemall/material-ui)
[![DevDependencies](https://img.shields.io/david/dev/callemall/material-ui.svg)](https://david-dm.org/callemall/material-ui#info=devDependencies&view=list)

Material-UI is a set of [React](http://facebook.github.io/react/) components that implement
[Google's Material Design](https://www.google.com/design/spec/material-design/introduction.html)
Expand Down
7 changes: 7 additions & 0 deletions docs/src/components/AppRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ export default function AppRouter() {
component={MarkdownDocs}
nav
/>
<Route
title="Testing"
path="/guides/testing"
content={requireMarkdown('./guides/testing.md')}
component={MarkdownDocs}
nav
/>
</Route>
<Route title="Style" path="/style" nav component={AppContent}>
<Route
Expand Down
138 changes: 138 additions & 0 deletions docs/src/pages/guides/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Testing

## Internal

We take tests seriously, we have written and we maintain **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/callemall/material-ui) have proven to be really helpful.
Copy link
Member

Choose a reason for hiding this comment

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

😄 Well I guess you deserve the link juice!

Copy link
Member Author

@oliviertassinari oliviertassinari Jun 11, 2017

Choose a reason for hiding this comment

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

Thanks for the review 🥝

To learn more about our internal tests, you can have a look at the [README](https://github.com/callemall/material-ui/blob/next/test/README.md).

[![Coverage Status](https://img.shields.io/codecov/c/github/callemall/material-ui/next.svg)](https://codecov.io/gh/callemall/material-ui/branch/next)

## Userspace

But what about writing tests in userspace? Material-UI styling infrastructure relies on the context feature of React to work correctly. You are going to need that context when testing your react components with ours.

### Shallow rendering

Shallow rendering is useful to constrain yourself to testing a component as a unit, and to ensure that your tests aren't indirectly asserting on behavior of child components.
We expose a `createShallow()` function for this situation. However, you will most likely not need it most of the time as shallow rendering was created to test components in isolation, without leaking children implementation details, like the context.

### 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 (i.e., `componentDidMount` etc.).
We expose a `createMount()` function for this situation.

### Render to string

Rendering to string is useful to test the behavior of the components that are used on the server.
You can take advantage of it to assert the generated HTML string.
We expose a `createRender()` function for this sitation.

## API

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

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


#### Arguments

1. `options` (*Object* [optional])
- `options.shallow` (*Function* [optional]): The shallow function to enhance, it's using **enzyme by default**.
- `options.otherContext` (*Object* [optional]): Context to be passed into the component.
- `options.dive` (*Boolean* [optional]): Shallow render the one non-DOM child of the current wrapper, and return a wrapper around the result.

#### Returns

`shallow` (*shallow*): A shallow function.

#### Examples

```js
import { createShallow } from 'material-ui/test-utils';

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

before(() => {
shallow = createShallow();
});

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

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

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

#### Arguments

1. `options` (*Object* [optional])
- `options.mount` (*Function* [optional]): The mount function to enhance, it's using **enzyme by default**.

#### Returns

`mount` (*mount*): A mount function.

#### Examples

```js
import { createMount } from 'material-ui/test-utils';

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

before(() => {
mount = createMount();
});

after(() => {
mount.cleanUp();
});

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

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

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

#### Arguments

1. `options` (*Object* [optional])
- `options.render` (*Function* [optional]): The render function to enhance, it's using **enzyme by default**.

#### Returns

`render` (*Function*): A render to string function.

#### Examples

```js
import { createRender } from 'material-ui/test-utils';

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

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

after(() => {
render.cleanUp();
});

it('should work', () => {
const wrapper = render(<MyComponent />);
});
});
```
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@
"prebuild": "npm run clean:build",
"start": "cd docs && npm start",
"test": "npm run lint && npm run flow && npm run test:unit",
"test:unit": "cross-env NODE_ENV=test mocha test/integration/{,**/}*.spec.js src/{,**/}*.spec.js",
"test:unit": "cross-env NODE_ENV=test mocha test/**/*.spec.js src/{,**/}*.spec.js",
"test:watch": "yarn test:unit -- -w",
"test:coverage": "cross-env NODE_ENV=test BABEL_ENV=coverage nyc mocha test/integration/{,**/}*.spec.js src/{,**/}*.spec.js && nyc report -r lcovonly",
"test:coverage:html": "cross-env NODE_ENV=test BABEL_ENV=coverage nyc mocha test/integration/{,**/}*.spec.js src/{,**/}*.spec.js && nyc report --reporter=html",
"test:coverage": "cross-env NODE_ENV=test BABEL_ENV=coverage nyc mocha test/**/*.spec.js src/{,**/}*.spec.js && nyc report -r lcovonly",
"test:coverage:html": "cross-env NODE_ENV=test BABEL_ENV=coverage nyc mocha test/**/*.spec.js src/{,**/}*.spec.js && nyc report --reporter=html",
"test:karma": "cross-env NODE_ENV=test karma start test/karma.conf.js --single-run",
"test:regressions": "webpack --config test/regressions/webpack.config.js && vrtest run --config test/vrtest.config.js --record",
"argos": "argos upload test/regressions/screenshots/chrome --token $ARGOS_TOKEN || true",
Expand Down Expand Up @@ -111,7 +111,6 @@
"flow-typed": "^2.1.2",
"fs-extra": "^3.0.1",
"glob": "^7.1.2",
"html-looks-like": "^1.0.2",
"jsdom": "^11.0.0",
"json-loader": "^0.5.4",
"karma": "^1.7.0",
Expand Down
27 changes: 4 additions & 23 deletions src/Button/Button.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

import React from 'react';
import { assert } from 'chai';
import htmlLooksLike from 'html-looks-like';
import { createShallow, createRenderToString } from '../test-utils';
import { createShallow, createRender } from '../test-utils';
import Button, { styleSheet } from './Button';

describe('<Button />', () => {
Expand All @@ -13,7 +12,7 @@ describe('<Button />', () => {

before(() => {
shallow = createShallow({ dive: true });
renderToString = createRenderToString();
renderToString = createRender();
classes = shallow.context.styleManager.render(styleSheet);
});

Expand Down Expand Up @@ -189,30 +188,12 @@ describe('<Button />', () => {

it('should server side render', () => {
// Only run the test on node.
if (!/Node.js/.test(window.navigator.userAgent)) {
if (!/jsdom/.test(window.navigator.userAgent)) {
return;
}

const markup = renderToString(<Button>Hello World</Button>);

htmlLooksLike(
markup,
`
<button
tabindex="0"
class="MuiButtonBase-buttonBase-3170508663 MuiButton-root-3593367901"
type="button"
data-reactroot=""
data-reactid="1"
data-react-checksum="-1899863948"
>
<span class="MuiButton-label-49836587" data-reactid="2">
Hello World
</span>
<span class="MuiTouchRipple-root-3868442396" data-reactid="3"></span>
</button>
`,
);
assert.strictEqual(markup.text(), 'Hello World');
});
});
});
3 changes: 2 additions & 1 deletion src/Tabs/Tabs.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import React from 'react';
import { assert } from 'chai';
import { spy, stub } from 'sinon';
import scroll from 'scroll';
import { createShallow, createMount, consoleErrorMock } from '../test-utils';
import { createShallow, createMount } from '../test-utils';
import consoleErrorMock from '../../test/utils/consoleErrorMock';
import Tabs, { styleSheet } from './Tabs';
import TabScrollButton from './TabScrollButton';
import TabIndicator from './TabIndicator';
Expand Down
3 changes: 2 additions & 1 deletion src/internal/Modal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { assert } from 'chai';
import { spy, stub } from 'sinon';
import keycode from 'keycode';
import contains from 'dom-helpers/query/contains';
import { createShallow, createMount, consoleErrorMock } from '../test-utils';
import { createShallow, createMount } from '../test-utils';
import consoleErrorMock from '../../test/utils/consoleErrorMock';
import Backdrop from './Backdrop';
import Modal, { styleSheet } from './Modal';

Expand Down
35 changes: 3 additions & 32 deletions src/styles/MuiThemeProvider.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,19 @@
import { stub } from 'sinon';
import { assert } from 'chai';
import { create } from 'jss';
import path from 'path';
import fs from 'fs';
import jssPreset from 'jss-preset-default';
import { createStyleManager } from 'jss-theme-reactor';
import React from 'react';
import htmlLooksLike from 'html-looks-like';
import { renderToString } from 'react-dom/server';
import { createMount } from '../test-utils';
import { createMuiTheme } from '../styles';
import Button from '../Button';
import MuiThemeProvider from './MuiThemeProvider';

function trim(str) {
return str.replace(/^\s+|\s+$/, '');
}

describe('<MuiThemeProvider />', () => {
describe('server side', () => {
// Only run the test on node.
if (!/Node.js/.test(window.navigator.userAgent)) {
if (!/jsdom/.test(window.navigator.userAgent)) {
return;
}

Expand All @@ -48,30 +41,8 @@ describe('<MuiThemeProvider />', () => {
</MuiThemeProvider>,
);

htmlLooksLike(
markup,
`
<button
tabindex="0"
class="MuiButtonBase-buttonBase-3170508663 MuiButton-root-3593367901"
type="button"
data-reactroot=""
data-reactid="1"
data-react-checksum="-1899863948"
>
<span class="MuiButton-label-49836587" data-reactid="2">
Hello World
</span>
<span class="MuiTouchRipple-root-3868442396" data-reactid="3"></span>
</button>
`,
);

const expected = fs.readFileSync(
path.join(__dirname, 'MuiThemeProvider.spec.output.css'),
'utf-8',
);
assert.strictEqual(styleManager.sheetsToString(), trim(expected));
assert.notStrictEqual(markup.match('Hello World'), null);
assert.strictEqual(styleManager.sheetsToString().length > 4000, true);
});
});

Expand Down
Loading