Use Enzyme to test ContributionList dynamics (#102)

Summary:
This is our first dynamic test of a React component! Enzyme looks pretty
easy to use to me, for both snapshot tests and interaction simulation.

In doing so, we catch a minor bug in the edge case where a contribution
is not owned by any plugin (`colSpan`, not `colspan`). This edge case
does not appear in the sample data, but it does appear in the test data,
even prior to this commit. The previous renderer, `react-test-renderer`,
appears not to surface this error. Furthermore, this bug did not cause
any user-visible errors except a `console.error`.

Test Plan:
Inspect the snapshot file to make sure that it is reasonable. (The
existing test case has its snapshot regenerated due to formatting
differences between the two renderers.)

To test that the browser error is fixed, render a contribution list on a
GitHub graph but with an empty adapter set. One way to do this is to comment out line 7 of
`standardAdapterSet.js`; alternately, you can use the React Dev Tools to
select the `ContributionList` node, then run
```js
$r.props.adapters.adapters = {};
$r.forceUpdate();
```
Note subsequently that there is no console error and that the `<td>`s in
question span three columns.

wchargin-branch: contributionlist-dynamic-test
This commit is contained in:
William Chargin 2018-03-21 17:35:17 -07:00 committed by GitHub
parent 5dd5de306c
commit feac85ad2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 662 additions and 138 deletions

View File

@ -114,6 +114,9 @@
"extends": "react-app"
},
"devDependencies": {
"babel-plugin-flow-react-proptypes": "^18.0.0"
"babel-plugin-flow-react-proptypes": "^18.0.0",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"enzyme-to-json": "^3.3.3"
}
}

View File

@ -119,7 +119,7 @@ export class ContributionList extends React.Component<Props, State> {
if (adapter == null) {
return (
<tr key={JSON.stringify(node.address)}>
<td colspan={3}>
<td colSpan={3}>
<i>unknown</i> (plugin: {node.address.pluginName})
</td>
</tr>

View File

@ -1,8 +1,9 @@
// @flow
import type {ReactWrapper} from "enzyme";
import React from "react";
import ReactDOM from "react-dom";
import reactTestRenderer from "react-test-renderer";
import {mount} from "enzyme";
import enzymeToJSON from "enzyme-to-json";
import type {Address} from "../../../core/address";
import type {Node} from "../../../core/graph";
@ -12,6 +13,7 @@ import {ContributionList} from "./ContributionList";
import {Graph} from "../../../core/graph";
require("./testUtil").configureAphrodite();
require("./testUtil").configureEnzyme();
function createTestData(): * {
type PayloadA = number;
@ -152,11 +154,45 @@ function createTestData(): * {
}
describe("ContributionList", () => {
it("renders some test data in the default state", () => {
// Render a contribution list with the above test data.
function render() {
const data = createTestData();
const result = reactTestRenderer.create(
const result = mount(
<ContributionList graph={data.graph()} adapters={data.adapters()} />
);
expect(result).toMatchSnapshot();
return result;
}
// Select the unique <option> whose text matches the given patern.
function simulateSelect(container: ReactWrapper, pattern: RegExp): void {
const targetOption = container
.find("option")
.filterWhere((x) => pattern.test(x.text()));
expect(targetOption).toHaveLength(1);
container
.find("select")
.simulate("change", {target: {value: targetOption.prop("value")}});
}
it("renders some test data in the default state", () => {
const result = render();
expect(enzymeToJSON(result)).toMatchSnapshot();
});
it("updates the node table when a filter is selected", () => {
const result = render();
simulateSelect(result, /small/);
expect(enzymeToJSON(result)).toMatchSnapshot();
});
it("resets the node table when a filter is deselected", () => {
const result = render();
const originalHtml = result.html();
simulateSelect(result, /big/);
const intermediateHtml = result.html();
simulateSelect(result, /Show all/);
const finalHtml = result.html();
expect(finalHtml).toEqual(originalHtml);
expect(finalHtml).not.toEqual(intermediateHtml);
});
});

View File

@ -1,6 +1,75 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ContributionList renders some test data in the default state 1`] = `
<ContributionList
adapters={
AdapterSet {
"adapters": Object {
"sourcecred/example-plugin-a": Object {
"extractTitle": [Function],
"extractType": [Function],
"pluginName": "sourcecred/example-plugin-a",
"renderer": [Function],
},
"sourcecred/example-plugin-b": Object {
"extractTitle": [Function],
"extractType": [Function],
"pluginName": "sourcecred/example-plugin-b",
"renderer": [Function],
},
},
}
}
graph={
Object {
"edges": Object {
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"id\\":\\"one-to-two\\"}": Object {
"dst": Object {
"id": "two",
"pluginName": "sourcecred/example-plugin-a",
"repositoryName": "sourcecred/tests",
},
"payload": null,
"src": Object {
"id": "one",
"pluginName": "sourcecred/example-plugin-a",
"repositoryName": "sourcecred/tests",
},
},
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-c\\",\\"id\\":\\"four-to-three\\"}": Object {
"dst": Object {
"id": "three",
"pluginName": "sourcecred/example-plugin-a",
"repositoryName": "sourcecred/tests",
},
"payload": null,
"src": Object {
"id": "four",
"pluginName": "sourcecred/example-plugin-b",
"repositoryName": "sourcecred/tests",
},
},
},
"nodes": Object {
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"id\\":\\"one\\"}": Object {
"payload": 111,
},
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"id\\":\\"three\\"}": Object {
"payload": 616,
},
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"id\\":\\"two\\"}": Object {
"payload": 234,
},
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-b\\",\\"id\\":\\"four\\"}": Object {
"payload": true,
},
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-c\\",\\"id\\":\\"five\\"}": Object {
"payload": "I have no adapter :-(",
},
},
}
}
>
<div>
<h2>
Contributions
@ -19,6 +88,7 @@ exports[`ContributionList renders some test data in the default state 1`] = `
</option>
<option
disabled={true}
key="sourcecred/example-plugin-a"
style={
Object {
"fontWeight": "bold",
@ -28,17 +98,20 @@ exports[`ContributionList renders some test data in the default state 1`] = `
sourcecred/example-plugin-a
</option>
<option
key="big"
value="{\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"type\\":\\"big\\"}"
>
big
</option>
<option
key="small"
value="{\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"type\\":\\"small\\"}"
>
small
</option>
<option
disabled={true}
key="sourcecred/example-plugin-b"
style={
Object {
"fontWeight": "bold",
@ -48,6 +121,7 @@ exports[`ContributionList renders some test data in the default state 1`] = `
sourcecred/example-plugin-b
</option>
<option
key="very true"
value="{\\"pluginName\\":\\"sourcecred/example-plugin-b\\",\\"type\\":\\"very true\\"}"
>
very true
@ -69,7 +143,9 @@ exports[`ContributionList renders some test data in the default state 1`] = `
</tr>
</thead>
<tbody>
<tr>
<tr
key="{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"id\\":\\"one\\"}"
>
<td>
the number 111
</td>
@ -80,7 +156,9 @@ exports[`ContributionList renders some test data in the default state 1`] = `
[TODO]
</td>
</tr>
<tr>
<tr
key="{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"id\\":\\"two\\"}"
>
<td>
the number 234
</td>
@ -91,7 +169,9 @@ exports[`ContributionList renders some test data in the default state 1`] = `
[TODO]
</td>
</tr>
<tr>
<tr
key="{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"id\\":\\"three\\"}"
>
<td>
the number 616
</td>
@ -102,7 +182,9 @@ exports[`ContributionList renders some test data in the default state 1`] = `
[TODO]
</td>
</tr>
<tr>
<tr
key="{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-b\\",\\"id\\":\\"four\\"}"
>
<td>
TRUE!
</td>
@ -113,9 +195,11 @@ exports[`ContributionList renders some test data in the default state 1`] = `
[TODO]
</td>
</tr>
<tr>
<tr
key="{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-c\\",\\"id\\":\\"five\\"}"
>
<td
colspan={3}
colSpan={3}
>
<i>
unknown
@ -128,4 +212,180 @@ exports[`ContributionList renders some test data in the default state 1`] = `
</tbody>
</table>
</div>
</ContributionList>
`;
exports[`ContributionList updates the node table when a filter is selected 1`] = `
<ContributionList
adapters={
AdapterSet {
"adapters": Object {
"sourcecred/example-plugin-a": Object {
"extractTitle": [Function],
"extractType": [Function],
"pluginName": "sourcecred/example-plugin-a",
"renderer": [Function],
},
"sourcecred/example-plugin-b": Object {
"extractTitle": [Function],
"extractType": [Function],
"pluginName": "sourcecred/example-plugin-b",
"renderer": [Function],
},
},
}
}
graph={
Object {
"edges": Object {
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"id\\":\\"one-to-two\\"}": Object {
"dst": Object {
"id": "two",
"pluginName": "sourcecred/example-plugin-a",
"repositoryName": "sourcecred/tests",
},
"payload": null,
"src": Object {
"id": "one",
"pluginName": "sourcecred/example-plugin-a",
"repositoryName": "sourcecred/tests",
},
},
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-c\\",\\"id\\":\\"four-to-three\\"}": Object {
"dst": Object {
"id": "three",
"pluginName": "sourcecred/example-plugin-a",
"repositoryName": "sourcecred/tests",
},
"payload": null,
"src": Object {
"id": "four",
"pluginName": "sourcecred/example-plugin-b",
"repositoryName": "sourcecred/tests",
},
},
},
"nodes": Object {
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"id\\":\\"one\\"}": Object {
"payload": 111,
},
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"id\\":\\"three\\"}": Object {
"payload": 616,
},
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"id\\":\\"two\\"}": Object {
"payload": 234,
},
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-b\\",\\"id\\":\\"four\\"}": Object {
"payload": true,
},
"{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-c\\",\\"id\\":\\"five\\"}": Object {
"payload": "I have no adapter :-(",
},
},
}
}
>
<div>
<h2>
Contributions
</h2>
<label>
Filter by contribution type:
<select
onChange={[Function]}
value="{\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"type\\":\\"small\\"}"
>
<option
value="null"
>
Show all
</option>
<option
disabled={true}
key="sourcecred/example-plugin-a"
style={
Object {
"fontWeight": "bold",
}
}
>
sourcecred/example-plugin-a
</option>
<option
key="big"
value="{\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"type\\":\\"big\\"}"
>
big
</option>
<option
key="small"
value="{\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"type\\":\\"small\\"}"
>
small
</option>
<option
disabled={true}
key="sourcecred/example-plugin-b"
style={
Object {
"fontWeight": "bold",
}
}
>
sourcecred/example-plugin-b
</option>
<option
key="very true"
value="{\\"pluginName\\":\\"sourcecred/example-plugin-b\\",\\"type\\":\\"very true\\"}"
>
very true
</option>
</select>
</label>
<table>
<thead>
<tr>
<th>
Title
</th>
<th>
Artifact
</th>
<th>
Weight
</th>
</tr>
</thead>
<tbody>
<tr
key="{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"id\\":\\"one\\"}"
>
<td>
the number 111
</td>
<td>
[TODO]
</td>
<td>
[TODO]
</td>
</tr>
<tr
key="{\\"repositoryName\\":\\"sourcecred/tests\\",\\"pluginName\\":\\"sourcecred/example-plugin-a\\",\\"id\\":\\"two\\"}"
>
<td>
the number 234
</td>
<td>
[TODO]
</td>
<td>
[TODO]
</td>
</tr>
</tbody>
</table>
</div>
</ContributionList>
`;

View File

@ -1,6 +1,13 @@
import {StyleSheetTestUtils} from "aphrodite/no-important";
// @flow
export function configureEnzyme() {
const Enzyme = require("enzyme");
const Adapter = require("enzyme-adapter-react-16");
Enzyme.configure({adapter: new Adapter()});
}
export function configureAphrodite() {
const {StyleSheetTestUtils} = require("aphrodite/no-important");
beforeEach(() => {
StyleSheetTestUtils.suppressStyleInjection();
});

236
yarn.lock
View File

@ -2,6 +2,10 @@
# yarn lockfile v1
"@types/node@*":
version "9.4.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.7.tgz#57d81cd98719df2c9de118f2d5f3b1120dcd7275"
abab@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e"
@ -1316,6 +1320,17 @@ chardet@^0.4.0:
version "0.4.2"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
cheerio@^1.0.0-rc.2:
version "1.0.0-rc.2"
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db"
dependencies:
css-select "~1.2.0"
dom-serializer "~0.1.0"
entities "~1.1.1"
htmlparser2 "^3.9.1"
lodash "^4.15.0"
parse5 "^3.0.1"
chokidar@^1.6.0, chokidar@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
@ -1455,6 +1470,10 @@ colormin@^1.0.5:
css-color-names "0.0.4"
has "^1.0.1"
colors@0.5.x:
version "0.5.1"
resolved "https://registry.yarnpkg.com/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774"
colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
@ -1699,7 +1718,7 @@ css-loader@0.28.7:
postcss-value-parser "^3.3.0"
source-list-map "^2.0.0"
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:
@ -1940,6 +1959,10 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0"
randombytes "^2.0.0"
discontinuous-range@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
dns-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
@ -1976,7 +1999,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:
@ -1993,7 +2016,7 @@ domain-browser@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
domelementtype@1:
domelementtype@1, domelementtype@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2"
@ -2007,6 +2030,12 @@ 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"
@ -2020,6 +2049,13 @@ domutils@1.5.1:
dom-serializer "0"
domelementtype "1"
domutils@^1.5.1:
version "1.7.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
dependencies:
dom-serializer "0"
domelementtype "1"
dot-prop@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
@ -2099,10 +2135,57 @@ enhanced-resolve@^3.4.0:
object-assign "^4.0.1"
tapable "^0.2.7"
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-adapter-react-16@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.1.1.tgz#a8f4278b47e082fbca14f5bfb1ee50ee650717b4"
dependencies:
enzyme-adapter-utils "^1.3.0"
lodash "^4.17.4"
object.assign "^4.0.4"
object.values "^1.0.4"
prop-types "^15.6.0"
react-reconciler "^0.7.0"
react-test-renderer "^16.0.0-0"
enzyme-adapter-utils@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.3.0.tgz#d6c85756826c257a8544d362cc7a67e97ea698c7"
dependencies:
lodash "^4.17.4"
object.assign "^4.0.4"
prop-types "^15.6.0"
enzyme-to-json@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/enzyme-to-json/-/enzyme-to-json-3.3.3.tgz#ede45938fb309cd87ebd4386f60c754525515a07"
dependencies:
lodash "^4.17.4"
enzyme@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.3.0.tgz#0971abd167f2d4bf3f5bd508229e1c4b6dc50479"
dependencies:
cheerio "^1.0.0-rc.2"
function.prototype.name "^1.0.3"
has "^1.0.1"
is-boolean-object "^1.0.0"
is-callable "^1.1.3"
is-number-object "^1.0.3"
is-string "^1.0.4"
is-subset "^0.1.1"
lodash "^4.17.4"
object-inspect "^1.5.0"
object-is "^1.0.1"
object.assign "^4.1.0"
object.entries "^1.0.4"
object.values "^1.0.4"
raf "^3.4.0"
rst-selector-parser "^2.2.3"
errno@^0.1.3, errno@^0.1.4:
version "0.1.6"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.6.tgz#c386ce8a6283f14fc09563b71560908c9bf53026"
@ -2115,7 +2198,7 @@ error-ex@^1.2.0, error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
es-abstract@^1.7.0:
es-abstract@^1.6.1, es-abstract@^1.7.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864"
dependencies:
@ -2784,10 +2867,18 @@ fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
mkdirp ">=0.5 0"
rimraf "2"
function-bind@^1.0.2, function-bind@^1.1.1:
function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
function.prototype.name@^1.0.3:
version "1.1.0"
resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.0.tgz#8bd763cc0af860a859cc5d49384d74b932cd2327"
dependencies:
define-properties "^1.1.2"
function-bind "^1.1.1"
is-callable "^1.1.3"
functional-red-black-tree@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
@ -2980,6 +3071,10 @@ has-flag@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
has-symbols@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
has-unicode@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@ -3112,6 +3207,17 @@ html-webpack-plugin@2.29.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"
@ -3328,6 +3434,10 @@ is-binary-path@^1.0.0:
dependencies:
binary-extensions "^1.0.0"
is-boolean-object@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.0.tgz#98f8b28030684219a95f375cfbd88ce3405dff93"
is-buffer@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
@ -3423,6 +3533,10 @@ is-npm@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
is-number-object@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.3.tgz#f265ab89a9f445034ef6aff15a8f00b00f551799"
is-number@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
@ -3507,6 +3621,14 @@ 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-string@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.4.tgz#cc3a9b69857d621e963725a24caeec873b826e64"
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"
@ -4168,6 +4290,10 @@ lodash.defaults@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
lodash.flattendeep@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
@ -4449,6 +4575,15 @@ ncname@1.0.x:
dependencies:
xml-char-classes "^1.0.0"
nearley@^2.7.10:
version "2.13.0"
resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.13.0.tgz#6e7b0f4e68bfc3e74c99eaef2eda39e513143439"
dependencies:
nomnom "~1.6.2"
railroad-diagrams "^1.0.0"
randexp "0.4.6"
semver "^5.4.1"
negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
@ -4527,6 +4662,13 @@ node-pre-gyp@^0.6.39:
tar "^2.2.1"
tar-pack "^3.4.0"
nomnom@~1.6.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.6.2.tgz#84a66a260174408fc5b77a18f888eccc44fb6971"
dependencies:
colors "0.5.x"
underscore "~1.4.4"
nopt@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
@ -4625,10 +4767,36 @@ object-hash@^1.1.4:
version "1.2.0"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.2.0.tgz#e96af0e96981996a1d47f88ead8f74f1ebc4422b"
object-keys@^1.0.8:
object-inspect@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.5.0.tgz#9d876c11e40f485c79215670281b767488f9bfe3"
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.11, object-keys@^1.0.8:
version "1.0.11"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
object.assign@^4.0.4, object.assign@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
dependencies:
define-properties "^1.1.2"
function-bind "^1.1.1"
has-symbols "^1.0.0"
object-keys "^1.0.11"
object.entries@^1.0.4:
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"
@ -4636,6 +4804,15 @@ object.omit@^2.0.0:
for-own "^0.1.4"
is-extendable "^0.1.1"
object.values@^1.0.4:
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.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e"
@ -4821,6 +4998,12 @@ parse5@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
parse5@^3.0.1:
version "3.0.3"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
dependencies:
"@types/node" "*"
parseurl@~1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
@ -5368,12 +5551,23 @@ querystringify@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb"
raf@3.4.0:
raf@3.4.0, raf@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.0.tgz#a28876881b4bc2ca9117d4138163ddb80f781575"
dependencies:
performance-now "^2.1.0"
railroad-diagrams@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
randexp@0.4.6:
version "0.4.6"
resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3"
dependencies:
discontinuous-range "1.0.0"
ret "~0.1.10"
randomatic@^1.1.3:
version "1.1.7"
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c"
@ -5452,7 +5646,16 @@ react-error-overlay@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4"
react-test-renderer@^16.2.0:
react-reconciler@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.7.0.tgz#9614894103e5f138deeeb5eabaf3ee80eb1d026d"
dependencies:
fbjs "^0.8.16"
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.0"
react-test-renderer@^16.0.0-0, react-test-renderer@^16.2.0:
version "16.2.0"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.2.0.tgz#bddf259a6b8fcd8555f012afc8eacc238872a211"
dependencies:
@ -5775,6 +5978,10 @@ restore-cursor@^2.0.0:
onetime "^2.0.0"
signal-exit "^3.0.2"
ret@~0.1.10:
version "0.1.15"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
right-align@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
@ -5794,6 +6001,13 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
hash-base "^2.0.0"
inherits "^2.0.1"
rst-selector-parser@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz#81b230ea2fcc6066c89e3472de794285d9b03d91"
dependencies:
lodash.flattendeep "^4.4.0"
nearley "^2.7.10"
run-async@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
@ -6486,6 +6700,10 @@ uid-number@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
underscore@~1.4.4:
version "1.4.4"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.4.4.tgz#61a6a32010622afa07963bf325203cf12239d604"
uniq@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"