From a48f45f174fa2c27cc08d5276cb59c5636de6a23 Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Wed, 31 May 2017 15:36:32 -0400 Subject: [PATCH] 333 add ui tests (#336) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add infrastructure to support UI tests with Jest. Also add minimal test for lib-voyager.tsx * revert some package updates in an attempt to get ui tests working again * snapshot commit before possibly reverting changes. * Add infrastructure for running UI tests. Add some initial tests for app.tsx and lib-voyager.tsx * update tests to use ‘it’ instead of ‘test’. fixed up test. --- config/jest-ui.config.json | 13 + .../webpack.lib.config.js | 83 +++---- package.json | 7 +- scripts/jest.js | 40 +++ src/components/app.test.ui.tsx | 78 ++++++ src/lib-voyager.test.ui.tsx | 145 +++++++++++ src/store/index.ts | 2 +- yarn.lock | 230 +++++++++++++++++- 8 files changed, 543 insertions(+), 55 deletions(-) create mode 100644 config/jest-ui.config.json rename webpack.lib.config.js => config/webpack.lib.config.js (58%) create mode 100644 scripts/jest.js create mode 100644 src/components/app.test.ui.tsx create mode 100644 src/lib-voyager.test.ui.tsx diff --git a/config/jest-ui.config.json b/config/jest-ui.config.json new file mode 100644 index 000000000..4270c09f9 --- /dev/null +++ b/config/jest-ui.config.json @@ -0,0 +1,13 @@ +{ + "testPathDirs": [ + "/lib/" + ], + "testPathIgnorePatterns": [ + "/node_modules/" + ], + "testRegex": "(test\\.ui\\.(ts|tsx|jsx|js)\\.js$)", + "moduleFileExtensions": [ + "js" + ], + "collectCoverage": false +} \ No newline at end of file diff --git a/webpack.lib.config.js b/config/webpack.lib.config.js similarity index 58% rename from webpack.lib.config.js rename to config/webpack.lib.config.js index 88410481f..fa4c55763 100644 --- a/webpack.lib.config.js +++ b/config/webpack.lib.config.js @@ -1,48 +1,36 @@ var path = require('path'); +const webpack = require('webpack'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); +const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); var WebpackNotifierPlugin = require('webpack-notifier'); +const getClientEnvironment = require('./env'); +// Get environment variables to inject into our app. +var publicUrl = ''; +const env = getClientEnvironment(publicUrl); + module.exports = { entry: { - bundle: path.resolve(__dirname, 'src/lib-voyager.tsx'), - // Bundling deps into the bundle for now... - // vendor: [ - // // React - // 'react-css-modules', - // 'react-dnd', - // 'react-dnd-html5-backend', - // 'react-redux', - // 'react-split-pane', - // 'redux-thunk', - // 'redux-undo', - // - // 'reselect', - // - // // Other Lib - // 'd3', - // 'tslib', - // - // // Vega Dep - // 'compassql', - // 'vega-lite', - // 'vega' - // ] + bundle: path.resolve(__dirname, '../src/lib-voyager.tsx'), }, output: { filename: "[name].js", - path: path.resolve(__dirname, 'lib'), - publicPath: '/lib/', - libraryTarget: "umd", - library: "voyager", + path: path.resolve(__dirname, '../lib'), + // Add /* filename */ comments to generated require()s in the output. + pathinfo: true, + // There are also additional JS chunk files if you use code splitting. + chunkFilename: 'static/js/[name].chunk.js', + publicPath: '/lib/' }, // Enable sourcemaps for debugging webpack's output. - devtool: 'cheap-eval-source-map', - // devtool: "source-map", // this is better for production + // If it is inline, it will break CSS sourcemaps because of + // `extract-text-webpack-plugin` + devtool: 'source-map', devServer: { - contentBase: __dirname, + contentBase: path.resolve(__dirname, '../'), compress: true, port: 9000 }, @@ -54,13 +42,7 @@ module.exports = { module: { rules: [ - { - test: /\.tsx?$/, - loader: 'ts-loader', - options: { - configFileName: "tsconfig.lib.json", - }, - }, + { test: /\.tsx?$/, use: "ts-loader" }, // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. { test: /\.js$/, use: "source-map-loader", enforce: "pre" }, @@ -91,8 +73,9 @@ module.exports = { }, { loader: "sass-loader", options: { + sourceMap: true, includePaths: [ - path.resolve(__dirname, "node_modules/normalize-scss/sass") + path.resolve(__dirname, "../node_modules/normalize-scss/sass") ] } }] @@ -121,15 +104,29 @@ module.exports = { // assume a corresponding global variable exists and use that instead. // This is important because it allows us to avoid bundling all of our // dependencies, which allows browsers to cache those libraries between builds. - // externals: { - // "react": "React", - // "react-dom": "ReactDOM" - // }, + externals: { + // "react": "React", + // "react-dom": "ReactDOM" + }, plugins: [ + // Makes some environment variables available to the JS code, for example: + // if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`. + new webpack.DefinePlugin(env.stringified), + + // Watcher doesn't work well if you mistype casing in a path so we use + // a plugin that prints an error when you attempt to do this. + // See https://github.com/facebookincubator/create-react-app/issues/240 + new CaseSensitivePathsPlugin(), new ExtractTextPlugin({ filename: "style.css", disable: false }), new WebpackNotifierPlugin() - ] + ], + // Turn off performance hints during development because we don't do any + // splitting or minification in interest of speed. These warnings become + // cumbersome. + performance: { + hints: false, + }, }; diff --git a/package.json b/package.json index c83694009..4e1f32a1c 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,9 @@ "clean": "find -E dist -regex '.*\\.(js|js.map|d.ts)' -delete", "lint": "tslint -c tslint.json 'src/**/*.ts' 'src/**/*.tsx'", "lint-fix": "npm run lint -- --fix", - "test": "jest --no-cache --coverage", + "test": "npm run test:logic && npm run test:ui", + "test:logic": "jest --no-cache --coverage", + "test:ui": "NODE_ENV=test node scripts/jest.js", "posttest": "npm run lint", "codecov": "jest --no-cache --coverage && codecov" }, @@ -57,6 +59,7 @@ }, "devDependencies": { "@types/classnames": "^0.0.32", + "@types/enzyme": "^2.8.0", "@types/jest": "^18.1.1", "@types/react": "^15.0.8", "@types/react-css-modules": "^3.7.6", @@ -70,6 +73,7 @@ "case-sensitive-paths-webpack-plugin": "^2.0.0", "codecov": "^1.0.1", "css-loader": "^0.26.1", + "enzyme": "^2.8.2", "extract-text-webpack-plugin": "beta", "file-loader": "^0.10.1", "fs-extra": "^3.0.1", @@ -77,6 +81,7 @@ "jest": "~18", "node-sass": "^4.5.0", "postcss-loader": "^1.3.3", + "react-addons-test-utils": "15.4.2", "react-dev-utils": "^0.5.2", "sass-loader": "^5.0.1", "source-map-loader": "^0.1.6", diff --git a/scripts/jest.js b/scripts/jest.js new file mode 100644 index 000000000..a93d5083b --- /dev/null +++ b/scripts/jest.js @@ -0,0 +1,40 @@ +#!/usr/bin/env node + +const path = require('path'); +const webpack = require('webpack'); +// const config = require('../config/webpack.config.dev'); +const config = require('../config/webpack.lib.config'); +const glob = require('glob'); + + +const basedir = path.resolve(__dirname, '../src'); +const tests = glob.sync('*.{test,spec}.ui.{ts,tsx,js,jsx}', { + cwd: basedir, + matchBase: true, +}); + +config.entry = tests + .reduce(function(carry, key) { + carry[key] = path.resolve(basedir, key); + return carry; + }, {}); + + +const compiler = webpack(config); +compiler.run(function() {}); + +compiler.plugin('done', function(compilation) { + + if (process.env.NODE_ENV == null) { + process.env.NODE_ENV = 'test'; + } + + const jestConf = `--config ${path.resolve(__dirname, '../config', 'jest-ui.config.json')}`; + + try { + require('jest-cli/build/cli').run(jestConf); + } + catch (_) { + require('jest/node_modules/jest-cli/build/cli').run(jestConf); + } +}); diff --git a/src/components/app.test.ui.tsx b/src/components/app.test.ui.tsx new file mode 100644 index 000000000..c07e4bd85 --- /dev/null +++ b/src/components/app.test.ui.tsx @@ -0,0 +1,78 @@ +/** + * @jest-environment jsdom + */ +import {mount} from 'enzyme'; +import * as React from 'react'; + + +import {Provider} from 'react-redux'; +import {configureStore} from '../store'; +import {App} from './app'; + +describe('Voyager', () => { + describe('instantiation via component', () => { + it('renders voyager', done => { + const config = {}; + const data: any = undefined; + const store = configureStore(); + + setTimeout(() => { + try { + const wrapper = mount( + + + , + ); + + const header = wrapper.find('header'); + expect(header.exists()); + expect(header.text()).toContain('Voyager 2'); + } catch (err) { + done.fail(err); + } + done(); + }, 10); + }); + + it('renders voyager with custom data', done => { + const config = {}; + const data: any = { + "values": [ + {"fieldA": "A", "fieldB": 28}, {"fieldA": "B", "fieldB": 55}, {"fieldA": "C", "fieldB": 43}, + {"fieldA": "D", "fieldB": 91}, {"fieldA": "E", "fieldB": 81}, {"fieldA": "F", "fieldB": 53}, + {"fieldA": "G", "fieldB": 19}, {"fieldA": "H", "fieldB": 87}, {"fieldA": "I", "fieldB": 52} + ] + }; + const store = configureStore(); + + setTimeout(() => { + try { + const wrapper = mount( + + + , + ); + + const fieldList = wrapper.find('.field-list__field-list-item'); + const fields = fieldList.children().map(d => d.text()); + + expect(fields).toContain('fieldA'); + expect(fields).toContain('fieldB'); + + done(); + } catch (err) { + done.fail(err); + } + }, 10); + }); + + }); +}); diff --git a/src/lib-voyager.test.ui.tsx b/src/lib-voyager.test.ui.tsx new file mode 100644 index 000000000..e9c1c3aeb --- /dev/null +++ b/src/lib-voyager.test.ui.tsx @@ -0,0 +1,145 @@ +/** + * @jest-environment jsdom + */ +import {mount} from 'enzyme'; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; + +import {Provider} from 'react-redux'; +import {App} from './components/app'; +import {CreateVoyager} from './lib-voyager'; +import {configureStore} from './store'; + +describe('lib-voyager', () => { + let container: HTMLElement; + + beforeEach(() => { + document.body.innerHTML = `
`; + container = document.getElementById('root'); + }); + + afterEach(done => { + ReactDOM.unmountComponentAtNode(container); + document.body.innerHTML = ""; + setTimeout(done); + }); + + describe('instantiation via component', () => { + it('renders voyager', done => { + const config = {}; + const data: any = undefined; + const store = configureStore(); + + setTimeout(() => { + try { + const wrapper = mount( + + + , + ); + + const header = wrapper.find('header'); + expect(header.exists()); + expect(header.text()).toContain('Voyager 2'); + } catch (err) { + done.fail(err); + } + done(); + }, 10); + + + + }); + }); + + describe('instantiation', () => { + it('renders voyager on instantiation with DOM Node', done => { + const config = {}; + const data: any = undefined; + + setTimeout(() => { + try { + CreateVoyager(container, config, data); + const header = document.querySelector('header'); + expect(header.textContent).toContain('Voyager 2'); + done(); + } catch (err) { + done.fail(err); + } + }, 10); + }); + }); + + describe.skip('data', () => { + let originalTimeout: number; + beforeEach(done => { + jest.useRealTimers(); + // tslint:disable-next-line:no-string-literal + originalTimeout = jasmine['DEFAULT_TIMEOUT_INTERVAL']; + // tslint:disable-next-line:no-string-literal + jasmine['DEFAULT_TIMEOUT_INTERVAL'] = 20000; + done(); + }); + + afterEach(done => { + // tslint:disable-next-line:no-string-literal + jasmine['DEFAULT_TIMEOUT_INTERVAL'] = originalTimeout; + jest.useFakeTimers(); + done(); + }); + + + test('initialize with custom data', done => { + + const config = {}; + const data: any = { + "values": [ + {"fieldA": "A", "fieldB": 28}, {"fieldA": "B", "fieldB": 55}, {"fieldA": "C", "fieldB": 43}, + {"fieldA": "D", "fieldB": 91}, {"fieldA": "E", "fieldB": 81}, {"fieldA": "F", "fieldB": 53}, + {"fieldA": "G", "fieldB": 19}, {"fieldA": "H", "fieldB": 87}, {"fieldA": "I", "fieldB": 52} + ] + }; + + setTimeout(() => { + try { + CreateVoyager(container, config, data); + + setTimeout(() => { + const fieldList = document.querySelectorAll('.field-list__field-list-item'); + const fields = Array.prototype.map.call(fieldList, (d: Node) => d.textContent); + + expect(fieldList.length).toBe(2); + expect(fields).toBe(['fieldA', 'fieldB']); + done(); + }, 4000); + + // tslint:disable-next-line:no-string-literal + // const _store = voyager['store']; + // _store.subscribe(() => { + // const state = _store.getState(); + // console.log('store has changed', state, state.past[0]["dataset"]) + // if (state.present.dataset.name === "Custom Data") { + + // const fieldList = document.querySelectorAll('.field-list__field-list-item'); + // const fields = Array.prototype.map.call(fieldList, (d: Node) => d.textContent); + // console.log("WE GOT OUR DATA") + // console.log("FEFFE", fields) + // expect(fieldList.length).toBe(2); + // expect(fields).toBe(['fieldA', 'fieldB']); + // done(); + // } + // }); + + + } catch (err) { + done.fail(err); + } + }, 10); + + }); + }); +}); diff --git a/src/store/index.ts b/src/store/index.ts index 9ff767988..04bd3d3f9 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -15,7 +15,7 @@ let composeEnhancers = compose; const middleware: Middleware[] = [thunkMiddleware]; // when not in production enable redux tools and add logger middleware -if (process.env.NODE_ENV !== 'production') { +if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') { composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; middleware.push(loggerMiddleware); diff --git a/yarn.lock b/yarn.lock index 97dcdcdca..783b653bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,10 +2,21 @@ # yarn lockfile v1 +"@types/cheerio@*": + version "0.22.1" + resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.1.tgz#740c4cd8c4d3f3074f83b9ab62e711eac2c764ce" + "@types/classnames@^0.0.32": version "0.0.32" resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-0.0.32.tgz#449abcd9a826807811ef101e58df9f83cfc61713" +"@types/enzyme@^2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-2.8.0.tgz#84c6204cf89831223a89ab6dc3f490b1e0886352" + dependencies: + "@types/cheerio" "*" + "@types/react" "*" + "@types/es6-promise": version "0.0.32" resolved "https://registry.yarnpkg.com/@types/es6-promise/-/es6-promise-0.0.32.tgz#3bcf44fb1e429f3df76188c8c6d874463ba371fd" @@ -744,6 +755,27 @@ chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" +cheerio@^0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.0" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash.assignin "^4.0.9" + lodash.bind "^4.1.4" + lodash.defaults "^4.0.1" + lodash.filter "^4.4.0" + lodash.flatten "^4.2.0" + lodash.foreach "^4.3.0" + lodash.map "^4.4.0" + lodash.merge "^4.4.0" + lodash.pick "^4.2.1" + lodash.reduce "^4.4.0" + lodash.reject "^4.4.0" + lodash.some "^4.4.0" + chokidar@^1.4.3, chokidar@^1.6.0: version "1.6.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" @@ -1113,7 +1145,7 @@ css-loader@*, css-loader@^0.26.1: postcss-modules-values "^1.1.0" source-list-map "^0.1.4" -css-select@^1.1.0: +css-select@^1.1.0, css-select@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" dependencies: @@ -1417,6 +1449,13 @@ default-require-extensions@^1.0.0: dependencies: strip-bom "^2.0.0" +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + defined@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" @@ -1488,7 +1527,7 @@ dom-converter@~0.1: dependencies: utila "~0.3" -dom-serializer@0: +dom-serializer@0, dom-serializer@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" dependencies: @@ -1499,7 +1538,7 @@ domain-browser@^1.1.1: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" -domelementtype@1: +domelementtype@1, domelementtype@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" @@ -1513,13 +1552,19 @@ domhandler@2.1: dependencies: domelementtype "1" +domhandler@^2.3.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.1.tgz#892e47000a99be55bbf3774ffea0561d8879c259" + dependencies: + domelementtype "1" + domutils@1.1: version "1.1.6" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485" dependencies: domelementtype "1" -domutils@1.5.1: +domutils@1.5.1, domutils@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" dependencies: @@ -1592,10 +1637,25 @@ enhanced-resolve@^3.0.0: object-assign "^4.0.1" tapable "^0.2.5" -entities@~1.1.1: +entities@^1.1.1, entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" +enzyme@^2.8.2: + version "2.8.2" + resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-2.8.2.tgz#6c8bcb05012abc4aa4bc3213fb23780b9b5b1714" + dependencies: + cheerio "^0.22.0" + function.prototype.name "^1.0.0" + is-subset "^0.1.1" + lodash "^4.17.2" + object-is "^1.0.1" + object.assign "^4.0.4" + object.entries "^1.0.3" + object.values "^1.0.3" + prop-types "^15.5.4" + uuid "^2.0.3" + "errno@>=0.1.1 <0.2.0-0", errno@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" @@ -1608,6 +1668,23 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" +es-abstract@^1.6.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.7.0.tgz#dfade774e01bfcd97f96180298c449c8623fb94c" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.0" + is-callable "^1.1.3" + is-regex "^1.0.3" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -1863,7 +1940,7 @@ fb-watchman@^1.8.0, fb-watchman@^1.9.0: dependencies: bser "1.0.2" -fbjs@^0.8.1, fbjs@^0.8.4: +fbjs@^0.8.1, fbjs@^0.8.4, fbjs@^0.8.9: version "0.8.9" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.9.tgz#180247fbd347dcc9004517b904f865400a0c8f14" dependencies: @@ -2031,10 +2108,18 @@ fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: mkdirp ">=0.5 0" rimraf "2" -function-bind@^1.0.2: +function-bind@^1.0.2, function-bind@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" +function.prototype.name@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.0.0.tgz#5f523ca64e491a5f95aba80cc1e391080a14482e" + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.0" + is-callable "^1.1.2" + gauge@~2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09" @@ -2349,6 +2434,17 @@ html-webpack-plugin@^2.28.0: pretty-error "^2.0.2" toposort "^1.0.0" +htmlparser2@^3.9.1: + version "3.9.2" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" + dependencies: + domelementtype "^1.3.0" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^2.0.2" + htmlparser2@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe" @@ -2524,12 +2620,20 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" +is-callable@^1.1.1, is-callable@^1.1.2, is-callable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" + is-ci@^1.0.9: version "1.0.10" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e" dependencies: ci-info "^1.0.0" +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + is-dotfile@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" @@ -2623,6 +2727,12 @@ is-redirect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" +is-regex@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + is-retry-allowed@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" @@ -2631,12 +2741,20 @@ is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" +is-subset@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" + is-svg@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" dependencies: html-comment-regex "^1.1.0" +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -3221,6 +3339,14 @@ lodash.assign@^4.0.3, lodash.assign@^4.0.6, lodash.assign@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" +lodash.assignin@^4.0.9: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + +lodash.bind@^4.1.4: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" + lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" @@ -3236,12 +3362,28 @@ lodash.clonedeep@^4.3.2: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" +lodash.defaults@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + lodash.escape@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" dependencies: lodash._root "^3.0.0" +lodash.filter@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" + +lodash.flatten@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + +lodash.foreach@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" @@ -3262,10 +3404,18 @@ lodash.keys@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" +lodash.map@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" + lodash.memoize@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" +lodash.merge@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" + lodash.mergewith@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55" @@ -3274,14 +3424,30 @@ lodash.partition@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.partition/-/lodash.partition-4.6.0.tgz#a38e46b73469e0420b0da1212e66d414be364ba4" +lodash.pick@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + lodash.pickby@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff" +lodash.reduce@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" + +lodash.reject@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" + lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" +lodash.some@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + lodash.tail@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" @@ -3323,7 +3489,7 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0, loose-envify@^1.1.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: @@ -3743,7 +3909,11 @@ object-inspect@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-0.4.0.tgz#f5157c116c1455b243b06ee97703392c5ad89fec" -object-keys@^1.0.6: +object-is@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6" + +object-keys@^1.0.10, object-keys@^1.0.6, object-keys@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" @@ -3755,6 +3925,23 @@ object-unfreeze@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/object-unfreeze/-/object-unfreeze-1.1.0.tgz#69628bea1f3c9d29f4eb0ba63b38002d70ea3ce9" +object.assign@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.0.4.tgz#b1c9cc044ef1b9fe63606fc141abbb32e14730cc" + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.0" + object-keys "^1.0.10" + +object.entries@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.4.tgz#1bf9a4dd2288f5b33f3a993d257661f05d161a5f" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.6.1" + function-bind "^1.1.0" + has "^1.0.1" + object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -3762,6 +3949,15 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" +object.values@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.4.tgz#e524da09b4f66ff05df457546ec72ac99f13069a" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.6.1" + function-bind "^1.1.0" + has "^1.0.1" + obuf@^1.0.0, obuf@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e" @@ -4317,6 +4513,13 @@ promise@^7.1.1: dependencies: asap "~2.0.3" +prop-types@^15.5.4: + version "15.5.10" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154" + dependencies: + fbjs "^0.8.9" + loose-envify "^1.3.1" + proxy-addr@~1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.3.tgz#dc97502f5722e888467b3fa2297a7b1ff47df074" @@ -4420,6 +4623,13 @@ rc@^1.0.1, rc@^1.1.6, rc@~1.1.6: minimist "^1.2.0" strip-json-comments "~1.0.4" +react-addons-test-utils@15.4.2: + version "15.4.2" + resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.4.2.tgz#93bcaa718fcae7360d42e8fb1c09756cc36302a2" + dependencies: + fbjs "^0.8.4" + object-assign "^4.1.0" + react-css-modules@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/react-css-modules/-/react-css-modules-4.1.0.tgz#848e3d5089ec6596feabf6c0daaacc06866c58e7" @@ -5662,7 +5872,7 @@ utils-merge@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" -uuid@^2.0.2: +uuid@^2.0.2, uuid@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"