set up react testing (#1080)
* install mocha-webpack. also switch hark to npm version instead of github version * well, mocha-webpack runs * add jsdom for tests * upgrade to webpack 2 * fix npm run test errors * ImportDialogBox component tests
This commit is contained in:
parent
a6c1c0c730
commit
4ff9619837
10 changed files with 108 additions and 27 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -22,6 +22,7 @@ app/assets/javascripts/webpacked
|
||||||
# Ignore all logfiles and tempfiles.
|
# Ignore all logfiles and tempfiles.
|
||||||
log/*.log
|
log/*.log
|
||||||
tmp
|
tmp
|
||||||
|
.tmp
|
||||||
|
|
||||||
coverage
|
coverage
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,10 @@ const ImportDialog = {
|
||||||
ReactDOM.render(React.createElement(ImportDialogBox, {
|
ReactDOM.render(React.createElement(ImportDialogBox, {
|
||||||
onFileAdded: PasteInput.handleFile,
|
onFileAdded: PasteInput.handleFile,
|
||||||
exampleImageUrl: serverData['import-example.png'],
|
exampleImageUrl: serverData['import-example.png'],
|
||||||
downloadScreenshot: ImportDialog.downloadScreenshot
|
downloadScreenshot: ImportDialog.downloadScreenshot,
|
||||||
|
onExport: format => {
|
||||||
|
window.open(`${window.location.pathname}/export.${format}`, '_blank')
|
||||||
|
}
|
||||||
}), $('.importDialogWrapper').get(0))
|
}), $('.importDialogWrapper').get(0))
|
||||||
},
|
},
|
||||||
show: function() {
|
show: function() {
|
||||||
|
|
|
@ -2,17 +2,6 @@ import React, { PropTypes, Component } from 'react'
|
||||||
import Dropzone from 'react-dropzone'
|
import Dropzone from 'react-dropzone'
|
||||||
|
|
||||||
class ImportDialogBox extends Component {
|
class ImportDialogBox extends Component {
|
||||||
constructor(props) {
|
|
||||||
super(props)
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleExport = format => () => {
|
|
||||||
window.open(`${window.location.pathname}/export.${format}`, '_blank')
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFile = (files, e) => {
|
handleFile = (files, e) => {
|
||||||
e.preventDefault() // prevent it from triggering the default drag-drop handler
|
e.preventDefault() // prevent it from triggering the default drag-drop handler
|
||||||
this.props.onFileAdded(files[0])
|
this.props.onFileAdded(files[0])
|
||||||
|
@ -22,13 +11,13 @@ class ImportDialogBox extends Component {
|
||||||
return (
|
return (
|
||||||
<div className="import-dialog">
|
<div className="import-dialog">
|
||||||
<h3>EXPORT</h3>
|
<h3>EXPORT</h3>
|
||||||
<div className="import-blue-button" onClick={this.handleExport('csv')}>
|
<div className="export-csv import-blue-button" onClick={this.props.onExport('csv')}>
|
||||||
Export as CSV
|
Export as CSV
|
||||||
</div>
|
</div>
|
||||||
<div className="import-blue-button" onClick={this.handleExport('json')}>
|
<div className="export-json import-blue-button" onClick={this.props.onExport('json')}>
|
||||||
Export as JSON
|
Export as JSON
|
||||||
</div>
|
</div>
|
||||||
<div className="import-blue-button" onClick={this.props.downloadScreenshot}>
|
<div className="download-screenshot import-blue-button" onClick={this.props.downloadScreenshot}>
|
||||||
Download screenshot
|
Download screenshot
|
||||||
</div>
|
</div>
|
||||||
<h3>IMPORT</h3>
|
<h3>IMPORT</h3>
|
||||||
|
@ -46,8 +35,8 @@ class ImportDialogBox extends Component {
|
||||||
|
|
||||||
ImportDialogBox.propTypes = {
|
ImportDialogBox.propTypes = {
|
||||||
onFileAdded: PropTypes.func,
|
onFileAdded: PropTypes.func,
|
||||||
exampleImageUrl: PropTypes.string,
|
downloadScreenshot: PropTypes.func,
|
||||||
downloadScreenshot: PropTypes.func
|
onExport: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ImportDialogBox
|
export default ImportDialogBox
|
||||||
|
|
50
frontend/test/components/ImportDialogBox.spec.js
Normal file
50
frontend/test/components/ImportDialogBox.spec.js
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/* global describe, it */
|
||||||
|
import React from 'react'
|
||||||
|
import TestUtils from 'react-addons-test-utils' // ES6
|
||||||
|
import ImportDialogBox from '../../src/components/ImportDialogBox.js'
|
||||||
|
import Dropzone from 'react-dropzone'
|
||||||
|
import chai from 'chai'
|
||||||
|
|
||||||
|
const { expect } = chai
|
||||||
|
|
||||||
|
describe('ImportDialogBox', function() {
|
||||||
|
it('has an Export CSV button', function(done) {
|
||||||
|
const onExport = format => {
|
||||||
|
if (format === 'csv') done()
|
||||||
|
}
|
||||||
|
const detachedComp = TestUtils.renderIntoDocument(<ImportDialogBox onExport={onExport} />)
|
||||||
|
const button = TestUtils.findRenderedDOMComponentWithClass(detachedComp, 'export-csv')
|
||||||
|
const buttonNode = React.findDOMNode(button)
|
||||||
|
expect(button).to.exist;
|
||||||
|
TestUtils.Simulate.click(buttonNode)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has an Export JSON button', function(done) {
|
||||||
|
const onExport = format => {
|
||||||
|
if (format === 'json') done()
|
||||||
|
}
|
||||||
|
const detachedComp = TestUtils.renderIntoDocument(<ImportDialogBox onExport={onExport} />)
|
||||||
|
const button = TestUtils.findRenderedDOMComponentWithClass(detachedComp, 'export-json')
|
||||||
|
const buttonNode = React.findDOMNode(button)
|
||||||
|
expect(button).to.exist;
|
||||||
|
TestUtils.Simulate.click(buttonNode)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a Download screenshot button', function(done) {
|
||||||
|
const downloadScreenshot = () => { done() }
|
||||||
|
const detachedComp = TestUtils.renderIntoDocument(<ImportDialogBox downloadScreenshot={downloadScreenshot()} />)
|
||||||
|
const button = TestUtils.findRenderedDOMComponentWithClass(detachedComp, 'download-screenshot')
|
||||||
|
const buttonNode = React.findDOMNode(button)
|
||||||
|
expect(button).to.exist;
|
||||||
|
TestUtils.Simulate.click(buttonNode)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a file uploader', function(done) {
|
||||||
|
const uploadedFile = { file: 'mock a file' }
|
||||||
|
const onFileAdded = file => { if (file === uploadedFile) done() }
|
||||||
|
const detachedComp = TestUtils.renderIntoDocument(<ImportDialogBox onExport={() => {}} onFileAdded={onFileAdded} />)
|
||||||
|
const dropzone = TestUtils.findRenderedComponentWithType(detachedComp, Dropzone)
|
||||||
|
expect(dropzone).to.exist;
|
||||||
|
dropzone.props.onDropAccepted([uploadedFile], { preventDefault: () => {} })
|
||||||
|
})
|
||||||
|
})
|
25
frontend/test/support/dom.js
Normal file
25
frontend/test/support/dom.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
const jsdom = require('jsdom')
|
||||||
|
const doc = jsdom.jsdom('<!doctype html><html><body></body></html>')
|
||||||
|
const win = doc.defaultView
|
||||||
|
|
||||||
|
global.document = doc
|
||||||
|
global.window = win
|
||||||
|
|
||||||
|
// take all properties of the window object and also attach it to the
|
||||||
|
// mocha global object
|
||||||
|
propagateToGlobal(win)
|
||||||
|
|
||||||
|
// from mocha-jsdom https://github.com/rstacruz/mocha-jsdom/blob/master/index.js#L80
|
||||||
|
function propagateToGlobal (window) {
|
||||||
|
for (let key in window) {
|
||||||
|
if (!window.hasOwnProperty(key)) continue
|
||||||
|
if (key in global) continue
|
||||||
|
|
||||||
|
global[key] = window[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metamaps dependencies fixes
|
||||||
|
global.HowlerGlobal = global.HowlerGlobal || { prototype: {} }
|
||||||
|
global.Howl = global.Howl || { prototype: {} }
|
||||||
|
global.Sound = global.Sound || { prototype: {} }
|
15
package.json
15
package.json
|
@ -5,7 +5,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack",
|
"build": "webpack",
|
||||||
"build:watch": "webpack --watch",
|
"build:watch": "webpack --watch",
|
||||||
"test": "mocha --compilers js:babel-core/register frontend/test",
|
"test": "mocha-webpack --webpack-config webpack.test.config.js --require frontend/test/support/dom.js frontend/test",
|
||||||
"eslint": "eslint frontend",
|
"eslint": "eslint frontend",
|
||||||
"eslint:fix": "eslint --fix frontend"
|
"eslint:fix": "eslint --fix frontend"
|
||||||
},
|
},
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
"csv-parse": "1.1.10",
|
"csv-parse": "1.1.10",
|
||||||
"emoji-mart": "0.3.7",
|
"emoji-mart": "0.3.7",
|
||||||
"getscreenmedia": "2.0.0",
|
"getscreenmedia": "2.0.0",
|
||||||
"hark": "git://github.com/otalk/hark#342ef9b7eff2",
|
"hark": "1.1.5",
|
||||||
"howler": "2.0.2",
|
"howler": "2.0.2",
|
||||||
"jquery": "3.1.1",
|
"jquery": "3.1.1",
|
||||||
"json-loader": "0.5.4",
|
"json-loader": "0.5.4",
|
||||||
|
@ -45,12 +45,12 @@
|
||||||
"react": "15.4.2",
|
"react": "15.4.2",
|
||||||
"react-dom": "15.4.2",
|
"react-dom": "15.4.2",
|
||||||
"react-dropzone": "3.9.1",
|
"react-dropzone": "3.9.1",
|
||||||
"react-onclickoutside": "^5.9.0",
|
"react-onclickoutside": "5.9.0",
|
||||||
"redux": "3.6.0",
|
"redux": "3.6.0",
|
||||||
"riek": "^1.0.7",
|
"riek": "1.0.7",
|
||||||
"simplewebrtc": "2.2.2",
|
"simplewebrtc": "2.2.2",
|
||||||
"socket.io": "1.3.7",
|
"socket.io": "1.3.7",
|
||||||
"webpack": "1.14.0"
|
"webpack": "2.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-eslint": "^7.1.1",
|
"babel-eslint": "^7.1.1",
|
||||||
|
@ -61,7 +61,10 @@
|
||||||
"eslint-plugin-promise": "^3.4.0",
|
"eslint-plugin-promise": "^3.4.0",
|
||||||
"eslint-plugin-react": "^6.8.0",
|
"eslint-plugin-react": "^6.8.0",
|
||||||
"eslint-plugin-standard": "^2.0.1",
|
"eslint-plugin-standard": "^2.0.1",
|
||||||
"mocha": "^3.2.0"
|
"jsdom": "^9.11.0",
|
||||||
|
"mocha": "^3.2.0",
|
||||||
|
"mocha-webpack": "^0.7.0",
|
||||||
|
"react-addons-test-utils": "^15.4.2"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"raml2html": "4.0.5"
|
"raml2html": "4.0.5"
|
||||||
|
|
|
@ -5,8 +5,12 @@ const NODE_ENV = process.env.NODE_ENV || 'development'
|
||||||
const plugins = [
|
const plugins = [
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
"process.env.NODE_ENV": `"${NODE_ENV}"`
|
"process.env.NODE_ENV": `"${NODE_ENV}"`
|
||||||
})
|
}),
|
||||||
|
new webpack.IgnorePlugin(/^mock-firmata$/), // work around bindings.js error
|
||||||
|
new webpack.ContextReplacementPlugin(/bindings$/, /^$/) // work around bindings.js error
|
||||||
]
|
]
|
||||||
|
const externals = ["bindings"] // work around bindings.js error
|
||||||
|
|
||||||
if (NODE_ENV === 'production') {
|
if (NODE_ENV === 'production') {
|
||||||
plugins.push(new webpack.optimize.DedupePlugin())
|
plugins.push(new webpack.optimize.DedupePlugin())
|
||||||
plugins.push(new webpack.optimize.UglifyJsPlugin({
|
plugins.push(new webpack.optimize.UglifyJsPlugin({
|
||||||
|
@ -26,12 +30,13 @@ const devtool = NODE_ENV === 'production' ? undefined : 'cheap-module-eval-sourc
|
||||||
module.exports = {
|
module.exports = {
|
||||||
context: __dirname,
|
context: __dirname,
|
||||||
plugins,
|
plugins,
|
||||||
|
externals,
|
||||||
devtool,
|
devtool,
|
||||||
module: {
|
module: {
|
||||||
preLoaders: [
|
|
||||||
{ test: /\.json$/, loader: 'json' }
|
|
||||||
],
|
|
||||||
loaders: [
|
loaders: [
|
||||||
|
{
|
||||||
|
test: /\.json$/, loader: 'json-loader'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.(js|jsx)?$/,
|
test: /\.(js|jsx)?$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
|
|
5
webpack.test.config.js
Normal file
5
webpack.test.config.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const config = require('./webpack.config')
|
||||||
|
|
||||||
|
config.target = 'node'
|
||||||
|
|
||||||
|
module.exports = config
|
Loading…
Add table
Reference in a new issue