diff --git a/frontend/src/metabase/dashboard/components/DashCard.jsx b/frontend/src/metabase/dashboard/components/DashCard.jsx index 6e91340b64f5e72a8ffaa0d9a74627e341ac44af..08df8f6ed8510b797245041249d23773af1f908b 100644 --- a/frontend/src/metabase/dashboard/components/DashCard.jsx +++ b/frontend/src/metabase/dashboard/components/DashCard.jsx @@ -2,7 +2,7 @@ import React, { Component, PropTypes } from "react"; import ReactDOM from "react-dom"; import visualizations, { getVisualizationRaw } from "metabase/visualizations"; -import Visualization from "metabase/visualizations/components/Visualization.jsx"; +import Visualization, { ERROR_MESSAGE_GENERIC, ERROR_MESSAGE_PERMISSION } from "metabase/visualizations/components/Visualization.jsx"; import ModalWithTrigger from "metabase/components/ModalWithTrigger.jsx"; import ChartSettings from "metabase/visualizations/components/ChartSettings.jsx"; @@ -15,9 +15,6 @@ import cx from "classnames"; import _ from "underscore"; import { getIn } from "icepick"; -const ERROR_MESSAGE_GENERIC = "There was a problem displaying this chart."; -const ERROR_MESSAGE_PERMISSION = "Sorry, you don't have permission to see this card." - export default class DashCard extends Component { constructor(props, context) { super(props, context); diff --git a/frontend/src/metabase/visualizations/Funnel.jsx b/frontend/src/metabase/visualizations/Funnel.jsx index cd721610c1ec01b8226c2eb1fbfbb75d15805bf9..7dcbbd2e1a263a0a838d65446964b1db0fb2437b 100644 --- a/frontend/src/metabase/visualizations/Funnel.jsx +++ b/frontend/src/metabase/visualizations/Funnel.jsx @@ -5,7 +5,6 @@ import BarChart from "./BarChart.jsx"; import { formatValue } from "metabase/lib/formatting"; import { getSettings } from "metabase/lib/visualization_settings"; -import { isNumeric } from "metabase/lib/schema_metadata"; import i from "icepick"; export default class Funnel extends Component { @@ -23,9 +22,8 @@ export default class Funnel extends Component { } static checkRenderable(cols, rows) { - if (!isNumeric(cols[0])) { - throw new Error("Funnel visualization requires a number."); - } + // leaving this blank for now since it should be difficult to get into an invalid state + // TODO: we should really change checkRenderable to take the entire `series` object } static transformSeries(series) { diff --git a/frontend/src/metabase/visualizations/components/Visualization.jsx b/frontend/src/metabase/visualizations/components/Visualization.jsx index 2edb36dfddb5259771442ab74b002b9e8b0c5e64..22786dbbe6d8fc09a7faaa98810131087b74a94d 100644 --- a/frontend/src/metabase/visualizations/components/Visualization.jsx +++ b/frontend/src/metabase/visualizations/components/Visualization.jsx @@ -1,3 +1,5 @@ +/* eslint "react/prop-types": "warn" */ + import React, { Component, PropTypes } from "react"; import ExplicitSize from "metabase/components/ExplicitSize.jsx"; @@ -16,6 +18,9 @@ import { assoc, getIn } from "icepick"; import _ from "underscore"; import cx from "classnames"; +export const ERROR_MESSAGE_GENERIC = "There was a problem displaying this chart."; +export const ERROR_MESSAGE_PERMISSION = "Sorry, you don't have permission to see this card." + @ExplicitSize export default class Visualization extends Component { constructor(props, context) { @@ -33,9 +38,31 @@ export default class Visualization extends Component { static propTypes = { series: PropTypes.array.isRequired, + className: PropTypes.string, + isDashboard: PropTypes.bool, isEditing: PropTypes.bool, + actionButtons: PropTypes.node, + + // errors + error: PropTypes.string, + errorIcon: PropTypes.string, + + // slow card warnings + isSlow: PropTypes.bool, + expectedDuration: PropTypes.number, + + // injected by ExplicitSize + width: PropTypes.number, + height: PropTypes.number, + + // settings overrides from settings panel + settings: PropTypes.object, + + // used for showing content in place of visualization, e.x. dashcard filter mapping + replacementContent: PropTypes.node, + // used by TableInteractive setSortFn: PropTypes.func, cellIsClickableFn: PropTypes.func, @@ -118,6 +145,12 @@ export default class Visualization extends Component { } } } + + // if on dashoard, and error didn't come from props replace it with the generic error message + if (isDashboard && error && this.props.error !== error) { + error = ERROR_MESSAGE_GENERIC; + } + if (!error) { noResults = getIn(series, [0, "data", "rows", "length"]) === 0; } @@ -136,7 +169,13 @@ export default class Visualization extends Component { { isDashboard && (settings["card.title"] || extra) && (loading || error || !CardVisualization.noHeader) || replacementContent ? <div className="p1 flex-no-shrink"> <LegendHeader - series={[{ card: { name: settings["card.title"] }}]} + series={ + settings["card.title"] ? + // if we have a card title set, use it + [{ card: { name: settings["card.title"] }}] : + // otherwise use the original series + series + } actionButtons={extra} settings={settings} /> diff --git a/frontend/test/karma.conf.js b/frontend/test/karma.conf.js index 97d778730d6619a9c2cbea62098cb39838b3c55e..80e628aeee1db342bdf753fee5f142c357684710 100644 --- a/frontend/test/karma.conf.js +++ b/frontend/test/karma.conf.js @@ -2,13 +2,17 @@ var webpackConfig = require('../../webpack.config'); webpackConfig.module.postLoaders = [ { test: /\.js$/, exclude: /(\.spec\.js|vendor|node_modules)/, loader: 'istanbul-instrumenter' } ]; +webpackConfig.module.loaders.forEach(function(loader) { + loader.loader = loader.loader.replace(/^.*extract-text-webpack-plugin[^!]+!/, ""); +}); module.exports = function(config) { config.set({ basePath: '../', files: [ 'test/metabase-bootstrap.js', - 'test/unit/**/*.spec.js' + // prevent tests from running twice: https://github.com/nikku/karma-browserify/issues/67#issuecomment-84448491 + { pattern: 'test/unit/**/*.spec.js', watched: false, included: true, served: true } ], exclude: [ ], @@ -26,7 +30,11 @@ module.exports = function(config) { ], webpack: { resolve: webpackConfig.resolve, - module: webpackConfig.module + module: webpackConfig.module, + postcss: webpackConfig.postcss + }, + webpackMiddleware: { + stats: "errors-only" }, webpackMiddleware: { stats: "errors-only", diff --git a/frontend/test/metabase-bootstrap.js b/frontend/test/metabase-bootstrap.js index c8a4220979d89e1f82ae45d9a12c48aff08b9174..aa4d9e7ae248e4ed9bf61ddbee1e0fed4b011423 100644 --- a/frontend/test/metabase-bootstrap.js +++ b/frontend/test/metabase-bootstrap.js @@ -1,4 +1,5 @@ import "metabase/vendor"; +import "metabase/css/index.css"; window.MetabaseBootstrap = { timezones: [ diff --git a/frontend/test/unit/support/visualizations.js b/frontend/test/unit/support/visualizations.js new file mode 100644 index 0000000000000000000000000000000000000000..fc1e56599f358c752eb619511490eeb18d862491 --- /dev/null +++ b/frontend/test/unit/support/visualizations.js @@ -0,0 +1,87 @@ + +export function makeCard(card) { + return { + name: "card", + dataset_query: {}, + visualization_settings: {}, + display: "scalar", + ...card + } +} + +export function makeData(cols, rows) { + return { + cols, + rows + }; +} + +export const Column = (col = {}) => ({ + ...col, + name: col.name || "column_name", + display_name: col.display_name || col.name || "column_display_name" +}); + +export const DateTimeColumn = (col = {}) => Column({ "base_type" : "type/DateTime", "special_type" : null, ...col }); +export const NumberColumn = (col = {}) => Column({ "base_type" : "type/Integer", "special_type" : "type/Number", ...col }); +export const StringColumn = (col = {}) => Column({ "base_type" : "type/Text", "special_type" : null, ...col }); + +export const Card = (name, ...overrides) => deepExtend({ + card: { + name: name + "_name", + visualization_settings: {} + } +}, ...overrides); + +export const ScalarCard = (name, ...overrides) => + Card(name, { + card: { + display: "scalar", + }, + data: { + cols: [NumberColumn({ name: name + "_col0" })], + rows: [[1]] + } + }, ...overrides); + +export const LineCard = (name, ...overrides) => + Card(name, { + card: { + display: "line", + }, + data: { + cols: [StringColumn({ name: name + "_col0" }), NumberColumn({ name: name + "_col1" })], + rows: [["a",0],["b",1]] + } + }, ...overrides); + +export const MultiseriesLineCard = (name, ...overrides) => + Card(name, { + card: { + name: name + "_name", + display: "line", + visualization_settings: {} + }, + data: { + cols: [StringColumn({ name: name + "_col0" }), StringColumn({ name: name + "_col1" }), NumberColumn({ name: name + "_col2" })], + rows: [ + [name + "_cat1", "x", 0], [name + "_cat1", "y", 1], [name + "_cat1", "z", 1], + [name + "_cat2", "x", 2], [name + "_cat2", "y", 3], [name + "_cat2", "z", 4] + ] + } + }, ...overrides); + +function deepExtend(target, ...sources) { + for (const source of sources) { + for (const prop in source) { + if (source.hasOwnProperty(prop)) { + if (target[prop] && typeof target[prop] === 'object' && source[prop] && typeof source[prop] === 'object') { + deepExtend(target[prop], source[prop]); + } else { + target[prop] = source[prop]; + } + } + } + } + return target; +} diff --git a/frontend/test/unit/visualizations/components/Visualization.spec.js b/frontend/test/unit/visualizations/components/Visualization.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..6d9e10fc4cd33fa216a4f1ae1518caf9c32b959b --- /dev/null +++ b/frontend/test/unit/visualizations/components/Visualization.spec.js @@ -0,0 +1,119 @@ + +import React from "react"; +import { renderIntoDocument, scryRenderedComponentsWithType as scryWithType } from "react-addons-test-utils"; + +import Visualization from "metabase/visualizations/components/Visualization.jsx"; + +import LegendHeader from "metabase/visualizations/components/LegendHeader.jsx"; +import LegendItem from "metabase/visualizations/components/LegendItem.jsx"; + +import { ScalarCard, LineCard, MultiseriesLineCard } from "../../support/visualizations"; + +describe("Visualization", () => { + describe("not in dashboard", () => { + describe("scalar card", () => { + it("should not render title", () => { + let viz = renderVisualization({ series: [ScalarCard("Foo")] }); + expect(getTitles(viz)).toEqual([]); + }); + }); + + describe("line card", () => { + it("should not render card title", () => { + let viz = renderVisualization({ series: [LineCard("Foo")] }); + expect(getTitles(viz)).toEqual([]); + }); + it("should not render setting title", () => { + let viz = renderVisualization({ series: [LineCard("Foo", { card: { visualization_settings: { "card.title": "Foo_title" }}})] }); + expect(getTitles(viz)).toEqual([]); + }); + it("should render breakout multiseries titles", () => { + let viz = renderVisualization({ series: [MultiseriesLineCard("Foo")] }); + expect(getTitles(viz)).toEqual([ + ["Foo_cat1", "Foo_cat2"] + ]); + }); + }); + }); + + describe("in dashboard", () => { + describe("scalar card", () => { + it("should not render title", () => { + let viz = renderVisualization({ series: [ScalarCard("Foo")], isDashboard: true }); + expect(getTitles(viz)).toEqual([]); + }); + it("should render title when loading", () => { + let viz = renderVisualization({ series: [ScalarCard("Foo", { data: null })], isDashboard: true }); + expect(getTitles(viz)).toEqual([ + ["Foo_name"] + ]); + }); + it("should render title when there's an error", () => { + let viz = renderVisualization({ series: [ScalarCard("Foo")], isDashboard: true, error: "oops" }); + expect(getTitles(viz)).toEqual([ + ["Foo_name"] + ]); + }); + it("should not render scalar title", () => { + let viz = renderVisualization({ series: [ScalarCard("Foo")], isDashboard: true }); + expect(getTitles(viz)).toEqual([]); + }); + it("should render multi scalar titles", () => { + let viz = renderVisualization({ series: [ScalarCard("Foo"), ScalarCard("Bar")], isDashboard: true }); + expect(getTitles(viz)).toEqual([ + ["Foo_name", "Bar_name"] + ]); + }); + }); + + describe("line card", () => { + it("should render normal title", () => { + let viz = renderVisualization({ series: [LineCard("Foo")], isDashboard: true }); + expect(getTitles(viz)).toEqual([ + ["Foo_name"] + ]); + }); + it("should render normal title and breakout multiseries titles", () => { + let viz = renderVisualization({ series: [MultiseriesLineCard("Foo")], isDashboard: true }); + expect(getTitles(viz)).toEqual([ + ["Foo_name"], + ["Foo_cat1", "Foo_cat2"] + ]); + }); + it("should render dashboard multiseries titles", () => { + let viz = renderVisualization({ series: [LineCard("Foo"), LineCard("Bar")], isDashboard: true }); + expect(getTitles(viz)).toEqual([ + ["Foo_col1", "Bar_col1"] + ]); + }); + it("should render dashboard multiseries titles and chart setting title", () => { + let viz = renderVisualization({ series: [ + LineCard("Foo", { card: { visualization_settings: { "card.title": "Foo_title" }}}), + LineCard("Bar") + ], isDashboard: true }); + expect(getTitles(viz)).toEqual([ + ["Foo_title"], + ["Foo_col1", "Bar_col1"] + ]); + }); + it("should render multiple breakout multiseries titles", () => { + let viz = renderVisualization({ series: [MultiseriesLineCard("Foo"), MultiseriesLineCard("Bar")], isDashboard: true }); + expect(getTitles(viz)).toEqual([ + ["Foo_cat1", "Foo_cat2", "Bar_cat1", "Bar_cat2"] + ]); + }); + }); + }); +}); + +function renderVisualization(props) { + return renderIntoDocument(<Visualization className="spread" {...props} />); +} + +function getTitles(viz) { + return scryWithType(viz, LegendHeader).map(header => + scryWithType(header, LegendItem).map(item => + item.props.title + ) + ); +} diff --git a/frontend/test/unit/visualizations/lib/LineAreaBarRenderer.spec.js b/frontend/test/unit/visualizations/lib/LineAreaBarRenderer.spec.js index cd05e61f9bd43ca9db744958a06454b612f59dd7..e3e5033981c577cb0fc5b1ce86e4018a9dfac329 100644 --- a/frontend/test/unit/visualizations/lib/LineAreaBarRenderer.spec.js +++ b/frontend/test/unit/visualizations/lib/LineAreaBarRenderer.spec.js @@ -4,10 +4,7 @@ import { formatValue } from "metabase/lib/formatting"; import d3 from "d3"; -const Column = (col = {}) => ({ name: "x", display_name: "x", ...col }) -const DateTimeColumn = (col = {}) => Column({ "base_type" : "type/DateTime", "special_type" : null, ...col }) -const NumberColumn = (col = {}) => Column({ "base_type" : "type/Integer", "special_type" : "type/Number", ...col }) - +import { DateTimeColumn, NumberColumn } from "../../support/visualizations"; let formatTz = (offset) => (offset < 0 ? "-" : "+") + d3.format("02d")(Math.abs(offset)) + ":00" diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index eec1867fb945075759187165af153099001c4822..f62012dab799f10d691e4c6f26c038932d6c6de3 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -409,179 +409,6 @@ } } }, - "babel-core": { - "version": "6.17.0", - "dependencies": { - "babel-code-frame": { - "version": "6.16.0", - "dependencies": { - "chalk": { - "version": "1.1.3", - "dependencies": { - "ansi-styles": { - "version": "2.2.1" - }, - "escape-string-regexp": { - "version": "1.0.5" - }, - "has-ansi": { - "version": "2.0.0", - "dependencies": { - "ansi-regex": { - "version": "2.0.0" - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "dependencies": { - "ansi-regex": { - "version": "2.0.0" - } - } - }, - "supports-color": { - "version": "2.0.0" - } - } - }, - "esutils": { - "version": "2.0.2" - }, - "js-tokens": { - "version": "2.0.0" - } - } - }, - "babel-generator": { - "version": "6.17.0", - "dependencies": { - "detect-indent": { - "version": "3.0.1", - "dependencies": { - "get-stdin": { - "version": "4.0.1" - }, - "minimist": { - "version": "1.2.0" - }, - "repeating": { - "version": "1.1.3", - "dependencies": { - "is-finite": { - "version": "1.0.2", - "dependencies": { - "number-is-nan": { - "version": "1.0.1" - } - } - } - } - } - } - }, - "jsesc": { - "version": "1.3.0" - } - } - }, - "babel-helpers": { - "version": "6.16.0" - }, - "babel-messages": { - "version": "6.8.0" - }, - "babel-template": { - "version": "6.16.0" - }, - "babel-traverse": { - "version": "6.16.0", - "dependencies": { - "globals": { - "version": "8.18.0" - }, - "invariant": { - "version": "2.2.1", - "dependencies": { - "loose-envify": { - "version": "1.2.0", - "dependencies": { - "js-tokens": { - "version": "1.0.3" - } - } - } - } - } - } - }, - "babel-types": { - "version": "6.16.0", - "dependencies": { - "esutils": { - "version": "2.0.2" - }, - "to-fast-properties": { - "version": "1.0.2" - } - } - }, - "babylon": { - "version": "6.11.4" - }, - "convert-source-map": { - "version": "1.3.0" - }, - "debug": { - "version": "2.2.0", - "dependencies": { - "ms": { - "version": "0.7.1" - } - } - }, - "json5": { - "version": "0.4.0" - }, - "lodash": { - "version": "4.16.4" - }, - "minimatch": { - "version": "3.0.3", - "dependencies": { - "brace-expansion": { - "version": "1.1.6", - "dependencies": { - "balanced-match": { - "version": "0.4.2" - }, - "concat-map": { - "version": "0.0.1" - } - } - } - } - }, - "path-exists": { - "version": "1.0.0" - }, - "path-is-absolute": { - "version": "1.0.1" - }, - "private": { - "version": "0.1.6" - }, - "shebang-regex": { - "version": "1.0.0" - }, - "slash": { - "version": "1.0.0" - }, - "source-map": { - "version": "0.5.6" - } - } - }, "babel-runtime": { "version": "6.11.6", "dependencies": { @@ -1222,131 +1049,6 @@ "babel-cli": { "version": "6.16.0", "dependencies": { - "babel-core": { - "version": "6.17.0", - "dependencies": { - "babel-code-frame": { - "version": "6.16.0", - "dependencies": { - "esutils": { - "version": "2.0.2" - }, - "js-tokens": { - "version": "2.0.0" - } - } - }, - "babel-generator": { - "version": "6.17.0", - "dependencies": { - "detect-indent": { - "version": "3.0.1", - "dependencies": { - "get-stdin": { - "version": "4.0.1" - }, - "minimist": { - "version": "1.2.0" - }, - "repeating": { - "version": "1.1.3", - "dependencies": { - "is-finite": { - "version": "1.0.2", - "dependencies": { - "number-is-nan": { - "version": "1.0.1" - } - } - } - } - } - } - }, - "jsesc": { - "version": "1.3.0" - } - } - }, - "babel-helpers": { - "version": "6.16.0" - }, - "babel-messages": { - "version": "6.8.0" - }, - "babel-template": { - "version": "6.16.0" - }, - "babel-traverse": { - "version": "6.16.0", - "dependencies": { - "globals": { - "version": "8.18.0" - }, - "invariant": { - "version": "2.2.1", - "dependencies": { - "loose-envify": { - "version": "1.2.0", - "dependencies": { - "js-tokens": { - "version": "1.0.3" - } - } - } - } - } - } - }, - "babel-types": { - "version": "6.16.0", - "dependencies": { - "esutils": { - "version": "2.0.2" - }, - "to-fast-properties": { - "version": "1.0.2" - } - } - }, - "babylon": { - "version": "6.11.4" - }, - "debug": { - "version": "2.2.0", - "dependencies": { - "ms": { - "version": "0.7.1" - } - } - }, - "json5": { - "version": "0.4.0" - }, - "minimatch": { - "version": "3.0.3", - "dependencies": { - "brace-expansion": { - "version": "1.1.6", - "dependencies": { - "balanced-match": { - "version": "0.4.2" - }, - "concat-map": { - "version": "0.0.1" - } - } - } - } - }, - "private": { - "version": "0.1.6" - }, - "shebang-regex": { - "version": "1.0.0" - } - } - }, "babel-runtime": { "version": "6.11.6", "dependencies": { @@ -5681,212 +5383,45 @@ "version": "6.11.6", "dependencies": { "core-js": { - "version": "2.4.1" - }, - "regenerator-runtime": { - "version": "0.9.5" - } - } - } - } - }, - "babel-plugin-transform-object-rest-spread": { - "version": "6.16.0", - "dependencies": { - "babel-plugin-syntax-object-rest-spread": { - "version": "6.13.0" - }, - "babel-runtime": { - "version": "6.11.6", - "dependencies": { - "core-js": { - "version": "2.4.1" - }, - "regenerator-runtime": { - "version": "0.9.5" - } - } - } - } - } - } - } - } - } - } - } - } - }, - "babel-register": { - "version": "6.16.3", - "dependencies": { - "babel-core": { - "version": "6.17.0", - "dependencies": { - "babel-code-frame": { - "version": "6.16.0", - "dependencies": { - "chalk": { - "version": "1.1.3", - "dependencies": { - "ansi-styles": { - "version": "2.2.1" - }, - "escape-string-regexp": { - "version": "1.0.5" - }, - "has-ansi": { - "version": "2.0.0", - "dependencies": { - "ansi-regex": { - "version": "2.0.0" - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "dependencies": { - "ansi-regex": { - "version": "2.0.0" + "version": "2.4.1" + }, + "regenerator-runtime": { + "version": "0.9.5" + } + } } } }, - "supports-color": { - "version": "2.0.0" - } - } - }, - "esutils": { - "version": "2.0.2" - }, - "js-tokens": { - "version": "2.0.0" - } - } - }, - "babel-generator": { - "version": "6.17.0", - "dependencies": { - "detect-indent": { - "version": "3.0.1", - "dependencies": { - "get-stdin": { - "version": "4.0.1" - }, - "minimist": { - "version": "1.2.0" - }, - "repeating": { - "version": "1.1.3", + "babel-plugin-transform-object-rest-spread": { + "version": "6.16.0", "dependencies": { - "is-finite": { - "version": "1.0.2", + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0" + }, + "babel-runtime": { + "version": "6.11.6", "dependencies": { - "number-is-nan": { - "version": "1.0.1" + "core-js": { + "version": "2.4.1" + }, + "regenerator-runtime": { + "version": "0.9.5" } } } } } } - }, - "jsesc": { - "version": "1.3.0" - } - } - }, - "babel-helpers": { - "version": "6.16.0" - }, - "babel-messages": { - "version": "6.8.0" - }, - "babel-template": { - "version": "6.16.0" - }, - "babel-traverse": { - "version": "6.16.0", - "dependencies": { - "globals": { - "version": "8.18.0" - }, - "invariant": { - "version": "2.2.1", - "dependencies": { - "loose-envify": { - "version": "1.2.0", - "dependencies": { - "js-tokens": { - "version": "1.0.3" - } - } - } - } - } - } - }, - "babel-types": { - "version": "6.16.0", - "dependencies": { - "esutils": { - "version": "2.0.2" - }, - "to-fast-properties": { - "version": "1.0.2" - } - } - }, - "babylon": { - "version": "6.11.4" - }, - "convert-source-map": { - "version": "1.3.0" - }, - "debug": { - "version": "2.2.0", - "dependencies": { - "ms": { - "version": "0.7.1" - } - } - }, - "json5": { - "version": "0.4.0" - }, - "minimatch": { - "version": "3.0.3", - "dependencies": { - "brace-expansion": { - "version": "1.1.6", - "dependencies": { - "balanced-match": { - "version": "0.4.2" - }, - "concat-map": { - "version": "0.0.1" - } - } } } - }, - "path-is-absolute": { - "version": "1.0.1" - }, - "private": { - "version": "0.1.6" - }, - "shebang-regex": { - "version": "1.0.0" - }, - "slash": { - "version": "1.0.0" - }, - "source-map": { - "version": "0.5.6" } } - }, + } + } + }, + "babel-register": { + "version": "6.16.3", + "dependencies": { "babel-runtime": { "version": "6.11.6", "dependencies": { @@ -11480,141 +11015,6 @@ "systemjs-builder": { "version": "0.15.32", "dependencies": { - "babel-core": { - "version": "6.17.0", - "dependencies": { - "babel-code-frame": { - "version": "6.16.0", - "dependencies": { - "esutils": { - "version": "2.0.2" - }, - "js-tokens": { - "version": "2.0.0" - } - } - }, - "babel-generator": { - "version": "6.17.0", - "dependencies": { - "detect-indent": { - "version": "3.0.1", - "dependencies": { - "get-stdin": { - "version": "4.0.1" - }, - "minimist": { - "version": "1.2.0" - }, - "repeating": { - "version": "1.1.3", - "dependencies": { - "is-finite": { - "version": "1.0.2", - "dependencies": { - "number-is-nan": { - "version": "1.0.1" - } - } - } - } - } - } - }, - "jsesc": { - "version": "1.3.0" - } - } - }, - "babel-helpers": { - "version": "6.16.0" - }, - "babel-messages": { - "version": "6.8.0" - }, - "babel-runtime": { - "version": "6.11.6", - "dependencies": { - "core-js": { - "version": "2.4.1" - }, - "regenerator-runtime": { - "version": "0.9.5" - } - } - }, - "babel-template": { - "version": "6.16.0" - }, - "babel-traverse": { - "version": "6.16.0", - "dependencies": { - "globals": { - "version": "8.18.0" - }, - "invariant": { - "version": "2.2.1", - "dependencies": { - "loose-envify": { - "version": "1.2.0", - "dependencies": { - "js-tokens": { - "version": "1.0.3" - } - } - } - } - } - } - }, - "babel-types": { - "version": "6.16.0", - "dependencies": { - "esutils": { - "version": "2.0.2" - }, - "to-fast-properties": { - "version": "1.0.2" - } - } - }, - "babylon": { - "version": "6.11.4" - }, - "convert-source-map": { - "version": "1.3.0" - }, - "debug": { - "version": "2.2.0", - "dependencies": { - "ms": { - "version": "0.7.1" - } - } - }, - "json5": { - "version": "0.4.0" - }, - "lodash": { - "version": "4.16.4" - }, - "path-exists": { - "version": "1.0.0" - }, - "path-is-absolute": { - "version": "1.0.1" - }, - "private": { - "version": "0.1.6" - }, - "shebang-regex": { - "version": "1.0.0" - }, - "slash": { - "version": "1.0.0" - } - } - }, "babel-plugin-transform-cjs-system-wrapper": { "version": "0.2.1", "dependencies": { @@ -12448,6 +11848,9 @@ "react-addons-shallow-compare": { "version": "15.3.2" }, + "react-addons-test-utils": { + "version": "15.3.1" + }, "react-ansi-style": { "version": "1.0.0", "dependencies": { @@ -12846,7 +12249,7 @@ "version": "2.5.4", "dependencies": { "glob": { - "version": "7.1.0", + "version": "7.1.1", "dependencies": { "fs.realpath": { "version": "1.0.0" diff --git a/package.json b/package.json index 77dbb22a9a91feeb5ddc42bf0f0e3eec12795d29..c43ada6b61a21b8ec62a9bbf524f7fdc0fc2e62c 100644 --- a/package.json +++ b/package.json @@ -115,6 +115,7 @@ "postcss-import": "^8.0.2", "postcss-loader": "^0.8.1", "postcss-url": "^5.1.1", + "react-addons-test-utils": "^15.3.1", "react-hot-loader": "^1.3.0", "sauce-connect-launcher": "^0.15.1", "selenium-webdriver": "^2.53.3",