Skip to content

Commit f1de1f5

Browse files
committed
Setting up unit testing with Jest
1 parent 8986b0b commit f1de1f5

23 files changed

+2248
-39
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
__coverage__
12
dist
23
node_modules

README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,16 @@ only need to call `adopt-dev-deps` again if you update
3939
`topcoder-react-utils` to a newer version.
4040

4141
### <a name="configurations">Configurations</a>
42-
- [**Babel Configurations**](docs/babel-config.md) &mdash; Standard configurations
43-
for [Babel](https://babeljs.io/);
42+
- [**Babel Configurations**](docs/babel-config.md) &mdash; Standard
43+
configurations for [Babel](https://babeljs.io/);
4444
- [**ESLint Configurations**](docs/eslint-config.md) &mdash; Standard
45-
configurations for [ESLint](https://eslint.org/);
45+
configurations for [ESLint](https://eslint.org/);
46+
- [**Jest Configurations**](docs/jest-config.md) &mdash; Standard configurations
47+
for [Jest](https://facebook.github.io/jest/);
4648
- [**Stylelint Configurations**](docs/stylelint-config.md) &mdash; Standard
4749
configurations for [Stylelint](https://stylelint.io)
48-
- [**Webpack Configurations**](docs/webpack-config.md) &mdash; Standard configurations for [Webpack](https://webpack.js.org/).
50+
- [**Webpack Configurations**](docs/webpack-config.md) &mdash; Standard
51+
configurations for [Webpack](https://webpack.js.org/).
4952

5053
### <a name="components">Components</a>
5154
- [**`Avatar`**](docs/avatar.md) &mdash; The standard component for user avatars;
@@ -59,12 +62,13 @@ configurations for [ESLint](https://eslint.org/);
5962
- [**`ScalableRect`**](docs/scalable-rect.md) &mdash; Container that keeps
6063
the specified aspect ratio regardless the width you set.
6164

62-
6365
### <a name="utilities">Utilities</a>
6466
- [**Global Styles**](docs/global-styles.md) &mdash; Global styles necessary for
6567
a generic application;
6668
- [**SCSS Mixins**](docs/scss-mixins.md) &mdash; Collection of useful style
67-
mixins.
69+
mixins;
70+
- [**Jest utils**](docs/jest-utils.md) &mdash; Collection of helpers to be used
71+
in Jest tests code.
6872

6973
### <a name="development">Development</a>
7074
For convenient development you can link this package into your host package:

__tests__/.eslintrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "../config/eslint/jest.json"
3+
}

__tests__/shared/Avatar.jsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import Avatar from 'components/Avatar';
2+
import React from 'react';
3+
import { snapshot } from '../../jest-utils';
4+
5+
const testTheme = {
6+
avatar: 'avatarClassName',
7+
};
8+
9+
function DefaultAvatar() {
10+
return 'DEFAULT_AVATAR';
11+
}
12+
13+
test('Matches snapshots', () => {
14+
snapshot((
15+
<Avatar
16+
DefaultAvatar={DefaultAvatar}
17+
theme={testTheme}
18+
/>
19+
));
20+
snapshot((
21+
<Avatar
22+
DefaultAvatar={DefaultAvatar}
23+
theme={testTheme}
24+
url="url/to/the/avatar"
25+
/>
26+
));
27+
});

__tests__/shared/Button.jsx

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import _ from 'lodash';
2+
import Button from 'components/Button';
3+
import React from 'react';
4+
import { shallowSnapshot } from 'utils/jest';
5+
6+
const testTheme = {
7+
active: 'ACTIVE_CLASS',
8+
button: 'BUTTON_CLASS',
9+
disabled: 'DISABLED_CLASS',
10+
link: 'LINK_CLASS',
11+
regular: 'REGULAR_CLASS',
12+
xl: 'XL_CLASS',
13+
};
14+
15+
describe('Matches snapshots', () => {
16+
test('when active', () => {
17+
shallowSnapshot((
18+
<Button
19+
active
20+
onClick={_.noop}
21+
theme={testTheme}
22+
>BUTTON</Button>
23+
));
24+
shallowSnapshot((
25+
<Button
26+
active
27+
onClick={_.noop}
28+
theme={_.omit(testTheme, 'regular')}
29+
>BUTTON</Button>
30+
));
31+
});
32+
test('when disabled', () => {
33+
shallowSnapshot((
34+
<Button
35+
disabled
36+
onClick={_.noop}
37+
theme={testTheme}
38+
size="xl"
39+
>BUTTON</Button>
40+
));
41+
shallowSnapshot((
42+
<Button
43+
disabled
44+
onClick={_.noop}
45+
theme={_.omit(testTheme, 'disabled')}
46+
size="xl"
47+
>BUTTON</Button>
48+
));
49+
});
50+
test('when rendered as link', () => {
51+
shallowSnapshot((
52+
<Button
53+
active
54+
theme={testTheme}
55+
to="/SOME/TEST/URL"
56+
>BUTTON</Button>
57+
));
58+
shallowSnapshot((
59+
<Button
60+
active
61+
theme={_.omit(testTheme, 'link')}
62+
to="/SOME/TEST/URL"
63+
>BUTTON</Button>
64+
));
65+
});
66+
});
67+

__tests__/shared/GenericLink.jsx

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/* global window */
2+
3+
import GenericLink from 'components/GenericLink';
4+
import PT from 'prop-types';
5+
import React from 'react';
6+
import { findInDomByClass, renderDom, simulate, snapshot } from 'utils/jest';
7+
8+
function Link(props) {
9+
return (
10+
<button
11+
onClick={props.onClick}
12+
className={props.className}
13+
>{JSON.stringify(props)}</button>
14+
);
15+
}
16+
17+
Link.defaultProps = {
18+
className: null,
19+
};
20+
21+
Link.propTypes = {
22+
className: PT.string,
23+
onClick: PT.func.isRequired,
24+
};
25+
26+
describe('Matches snapshots', () => {
27+
test('in a minimalistic example', () => {
28+
snapshot((
29+
<GenericLink
30+
routerLinkType={Link}
31+
to="SOME/TEST/URL"
32+
>LINK</GenericLink>
33+
));
34+
});
35+
test('when rendered as <a> element', () => {
36+
snapshot((
37+
<GenericLink
38+
enforceA
39+
routerLinkType={Link}
40+
to="SOME/TEST/URL"
41+
>LINK</GenericLink>
42+
));
43+
snapshot((
44+
<GenericLink
45+
openNewTab
46+
routerLinkType={Link}
47+
to="SOME/TEST/URL"
48+
>LINK</GenericLink>
49+
));
50+
});
51+
});
52+
53+
test('onClick(..) works when rendered as custom <Link>', () => {
54+
window.scroll = jest.fn();
55+
const clickHandler = jest.fn();
56+
let doc = renderDom((
57+
<GenericLink
58+
className="LINK"
59+
onClick={clickHandler}
60+
routerLinkType={Link}
61+
to="SOME/TEST/URL"
62+
>LINK</GenericLink>
63+
));
64+
let link = findInDomByClass(doc, 'LINK');
65+
simulate.click(link);
66+
expect(clickHandler).toHaveBeenCalled();
67+
68+
doc = renderDom((
69+
<GenericLink
70+
className="LINK"
71+
routerLinkType={Link}
72+
to="https://some.domain.com"
73+
>LINK</GenericLink>
74+
));
75+
link = findInDomByClass(doc, 'LINK');
76+
simulate.click(link);
77+
78+
expect(window.scroll).toHaveBeenCalledTimes(1);
79+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Matches snapshots 1`] = `"DEFAULT_AVATAR"`;
4+
5+
exports[`Matches snapshots 2`] = `
6+
<img
7+
alt="Avatar"
8+
className="avatarClassName"
9+
src="url/to/the/avatar"
10+
/>
11+
`;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Matches snapshots when active 1`] = `
4+
<button
5+
className="BUTTON_CLASS ACTIVE_CLASS REGULAR_CLASS"
6+
onClick={[Function]}
7+
onMouseDown={null}
8+
>
9+
BUTTON
10+
</button>
11+
`;
12+
13+
exports[`Matches snapshots when active 2`] = `
14+
<button
15+
className="BUTTON_CLASS ACTIVE_CLASS"
16+
onClick={[Function]}
17+
onMouseDown={null}
18+
>
19+
BUTTON
20+
</button>
21+
`;
22+
23+
exports[`Matches snapshots when disabled 1`] = `
24+
<div
25+
className="BUTTON_CLASS XL_CLASS DISABLED_CLASS"
26+
>
27+
BUTTON
28+
</div>
29+
`;
30+
31+
exports[`Matches snapshots when disabled 2`] = `
32+
<div
33+
className="BUTTON_CLASS XL_CLASS"
34+
>
35+
BUTTON
36+
</div>
37+
`;
38+
39+
exports[`Matches snapshots when rendered as link 1`] = `
40+
<Link
41+
className="BUTTON_CLASS ACTIVE_CLASS LINK_CLASS"
42+
enforceA={false}
43+
onClick={null}
44+
onMouseDown={null}
45+
openNewTab={false}
46+
replace={false}
47+
to="/SOME/TEST/URL"
48+
>
49+
BUTTON
50+
</Link>
51+
`;
52+
53+
exports[`Matches snapshots when rendered as link 2`] = `
54+
<Link
55+
className="BUTTON_CLASS ACTIVE_CLASS"
56+
enforceA={false}
57+
onClick={null}
58+
onMouseDown={null}
59+
openNewTab={false}
60+
replace={false}
61+
to="/SOME/TEST/URL"
62+
>
63+
BUTTON
64+
</Link>
65+
`;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Matches snapshots in a minimalistic example 1`] = `
4+
<button
5+
className={null}
6+
onClick={[Function]}
7+
>
8+
{"to":"SOME/TEST/URL","className":null,"onMouseDown":null,"replace":false,"children":"LINK"}
9+
</button>
10+
`;
11+
12+
exports[`Matches snapshots when rendered as <a> element 1`] = `
13+
<a
14+
className={null}
15+
href="SOME/TEST/URL"
16+
onClick={null}
17+
onMouseDown={null}
18+
rel="noopener noreferrer"
19+
target=""
20+
>
21+
LINK
22+
</a>
23+
`;
24+
25+
exports[`Matches snapshots when rendered as <a> element 2`] = `
26+
<a
27+
className={null}
28+
href="SOME/TEST/URL"
29+
onClick={null}
30+
onMouseDown={null}
31+
rel="noopener noreferrer"
32+
target="_blank"
33+
>
34+
LINK
35+
</a>
36+
`;

config/eslint/jest.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"extends": "./default.json",
3+
"env": {
4+
"jest": true
5+
},
6+
"plugins": [
7+
"jest"
8+
],
9+
"rules": {
10+
"global-require": 0,
11+
"import/no-dynamic-require": 0
12+
}
13+
}

config/jest/default.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module.exports = {
2+
collectCoverage: true,
3+
collectCoverageFrom: [
4+
'src/**/*.{js,jsx}',
5+
],
6+
coverageDirectory: '__coverage__',
7+
moduleNameMapper: {
8+
'\\.(scss|css)$': 'identity-obj-proxy',
9+
},
10+
rootDir: '../..',
11+
testPathIgnorePatterns: [
12+
'/node_modules/',
13+
],
14+
setupTestFrameworkScriptFile: '<rootDir>/config/jest/setup.js',
15+
};

config/jest/setup.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import 'raf/polyfill';

config/webpack/lib-base.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ module.exports = function configFactory(ops) {
3838
'lodash',
3939
'moment',
4040
'prop-types',
41+
'raf',
4142
'react',
4243
'react-css-super-themr',
4344
'react-dom',

0 commit comments

Comments
 (0)