From 4ff96198377ce58cefdca26cf2302dc99cb27005 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Mon, 6 Mar 2017 02:29:12 +0800 Subject: [PATCH] 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 --- .gitignore | 1 + .../src/Metamaps/GlobalUI/ImportDialog.js | 5 +- frontend/src/components/ImportDialogBox.js | 21 ++------ .../Import.spec.js} | 0 .../Util.spec.js} | 0 .../test/components/ImportDialogBox.spec.js | 50 +++++++++++++++++++ frontend/test/support/dom.js | 25 ++++++++++ package.json | 15 +++--- webpack.config.js | 13 +++-- webpack.test.config.js | 5 ++ 10 files changed, 108 insertions(+), 27 deletions(-) rename frontend/test/{Metamaps.Import.spec.js => Metamaps/Import.spec.js} (100%) rename frontend/test/{Metamaps.Util.spec.js => Metamaps/Util.spec.js} (100%) create mode 100644 frontend/test/components/ImportDialogBox.spec.js create mode 100644 frontend/test/support/dom.js create mode 100644 webpack.test.config.js diff --git a/.gitignore b/.gitignore index bf50d518..de3cc231 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ app/assets/javascripts/webpacked # Ignore all logfiles and tempfiles. log/*.log tmp +.tmp coverage diff --git a/frontend/src/Metamaps/GlobalUI/ImportDialog.js b/frontend/src/Metamaps/GlobalUI/ImportDialog.js index 1428ab6d..31913ea6 100644 --- a/frontend/src/Metamaps/GlobalUI/ImportDialog.js +++ b/frontend/src/Metamaps/GlobalUI/ImportDialog.js @@ -26,7 +26,10 @@ const ImportDialog = { ReactDOM.render(React.createElement(ImportDialogBox, { onFileAdded: PasteInput.handleFile, exampleImageUrl: serverData['import-example.png'], - downloadScreenshot: ImportDialog.downloadScreenshot + downloadScreenshot: ImportDialog.downloadScreenshot, + onExport: format => { + window.open(`${window.location.pathname}/export.${format}`, '_blank') + } }), $('.importDialogWrapper').get(0)) }, show: function() { diff --git a/frontend/src/components/ImportDialogBox.js b/frontend/src/components/ImportDialogBox.js index 6c2d7413..9a9c777b 100644 --- a/frontend/src/components/ImportDialogBox.js +++ b/frontend/src/components/ImportDialogBox.js @@ -2,17 +2,6 @@ import React, { PropTypes, Component } from 'react' import Dropzone from 'react-dropzone' class ImportDialogBox extends Component { - constructor(props) { - super(props) - - this.state = { - } - } - - handleExport = format => () => { - window.open(`${window.location.pathname}/export.${format}`, '_blank') - } - handleFile = (files, e) => { e.preventDefault() // prevent it from triggering the default drag-drop handler this.props.onFileAdded(files[0]) @@ -22,13 +11,13 @@ class ImportDialogBox extends Component { return (

EXPORT

-
+
Export as CSV
-
+
Export as JSON
-
+
Download screenshot

IMPORT

@@ -46,8 +35,8 @@ class ImportDialogBox extends Component { ImportDialogBox.propTypes = { onFileAdded: PropTypes.func, - exampleImageUrl: PropTypes.string, - downloadScreenshot: PropTypes.func + downloadScreenshot: PropTypes.func, + onExport: PropTypes.func } export default ImportDialogBox diff --git a/frontend/test/Metamaps.Import.spec.js b/frontend/test/Metamaps/Import.spec.js similarity index 100% rename from frontend/test/Metamaps.Import.spec.js rename to frontend/test/Metamaps/Import.spec.js diff --git a/frontend/test/Metamaps.Util.spec.js b/frontend/test/Metamaps/Util.spec.js similarity index 100% rename from frontend/test/Metamaps.Util.spec.js rename to frontend/test/Metamaps/Util.spec.js diff --git a/frontend/test/components/ImportDialogBox.spec.js b/frontend/test/components/ImportDialogBox.spec.js new file mode 100644 index 00000000..f14e04b3 --- /dev/null +++ b/frontend/test/components/ImportDialogBox.spec.js @@ -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() + 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() + 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() + 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( {}} onFileAdded={onFileAdded} />) + const dropzone = TestUtils.findRenderedComponentWithType(detachedComp, Dropzone) + expect(dropzone).to.exist; + dropzone.props.onDropAccepted([uploadedFile], { preventDefault: () => {} }) + }) +}) diff --git a/frontend/test/support/dom.js b/frontend/test/support/dom.js new file mode 100644 index 00000000..af2c1bf9 --- /dev/null +++ b/frontend/test/support/dom.js @@ -0,0 +1,25 @@ +const jsdom = require('jsdom') +const doc = jsdom.jsdom('') +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: {} } diff --git a/package.json b/package.json index 6db62390..84eff416 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "build": "webpack", "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:fix": "eslint --fix frontend" }, @@ -35,7 +35,7 @@ "csv-parse": "1.1.10", "emoji-mart": "0.3.7", "getscreenmedia": "2.0.0", - "hark": "git://github.com/otalk/hark#342ef9b7eff2", + "hark": "1.1.5", "howler": "2.0.2", "jquery": "3.1.1", "json-loader": "0.5.4", @@ -45,12 +45,12 @@ "react": "15.4.2", "react-dom": "15.4.2", "react-dropzone": "3.9.1", - "react-onclickoutside": "^5.9.0", + "react-onclickoutside": "5.9.0", "redux": "3.6.0", - "riek": "^1.0.7", + "riek": "1.0.7", "simplewebrtc": "2.2.2", "socket.io": "1.3.7", - "webpack": "1.14.0" + "webpack": "2.2.1" }, "devDependencies": { "babel-eslint": "^7.1.1", @@ -61,7 +61,10 @@ "eslint-plugin-promise": "^3.4.0", "eslint-plugin-react": "^6.8.0", "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": { "raml2html": "4.0.5" diff --git a/webpack.config.js b/webpack.config.js index 13cf6a65..a207d23c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -5,8 +5,12 @@ const NODE_ENV = process.env.NODE_ENV || 'development' const plugins = [ new webpack.DefinePlugin({ "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') { plugins.push(new webpack.optimize.DedupePlugin()) plugins.push(new webpack.optimize.UglifyJsPlugin({ @@ -26,12 +30,13 @@ const devtool = NODE_ENV === 'production' ? undefined : 'cheap-module-eval-sourc module.exports = { context: __dirname, plugins, + externals, devtool, module: { - preLoaders: [ - { test: /\.json$/, loader: 'json' } - ], loaders: [ + { + test: /\.json$/, loader: 'json-loader' + }, { test: /\.(js|jsx)?$/, exclude: /node_modules/, diff --git a/webpack.test.config.js b/webpack.test.config.js new file mode 100644 index 00000000..518835d4 --- /dev/null +++ b/webpack.test.config.js @@ -0,0 +1,5 @@ +const config = require('./webpack.config') + +config.target = 'node' + +module.exports = config