*FEATURE*: Unittests: Added support for React ShallowRendering as described in http://simonsmith.io/unit-testing-react-components-without-a-dom/.

This commit is contained in:
Chris
2015-07-01 08:50:32 +02:00
parent 62dda60bad
commit b0b0f3f84d
16 changed files with 129 additions and 85 deletions
+11 -12
View File
@@ -20,34 +20,33 @@
"normalize.css": "~3.0.3"
},
"devDependencies": {
"babel": "^5.0.0",
"babel-loader": "^5.0.0",
"grunt": "~0.4.5",
"eslint": "^0.21.2",
"eslint-loader": "^0.11.2",
"eslint-plugin-react": "^2.4.0",
"load-grunt-tasks": "~0.6.0",
"grunt-contrib-connect": "~0.8.0",
"webpack": "~1.4.3",
"grunt-webpack": "~1.0.8",
"jasmine-core": "^2.3.4",
"karma": "~0.12.21",
"karma-jasmine": "^0.3.5",
"karma-phantomjs-launcher": "~0.1.3",
"karma-script-launcher": "~0.1.0",
"karma-webpack": "^1.5.0",
"style-loader": "~0.8.0",
"url-loader": "~0.5.5",
"css-loader": "~0.9.0",
"karma-script-launcher": "~0.1.0",
"karma-chrome-launcher": "~0.1.4",
"karma-firefox-launcher": "~0.1.3",
"karma-jasmine": "~0.1.5",
"karma-phantomjs-launcher": "~0.1.3",
"karma": "~0.12.21",
"grunt-karma": "~0.8.3",
"karma-webpack": "~1.2.2",
"webpack-dev-server": "~1.6.5",
"grunt-open": "~0.2.3",
"grunt-contrib-copy": "~0.5.0",
"babel": "^4.0.0",
"babel-loader": "^4.0.0",
"grunt-contrib-clean": "~0.6.0",<% if (stylesLanguage.match(/s[ac]ss/)) { %>
"sass-loader": "^1.0.1",<% } %><% if (stylesLanguage === 'less') { %>
"less-loader": "^2.0.0",<% } %><% if (stylesLanguage === 'stylus') { %>
"stylus-loader": "^0.5.0",<% } %>
"react-hot-loader": "^1.0.7"
"react-hot-loader": "^1.0.7",
"webpack": "~1.10.0",
"webpack-dev-server": "~1.10.0"
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ module.exports = {
cache: true,
debug: true,
devtool: false,
devtool: 'sourcemap',
entry: [
'webpack/hot/only-dev-server',
'./src/components/<% if (reactRouter) { %>main<% } else { %><%= scriptAppName %><% } %>.js'
+16 -14
View File
@@ -7,12 +7,14 @@ module.exports = function (config) {
basePath: '',
frameworks: ['jasmine'],
files: [
'test/helpers/**/*.js',
'test/helpers/pack/**/*.js',
'test/helpers/react/**/*.js',
'test/spec/components/**/*.js'<% if(architecture === 'flux'||architecture === 'reflux') { %>,
'test/spec/stores/**/*.js',
'test/spec/actions/**/*.js'<% } %>
],
preprocessors: {
'test/helpers/createComponent.js': ['webpack'],
'test/spec/components/**/*.js': ['webpack'],
'test/spec/components/**/*.jsx': ['webpack']<% if(architecture === 'flux'||architecture === 'reflux') { %>,
'test/spec/stores/**/*.js': ['webpack'],
@@ -32,7 +34,8 @@ module.exports = function (config) {
loader: 'url-loader?limit=10000&mimetype=image/png'
}, {
test: /\.(js|jsx)$/,
loader: 'babel-loader'
loader: 'babel-loader',
exclude: /node_modules/
},<% if (stylesLanguage === 'sass') { %> {
test: /\.sass/,
loader: 'style-loader!css-loader!sass-loader?outputStyle=expanded'
@@ -61,11 +64,13 @@ module.exports = function (config) {
'styles': path.join(process.cwd(), './src/styles/'),
'components': path.join(process.cwd(), './src/components/')<% if(architecture === 'flux'||architecture === 'reflux') { %>,
'stores': '../../../src/stores/',
'actions': '../../../src/actions/'<% } %>
'actions': '../../../src/actions/'<% } %>,
'helpers': path.join(process.cwd(), './test/helpers/')
}
}
},
webpackServer: {
webpackMiddleware: {
noInfo: true,
stats: {
colors: true
}
@@ -75,17 +80,14 @@ module.exports = function (config) {
logLevel: config.LOG_INFO,
colors: true,
autoWatch: false,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: ['PhantomJS'],
reporters: ['progress'],
reporters: ['dots'],
captureTimeout: 60000,
singleRun: true
singleRun: true,
plugins: [
require('karma-webpack'),
require('karma-jasmine'),
require('karma-phantomjs-launcher')
]
});
};
+4 -2
View File
@@ -3,7 +3,8 @@
"react"
],
"ecmaFeatures": {
"jsx": true
"jsx": true,
"modules": true
},
"env": {
"browser": true,
@@ -14,6 +15,7 @@
"quotes": [ 1, "single" ],
"no-undef": false,
"global-strict": false,
"no-extra-semi": 1
"no-extra-semi": 1,
"no-underscore-dangle": false
}
}
@@ -0,0 +1,27 @@
/**
* Function to get the shallow output for a given component
* As we are using phantom.js, we also need to include the fn.proto.bind shim!
*
* @see http://simonsmith.io/unit-testing-react-components-without-a-dom/
* @author somonsmith
*/
// Add missing methods to phantom.js
import './pack/phantomjs-shims';
import React from 'react/addons';
const TestUtils = React.addons.TestUtils;
/**
* Get the shallow rendered component
*
* @param {Object} component The component to return the output for
* @param {Object} props [optional] The components properties
* @param {Mixed} ...children [optional] List of children
* @return {Object} Shallow rendered output
*/
export default function createComponent(component, props = {}, ...children) {
const shallowRenderer = TestUtils.createRenderer();
shallowRenderer.render(React.createElement(component, props, children.length > 1 ? children : children[0]));
return shallowRenderer.getRenderOutput();
}
+1 -1
View File
@@ -12,7 +12,7 @@ var imageURL = require('../images/yeoman.png');
var <%= scriptAppName %> = React.createClass({
render: function() {
return (
<div className='main'>
<div className="main">
<ReactTransitionGroup transitionName="fade">
<img src={imageURL} />
</ReactTransitionGroup>
+3 -2
View File
@@ -13,7 +13,9 @@ if (stylesLanguage === 'stylus') { %>require('styles/<%= classedFileName %>.styl
var <%= classedName %> = React.createClass({<% if(rich){%>
mixins: [<% if(architecture === 'reflux'){%>Reflux.ListenerMixin<%}%>],
getInitialState: function() { return({}) },
getInitialState: function() {
return {};
},
getDefaultProps: function() {},
componentWillMount: function() {},
componentDidMount: function() {},
@@ -32,4 +34,3 @@ var <%= classedName %> = React.createClass({<% if(rich){%>
<% if (es6) { %>export default <%= classedName %>;<% }
else { %>module.exports = <%= classedName %>;<% } %>
+4 -4
View File
@@ -1,13 +1,13 @@
'use strict';
describe('<%= classedName %>', function() {
var action;
describe('<%= classedName %>', () => {
let action;
beforeEach(function() {
beforeEach(() => {
action = require('actions/<%= classedFileName %>.js');
});
it('should be defined', function() {
it('should be defined', () => {
expect(action).toBeDefined();
});
});
+6 -6
View File
@@ -1,11 +1,11 @@
'use strict';
describe('<%= classedName %>', function () {
var React = require('react/addons');
var <%= scriptAppName %>, component;
describe('<%= classedName %>', () => {
let React = require('react/addons');
let <%= scriptAppName %>, component;
beforeEach(function () {
var container = document.createElement('div');
beforeEach(() => {
let container = document.createElement('div');
container.id = 'content';
document.body.appendChild(container);
@@ -13,7 +13,7 @@ describe('<%= classedName %>', function () {
component = React.createElement(<%= scriptAppName %>);
});
it('should create a new instance of <%= scriptAppName %>', function () {
it('should create a new instance of <%= scriptAppName %>', () => {
expect(component).toBeDefined();
});
});
+15 -10
View File
@@ -1,15 +1,20 @@
'use strict';
describe('<%= classedName %>', function () {
var React = require('react/addons');
var <%= classedName %>, component;
// Uncomment the following lines to use the react test utilities
// import React from 'react/addons';
// const TestUtils = React.addons.TestUtils;
beforeEach(function () {
<%= classedName %> = require('components/<%= classedFileName %><%= reactComponentSuffix %>');
component = React.createElement(<%= classedName %>);
});
import createComponent from 'helpers/createComponent';
import <%= classedName %> from 'components/<%= classedFileName %><%= reactComponentSuffix %>';
it('should create a new instance of <%= classedName %>', function () {
expect(component).toBeDefined();
});
describe('<%= classedName %>', () => {
let <%= classedName %>Component;
beforeEach(() => {
<%= classedName %>Component = createComponent(<%= classedName %>);
});
it('should have its component name as default className', () => {
expect(<%= classedName %>Component._store.props.className).toBe('<%= classedName %>');
});
});
+4 -4
View File
@@ -1,13 +1,13 @@
'use strict';
describe('<%= classedName %>', function() {
var store;
describe('<%= classedName %>', () => {
let store;
beforeEach(function() {
beforeEach(() => {
store = require('stores/<%= classedFileName %>.js');
});
it('should be defined', function() {
it('should be defined', () => {
expect(store).toBeDefined();
});
});
+4 -4
View File
@@ -1,14 +1,14 @@
'use strict';
describe('main', function () {
var main, component;
describe('main', () => {
let main, component;
beforeEach(function () {
beforeEach(() => {
main = require('components/main.jsx');
component = main();
});
it('should create a new instance of main', function () {
it('should create a new instance of main', () => {
expect(component).toBeDefined();
});
});