Skip to content

Commit 49c9775

Browse files
committed
Merge pull request #123 from weblogixx/feat-unittest
Updated Unit-Tests
2 parents 81bc264 + 7f911b5 commit 49c9775

File tree

16 files changed

+138
-94
lines changed

16 files changed

+138
-94
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ ehthumbs.db
1111
Desktop.ini
1212
$RECYCLE.BIN/
1313
node_modules/
14-
/test/*
1514
npm-debug.log
16-
.idea/
15+
.idea/
16+
/test/temp-test

README.md

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -78,27 +78,34 @@ var Foo = React.createClass({
7878
module.exports = Foo;
7979
```
8080

81-
And `test/spec/components/Foo.js` (*javascript - jasmine*):
81+
And `test/spec/components/Foo.js` (*javascript - jasmine, as seen on http://simonsmith.io/unit-testing-react-components-without-a-dom/*):
8282
```js
8383
'use strict';
8484

85-
describe('Foo', function () {
86-
var Foo, component;
85+
// Uncomment the following lines to use the react test utilities
86+
// import React from 'react/addons';
87+
// const TestUtils = React.addons.TestUtils;
8788

88-
beforeEach(function () {
89-
Foo = require('../../../src/components/Foo');
90-
component = Foo();
91-
});
89+
import createComponent from 'helpers/createComponent';
90+
import Foo from 'components/Foo.js';
9291

93-
it('should create a new instance of Foo', function () {
94-
expect(component).toBeDefined();
95-
});
92+
describe('Foo', () => {
93+
94+
let FooComponent;
95+
96+
beforeEach(() => {
97+
FooComponent = createComponent(Foo);
98+
});
99+
100+
it('should have its component name as default className', () => {
101+
expect(FooComponent._store.props.className).toBe('Foo');
102+
});
96103
});
97104
```
98105

99106
And `src/styles/Foo.css` (or .sass, .less etc...) :
100107
```css
101-
.Foo{
108+
.Foo {
102109
border: 1px dashed #f00;
103110
}
104111
```
@@ -117,7 +124,9 @@ This will give you all of react component's most common stuff :
117124

118125
var Foofoo = React.createClass({
119126
mixins: [],
120-
getInitialState: function() { return({}) },
127+
getInitialState: function() {
128+
return {};
129+
},
121130
getDefaultProps: function() {},
122131
componentWillMount: function() {},
123132
componentDidMount: function() {},
@@ -139,9 +148,6 @@ This will give you all of react component's most common stuff :
139148

140149
Just remove those you don't need, then fill and space out the rest.
141150

142-
143-
144-
145151
### Action
146152

147153
When using Flux or Reflux architecture, it generates an actionCreator in `src/actions` and it's corresponding test in `src/spec/actions`.
@@ -180,14 +186,14 @@ and same test for both architectures:
180186
```js
181187
'use strict';
182188

183-
describe('BarActionCreators', function() {
184-
var action;
189+
describe('BarActionCreators', () => {
190+
let action;
185191

186192
beforeEach(function() {
187193
action = require('actions/BarActionCreators.js');
188194
});
189195

190-
it('should be defined', function() {
196+
it('should be defined', () => {
191197
expect(action).toBeDefined();
192198
});
193199
});
@@ -246,14 +252,14 @@ and same test for both architectures:
246252
```js
247253
'use strict';
248254

249-
describe('BazStore', function() {
250-
var store;
255+
describe('BazStore', () => {
256+
let store;
251257

252-
beforeEach(function() {
258+
beforeEach(() => {
253259
store = require('stores/BazStore.js');
254260
});
255261

256-
it('should be defined', function() {
262+
it('should be defined', () => {
257263
expect(store).toBeDefined();
258264
});
259265
});
@@ -364,15 +370,19 @@ Out the box the [Gruntfile](http://gruntjs.com/api/grunt.file) is configured wit
364370
1. **webpack**: uses the [grunt-webpack](https://github.com/webpack/grunt-webpack) plugin to load all required modules and output to a single JS file `src/main.js`. This is included in the `src/index.html` file by default and will reload in the browser as and when it is recompiled.
365371
2. **webpack-dev-server**: uses the [webpack-dev-server](https://github.com/webpack/webpack-dev-server) to watch for file changes and also serve the webpack app in development.
366372
3. **connect**: uses the [grunt-connect](https://github.com/gruntjs/grunt-contrib-connect) plugin to start a webserver at [localhost](http://localhost:8000).
367-
4. **karma**: uses the [grunt-karma](https://github.com/karma-runner/grunt-karma) plugin to load the Karma configuration file `karma.conf.js` located in the project root. This will run all tests using [PhantomJS](http://phantomjs.org/) by default but supports many other browsers.
373+
4. **karma**: uses the [grunt-karma](https://github.com/karma-runner/grunt-karma) plugin to load the Karma configuration file `karma.conf.js` located in the project root. This will run all tests using [PhantomJS](http://phantomjs.org/) by default but supports many other browsers. Please note that karma-launchers other than PhantomJS must be installed separately and configured in `karma.conf.js`.
368374

369375
### CSS
370376

371377
Included in the project is the [normalize.css](http://necolas.github.io/normalize.css/) script. There is also a `src/styles/main.css` script that's required by the core `src/components/App.js` component using Webpack.
372378

373-
### JSHint
379+
### Linting
380+
381+
Webpack is automatically configured to run esLint (http://eslint.org) on every file change or build. The configuration can be found in `PROJECTROOT/.eslintrc`. There are plugins for different editors that use this tool directly:
382+
- linter-eslint for Atom
383+
- Sublime-Linter-eslint for Sublime
374384

375-
Please use [JSXHint](https://github.com/STRML/JSXHint) for linting JSX and the corresponding Sublime package if using SLT3 [SublimeLinter-jsxhint](https://github.com/SublimeLinter/SublimeLinter-jsxhint). Note this is a global npm install and JSX files will need to be associated with the JSX file type withing SLT3.
385+
You could also use jsxhint, the corresponding rules file is located in `PROJECTROOT/.jshintrc`. However, the support for jsxhint is planned to be dropped in a later release and only available for backwards compatibility.
376386

377387
## Props
378388

templates/common/_package.json

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,34 +20,33 @@
2020
"normalize.css": "~3.0.3"
2121
},
2222
"devDependencies": {
23+
"babel": "^5.0.0",
24+
"babel-loader": "^5.0.0",
2325
"grunt": "~0.4.5",
2426
"eslint": "^0.21.2",
2527
"eslint-loader": "^0.11.2",
2628
"eslint-plugin-react": "^2.4.0",
2729
"load-grunt-tasks": "~0.6.0",
2830
"grunt-contrib-connect": "~0.8.0",
29-
"webpack": "~1.4.3",
3031
"grunt-webpack": "~1.0.8",
32+
"jasmine-core": "^2.3.4",
33+
"karma": "~0.12.21",
34+
"karma-jasmine": "^0.3.5",
35+
"karma-phantomjs-launcher": "~0.1.3",
36+
"karma-script-launcher": "~0.1.0",
37+
"karma-webpack": "^1.5.0",
3138
"style-loader": "~0.8.0",
3239
"url-loader": "~0.5.5",
3340
"css-loader": "~0.9.0",
34-
"karma-script-launcher": "~0.1.0",
35-
"karma-chrome-launcher": "~0.1.4",
36-
"karma-firefox-launcher": "~0.1.3",
37-
"karma-jasmine": "~0.1.5",
38-
"karma-phantomjs-launcher": "~0.1.3",
39-
"karma": "~0.12.21",
4041
"grunt-karma": "~0.8.3",
41-
"karma-webpack": "~1.2.2",
42-
"webpack-dev-server": "~1.6.5",
4342
"grunt-open": "~0.2.3",
4443
"grunt-contrib-copy": "~0.5.0",
45-
"babel": "^4.0.0",
46-
"babel-loader": "^4.0.0",
4744
"grunt-contrib-clean": "~0.6.0",<% if (stylesLanguage.match(/s[ac]ss/)) { %>
4845
"sass-loader": "^1.0.1",<% } %><% if (stylesLanguage === 'less') { %>
4946
"less-loader": "^2.0.0",<% } %><% if (stylesLanguage === 'stylus') { %>
5047
"stylus-loader": "^0.5.0",<% } %>
51-
"react-hot-loader": "^1.0.7"
48+
"react-hot-loader": "^1.0.7",
49+
"webpack": "~1.10.0",
50+
"webpack-dev-server": "~1.10.0"
5251
}
5352
}

templates/common/_webpack.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module.exports = {
1616

1717
cache: true,
1818
debug: true,
19-
devtool: false,
19+
devtool: 'sourcemap',
2020
entry: [
2121
'webpack/hot/only-dev-server',
2222
'./src/components/<% if (reactRouter) { %>main<% } else { %><%= scriptAppName %><% } %>.js'

templates/common/karma.conf.js

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ module.exports = function (config) {
77
basePath: '',
88
frameworks: ['jasmine'],
99
files: [
10-
'test/helpers/**/*.js',
10+
'test/helpers/pack/**/*.js',
11+
'test/helpers/react/**/*.js',
1112
'test/spec/components/**/*.js'<% if(architecture === 'flux'||architecture === 'reflux') { %>,
1213
'test/spec/stores/**/*.js',
1314
'test/spec/actions/**/*.js'<% } %>
1415
],
1516
preprocessors: {
17+
'test/helpers/createComponent.js': ['webpack'],
1618
'test/spec/components/**/*.js': ['webpack'],
1719
'test/spec/components/**/*.jsx': ['webpack']<% if(architecture === 'flux'||architecture === 'reflux') { %>,
1820
'test/spec/stores/**/*.js': ['webpack'],
@@ -32,7 +34,8 @@ module.exports = function (config) {
3234
loader: 'url-loader?limit=10000&mimetype=image/png'
3335
}, {
3436
test: /\.(js|jsx)$/,
35-
loader: 'babel-loader'
37+
loader: 'babel-loader',
38+
exclude: /node_modules/
3639
},<% if (stylesLanguage === 'sass') { %> {
3740
test: /\.sass/,
3841
loader: 'style-loader!css-loader!sass-loader?outputStyle=expanded'
@@ -61,11 +64,13 @@ module.exports = function (config) {
6164
'styles': path.join(process.cwd(), './src/styles/'),
6265
'components': path.join(process.cwd(), './src/components/')<% if(architecture === 'flux'||architecture === 'reflux') { %>,
6366
'stores': '../../../src/stores/',
64-
'actions': '../../../src/actions/'<% } %>
67+
'actions': '../../../src/actions/'<% } %>,
68+
'helpers': path.join(process.cwd(), './test/helpers/')
6569
}
6670
}
6771
},
68-
webpackServer: {
72+
webpackMiddleware: {
73+
noInfo: true,
6974
stats: {
7075
colors: true
7176
}
@@ -75,17 +80,14 @@ module.exports = function (config) {
7580
logLevel: config.LOG_INFO,
7681
colors: true,
7782
autoWatch: false,
78-
// Start these browsers, currently available:
79-
// - Chrome
80-
// - ChromeCanary
81-
// - Firefox
82-
// - Opera
83-
// - Safari (only Mac)
84-
// - PhantomJS
85-
// - IE (only Windows)
8683
browsers: ['PhantomJS'],
87-
reporters: ['progress'],
84+
reporters: ['dots'],
8885
captureTimeout: 60000,
89-
singleRun: true
86+
singleRun: true,
87+
plugins: [
88+
require('karma-webpack'),
89+
require('karma-jasmine'),
90+
require('karma-phantomjs-launcher')
91+
]
9092
});
9193
};

templates/common/root/.eslintrc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"react"
44
],
55
"ecmaFeatures": {
6-
"jsx": true
6+
"jsx": true,
7+
"modules": true
78
},
89
"env": {
910
"browser": true,
@@ -14,6 +15,7 @@
1415
"quotes": [ 1, "single" ],
1516
"no-undef": false,
1617
"global-strict": false,
17-
"no-extra-semi": 1
18+
"no-extra-semi": 1,
19+
"no-underscore-dangle": false
1820
}
1921
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Function to get the shallow output for a given component
3+
* As we are using phantom.js, we also need to include the fn.proto.bind shim!
4+
*
5+
* @see http://simonsmith.io/unit-testing-react-components-without-a-dom/
6+
* @author somonsmith
7+
*/
8+
9+
// Add missing methods to phantom.js
10+
import './pack/phantomjs-shims';
11+
12+
import React from 'react/addons';
13+
const TestUtils = React.addons.TestUtils;
14+
15+
/**
16+
* Get the shallow rendered component
17+
*
18+
* @param {Object} component The component to return the output for
19+
* @param {Object} props [optional] The components properties
20+
* @param {Mixed} ...children [optional] List of children
21+
* @return {Object} Shallow rendered output
22+
*/
23+
export default function createComponent(component, props = {}, ...children) {
24+
const shallowRenderer = TestUtils.createRenderer();
25+
shallowRenderer.render(React.createElement(component, props, children.length > 1 ? children : children[0]));
26+
return shallowRenderer.getRenderOutput();
27+
}

templates/javascript/App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var imageURL = require('../images/yeoman.png');
1212
var <%= scriptAppName %> = React.createClass({
1313
render: function() {
1414
return (
15-
<div className='main'>
15+
<div className="main">
1616
<ReactTransitionGroup transitionName="fade">
1717
<img src={imageURL} />
1818
</ReactTransitionGroup>

templates/javascript/Component.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ if (stylesLanguage === 'stylus') { %>require('styles/<%= classedFileName %>.styl
1313

1414
var <%= classedName %> = React.createClass({<% if(rich){%>
1515
mixins: [<% if(architecture === 'reflux'){%>Reflux.ListenerMixin<%}%>],
16-
getInitialState: function() { return({}) },
16+
getInitialState: function() {
17+
return {};
18+
},
1719
getDefaultProps: function() {},
1820
componentWillMount: function() {},
1921
componentDidMount: function() {},
@@ -32,4 +34,3 @@ var <%= classedName %> = React.createClass({<% if(rich){%>
3234

3335
<% if (es6) { %>export default <%= classedName %>;<% }
3436
else { %>module.exports = <%= classedName %>;<% } %>
35-

0 commit comments

Comments
 (0)