Skip to content

Commit 4cad43e

Browse files
committed
test(*): add unit-tests
1 parent 2d1af74 commit 4cad43e

File tree

9 files changed

+262
-24
lines changed

9 files changed

+262
-24
lines changed

README.md

+9-6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ This project started as a POC for **React** and has now become my own sandbox fo
1919
* [Eslint](http://eslint.org/) (with [eslint-config-airbnb](https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb))
2020
* [style-loader](https://github.com/webpack/style-loader), [sass-loader](https://github.com/jtangelder/sass-loader)
2121
* [babel-preset-react-hmre](https://github.com/danmartinez101/babel-preset-react-hmre) (react-hot-reload for babel v6 - thanks to [react-transform-hmr](https://github.com/gaearon/react-transform-hmr))
22-
* [Karma](https://karma-runner.github.io) Test runner
22+
* [Karma](https://karma-runner.github.io) Test runner / [PhantomJS](http://phantomjs.org/) Scripted, headless browser
2323
* [Mocha](https://mochajs.org/) / [Chai](http://chaijs.com/) / [Sinon](http://sinonjs.org/) Test framework / Assertion Library / Test spies
2424
* [Enzyme](http://airbnb.io/enzyme/) Testing utilities for React from Airbnb
2525
* [babel-plugin-\_\_coverage\_\_](https://github.com/dtinth/babel-plugin-__coverage__) used with [karma-coverage](https://github.com/karma-runner/karma-coverage), spits out coverage reports **directly on es6 source code**
@@ -29,8 +29,8 @@ This project started as a POC for **React** and has now become my own sandbox fo
2929

3030
The **development / build / deploy workflow** is based on [topheman/webpack-babel-starter](https://github.com/topheman/webpack-babel-starter), which allows to have online both:
3131

32-
* production version (minified js/css ...)
33-
* development version (with sourcemaps, so that users could see the original es6 source code, even online, just by opening the sources panel in the devtools console)
32+
* [production version](https://topheman.github.io/react-es6-redux/) (minified js/css ...)
33+
* [development version](https://topheman.github.io/react-es6-redux/devtools/) (with sourcemaps, so that users could see the original es6 source code, even online, just by opening the sources panel in the devtools console)
3434

3535
**Support for [Travis CI](https://travis-ci.org/topheman/react-es6-redux)** (see [.travis.yml](https://github.com/topheman/react-es6-redux/blob/master/.travis.yml) file):
3636

@@ -53,6 +53,7 @@ To **read further** about this project and its evolution:
5353
* [Blog post about the original version](http://dev.topheman.com/playing-with-es6-and-react/)
5454
* [Slides of the ReactJsParis meetup about this project (nov 2015)](http://slides.com/topheman/react-es6-redux)
5555
* [Slides of the ParisJS meetup about this project (jan 2016)](https://topheman.github.io/talks/react-es6-redux/)
56+
* [Blog post about ES6+ code coverage with Babel plugin](http://dev.topheman.com/es6-code-coverage-with-babel-plugin)
5657

5758
**[ONLINE DEMO](https://topheman.github.io/react-es6-redux/)**
5859

@@ -109,14 +110,16 @@ You can run it with `npm run serve-build`
109110
* the unit-tests files are located in `/src` inside `__tests__` folders, named like `*.spec.js`
110111
* those tests files are run by karma
111112

112-
This task is launched on `pre-commit` hook & on Travis CI.
113+
This task is launched on `pre-commit` hook & on [Travis CI](https://travis-ci.org/topheman/react-es6-redux).
113114

114115
If you wish to generate coverage reports, just `npm run karma-coverage` (those reports are generated on Travis CI anyway and available on [coveralls.io](https://coveralls.io/github/topheman/react-es6-redux)), you will find them in local at `/build/reports/coverage`.
115116

116-
*Unit tests are still in progress, I assume some parts will be missing - like polyfills for PhantomJS - I'll finish that in a few days.*
117+
*Note:* Unit-tests are run through karma in PhantomJS (the `webpack.config.js` being injected), they can also be run directly via mocha ([see wiki](https://github.com/topheman/react-es6-redux/wiki/Advanced-tasks#test-tasks)).
117118

118119
#####End to end tests
119120

121+
e2e tests are located in `/test/e2e/spec`.
122+
120123
Open two terminal tabs, on each one:
121124

122125
* `npm run webpack-mock`: will launch the project in mock mode
@@ -168,7 +171,7 @@ My deployment routine is described on the [topheman/webpack-babel-starter Wiki](
168171

169172
This software is distributed under an MIT licence.
170173

171-
Copyright 2015 © Christophe Rosset
174+
Copyright 2015-2016 © Christophe Rosset
172175

173176
> Permission is hereby granted, free of charge, to any person obtaining a copy of this software
174177
> and associated documentation files (the "Software"), to deal in the Software without

src/components/ProfileList/__tests__/ProfileList.spec.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,25 @@ import ProfileBox from '../../ProfileBox/ProfileBox';
99
describe('components/ProfileList', () => {
1010
describe('state/render', () => {
1111
describe('case props.results not hydrated with data', () => {
12-
it('should render default message if props.results=null', () => {
12+
it('should render default message if props.results = null', () => {
1313
const wrapper = shallow(<ProfileList results={null} />);
1414
expect(wrapper.type()).to.be.equal('p');
1515
});
1616
it('should render the error if props.results.error is set', () => {
1717
const wrapper = shallow(<ProfileList results={{error: 'Something went wrong'}} />);
1818
expect(wrapper.equals(<div>Something went wrong</div>)).to.be.true;
1919
});
20-
it('should show "No results" if props.results.total_count=0', () => {
20+
it('should show "No results" if props.results.total_count = 0', () => {
2121
const wrapper = shallow(<ProfileList results={{total_count: 0}} />);
2222
expect(wrapper.equals(<div>No results.</div>)).to.be.true;
2323
});
2424
});
2525
describe('case props.results hydrated with data', () => {
26-
it('header should show "Total result" in case props.results.total_count=1', () => {
26+
it('header should show "Total result" in case props.results.total_count = 1', () => {
2727
const wrapper = shallow(<ProfileList results={{total_count: 1, items: [{$avatar_url: 'someurl', id: 42, login: 'foo'}] }} />);
2828
expect(wrapper.find('.panel-heading').text()).to.equal('Total result : 1 / showing : 1');
2929
});
30-
it('header should show "Total results" in case props.results.total_count>1', () => {
30+
it('header should show "Total results" in case props.results.total_count > 1', () => {
3131
const wrapper = shallow(<ProfileList results={{total_count: 2, items: [{$avatar_url: 'someurl', id: 42, login: 'foo'}, {$avatar_url: 'someurl', id: 43, login: 'bar'}] }} />);
3232
expect(wrapper.find('.panel-heading').text()).to.equal('Total results : 2 / showing : 2');
3333
});

src/components/Repos/__tests__/Repos.spec.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ describe('components/ProfileBox', () => {
3232
expect(wrapper.find('a').length).to.equal(3);
3333
});
3434
it('should render links properly', () => {
35-
const anchor = wrapper.find('a').get(1);
36-
expect(anchor.props.href).to.equal('https://github.com/topheman/webpack-babel-starter');
37-
expect(anchor.props.title).to.equal('topheman/webpack-babel-starter');
35+
const anchor = wrapper.find('a').at(1);
36+
expect(anchor.prop('href')).to.equal('https://github.com/topheman/webpack-babel-starter');
37+
expect(anchor.prop('title')).to.equal('topheman/webpack-babel-starter');
3838
});
3939
it('should render stargazer properly', () => {
40-
const displayStars = wrapper.find(DisplayStars).get(1);
41-
expect(displayStars.props.number).to.equal(39);
40+
const displayStars = wrapper.find(DisplayStars).at(1);
41+
expect(displayStars.prop('number')).to.equal(39);
4242
});
4343
});
4444
describe('check paginators', () => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/* eslint-disable no-unused-expressions, react/prop-types */
2+
import { expect } from 'chai';
3+
4+
import React from 'react';
5+
import { shallow } from 'enzyme';
6+
import ReposPaginator from '../ReposPaginator';
7+
8+
function noop() {}
9+
const syntheticEventData = {
10+
preventDefault: function preventDefault() {}
11+
};
12+
13+
describe('components/ReposPaginator', () => {
14+
describe('state/render', () => {
15+
it('should render empty p if props.infos.totalPages < 1', () => {
16+
const wrapper = shallow(<ReposPaginator infos={{}} reposGotoPage={noop} fetching={false} />);
17+
expect(wrapper.equals(<p></p>)).to.be.true;
18+
});
19+
it('should render link to first page if props.infos.page > 1', () => {
20+
const wrapper = shallow(<ReposPaginator infos={{totalPages: 10, page: 2}} reposGotoPage={noop} fetching={false} />);
21+
const li = wrapper.find('li').first();
22+
expect(li.prop('className')).to.be.equal('previous');
23+
expect(li.find('a').prop('title')).to.be.equal('First page');
24+
});
25+
it('should render link to previous page if props.infos.page > 2', () => {
26+
const wrapper = shallow(<ReposPaginator infos={{totalPages: 10, page: 3}} reposGotoPage={noop} fetching={false} />);
27+
const li = wrapper.find('li').at(1);
28+
expect(li.prop('className')).to.be.equal('previous');
29+
expect(li.find('a').prop('title')).to.be.equal('Previous page');
30+
});
31+
it('should render link to next page if props.infos.page<props.infos.totalPages - 1', () => {
32+
const wrapper = shallow(<ReposPaginator infos={{totalPages: 10, page: 7}} reposGotoPage={noop} fetching={false} />);
33+
const li = wrapper.find('li').at(3);
34+
expect(li.prop('className')).to.be.equal('next');
35+
expect(li.find('a').prop('title')).to.be.equal('Next page');
36+
});
37+
it('should render link to last page if props.infos.page<=props.infos.totalPages - 1', () => {
38+
const wrapper = shallow(<ReposPaginator infos={{totalPages: 10, page: 7}} reposGotoPage={noop} fetching={false} />);
39+
const li = wrapper.find('li').at(2);
40+
expect(li.prop('className')).to.be.equal('next');
41+
expect(li.find('a').prop('title')).to.be.equal('Last page');
42+
});
43+
});
44+
describe('state/behaviour', () => {
45+
it('click on "first page" should call props.reposGotoPage(1)', () => {
46+
const spy = sinon.spy();
47+
const wrapper = shallow(<ReposPaginator infos={{totalPages: 10, page: 5}} reposGotoPage={spy} fetching={false} />);
48+
const first = wrapper.find('li').at(0).find('a');
49+
first.simulate('click', syntheticEventData);
50+
expect(spy.calledOnce).to.be.true;
51+
expect(spy.calledWith(1)).to.be.true;
52+
});
53+
it('click on "previous page" should call props.reposGotoPage(props.infos.page - 1)', () => {
54+
const spy = sinon.spy();
55+
const wrapper = shallow(<ReposPaginator infos={{totalPages: 10, page: 5}} reposGotoPage={spy} fetching={false} />);
56+
const first = wrapper.find('li').at(1).find('a');
57+
first.simulate('click', syntheticEventData);
58+
expect(spy.calledOnce).to.be.true;
59+
expect(spy.calledWith(4)).to.be.true;
60+
});
61+
it('click on "next page" should call props.reposGotoPage(props.infos.page + 1)', () => {
62+
const spy = sinon.spy();
63+
const wrapper = shallow(<ReposPaginator infos={{totalPages: 10, page: 5}} reposGotoPage={spy} fetching={false} />);
64+
const first = wrapper.find('li').at(3).find('a');
65+
first.simulate('click', syntheticEventData);
66+
expect(spy.calledOnce).to.be.true;
67+
expect(spy.calledWith(6)).to.be.true;
68+
});
69+
it('click on "last page" should call props.reposGotoPage(props.infos.totalPages)', () => {
70+
const spy = sinon.spy();
71+
const wrapper = shallow(<ReposPaginator infos={{totalPages: 10, page: 5}} reposGotoPage={spy} fetching={false} />);
72+
const first = wrapper.find('li').at(2).find('a');
73+
first.simulate('click', syntheticEventData);
74+
expect(spy.calledOnce).to.be.true;
75+
expect(spy.calledWith(10)).to.be.true;
76+
});
77+
});
78+
});

src/components/common/__tests__/DisplayInfosPanel.spec.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ import Panel from '../Panel';
99

1010
describe('components/common/DisplayInfosPanel', () => {
1111
describe('state/render', () => {
12-
it('should render a spinner at fetching=true when props.infos.fetching=true', () => {
12+
it('should render a spinner at fetching=true when props.infos.fetching = true', () => {
1313
const wrapper = shallow(<DisplayInfosPanel infos={{fetching: true}} originalTitle={""} />);
1414
expect(wrapper.find(Spinner).props().fetching).to.be.true;
1515
});
16-
it('should render a spinner at fetching=false when props.infos.fetching=false', () => {
16+
it('should render a spinner at fetching=false when props.infos.fetching = false', () => {
1717
const wrapper = shallow(<DisplayInfosPanel infos={{fetching: false}} originalTitle={""} />);
1818
expect(wrapper.find(Spinner).props().fetching).to.be.false;
1919
});
20-
it('should render a panel with a title=props.originalTitle when props.infos.fetching=true', () => {
20+
it('should render a panel with a title=props.originalTitle when props.infos.fetching = true', () => {
2121
const wrapper = shallow(<DisplayInfosPanel infos={{fetching: true}} originalTitle={"Hello World"} />);
2222
expect(wrapper.find(Panel).props().title).to.equal('Hello World');
2323
});

src/components/common/__tests__/DisplayStars.spec.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import DisplayStars from '../DisplayStars';
77

88
describe('components/common/DisplayStars', () => {
99
describe('state/render', () => {
10-
it('should render the number passed via props.number if >0', () => {
10+
it('should render the number passed via props.number if > 0', () => {
1111
const wrapper = shallow(<DisplayStars number={2} />);
1212
expect(wrapper.find('span').first().text()).to.equal('2 ');
1313
});
14-
it('should render nothing if props.number=0', () => {
14+
it('should render nothing if props.number = 0', () => {
1515
const wrapper = shallow(<DisplayStars number={0} />);
1616
expect(wrapper.equals(<noscript/>)).to.be.true;
1717
});

src/components/common/__tests__/Spinner.spec.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import Spinner from '../Spinner';
77

88
describe('components/common/Spinner', () => {
99
describe('state/render', () => {
10-
it('should render empty div when props.fetching!==true', () => {
10+
it('should render empty div when props.fetching !== true', () => {
1111
const wrapper = shallow(<Spinner />);
1212
expect(wrapper.find('.bounce1').length).to.equal(0);
1313
});
14-
it('should render nested divs when props.fetching=true', () => {
14+
it('should render nested divs when props.fetching = true', () => {
1515
const wrapper = shallow(<Spinner fetching />);
1616
expect(wrapper.find('.bounce1').length).to.equal(1);
1717
expect(wrapper.find('.bounce2').length).to.equal(1);

src/components/common/__tests__/Tr.spec.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ describe('components/common/Tr', () => {
1313
expect(wrapper.contains(<td>Hello</td>)).to.be.true;
1414
expect(wrapper.contains(<td>World</td>)).to.be.true;
1515
});
16-
it('should render in 1 column if props.display=colspan', () => {
16+
it('should render in 1 column if props.display = colspan', () => {
1717
const wrapper = shallow(<Tr value="Hello World" display="colspan" />);
1818
expect(wrapper.find('td').length).to.equal(1);
1919
expect(wrapper.contains(<td colSpan="2">Hello World</td>)).to.be.true;
2020
});
21-
it('should render value as a link if props.type=link', () => {
21+
it('should render value as a link if props.type = link', () => {
2222
const wrapper = shallow(<Tr value="http://labs.topheman.com" label="Website" type="link" />);
2323
expect(wrapper.contains(<a href="http://labs.topheman.com">http://labs.topheman.com</a>)).to.be.true;
2424
});

0 commit comments

Comments
 (0)