Add unit tests for react-app (#6234)

* Add MetricFormat unit tests

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add App unit tests; Add debug script

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add Checkbox unit tests

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add SeriesName unit tests

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add QueryStatsView unit test

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add Legend unit tests

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Remove unused utils/func

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add utils/urlParams unit test

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add utils/timeFormat unit test

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add ExpressionInput unit tests

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add GraphControls unit test

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add TimeInput unit test

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add DataTable unit test

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add SanitizeHTML unit test

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add Graph unit test

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Extract utils/html

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add PanelList unit test

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add Panel unit test

Signed-off-by: Dustin Hooten <dhooten@splunk.com>

* Add react-ui test coverage report to CI

Signed-off-by: Dustin Hooten <dhooten@splunk.com>
This commit is contained in:
Dustin Hooten 2019-10-28 11:09:48 -06:00 committed by Julius Volz
parent 8340db5614
commit e0443e6fa3
29 changed files with 1751 additions and 75 deletions

View file

@ -60,7 +60,7 @@ react-app-lint-fix:
.PHONY: react-app-test
react-app-test: | $(REACT_APP_NODE_MODULES_PATH) react-app-lint
@echo ">> running React app tests"
cd $(REACT_APP_PATH) && yarn test --no-watch
cd $(REACT_APP_PATH) && yarn test --no-watch --coverage
.PHONY: test
test: common-test react-app-test

View file

@ -7,7 +7,7 @@
"@fortawesome/free-solid-svg-icons": "^5.7.1",
"@fortawesome/react-fontawesome": "^0.1.4",
"@reach/router": "^1.2.1",
"@types/jest": "^24.0.4",
"@types/jest": "^24.0.20",
"@types/jquery": "^3.3.29",
"@types/node": "^12.11.1",
"@types/reach__router": "^1.2.6",
@ -42,6 +42,7 @@
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"test:debug": "react-scripts --inspect-brk test --runInBand --no-cache",
"eject": "react-scripts eject",
"lint:ci": "eslint --quiet \"src/**/*.{ts,tsx}\"",
"lint": "eslint --fix \"src/**/*.{ts,tsx}\""
@ -58,6 +59,8 @@
"not op_mini all"
],
"devDependencies": {
"@types/enzyme": "^3.10.3",
"@types/enzyme-adapter-react-16": "^1.0.5",
"@types/flot": "0.0.31",
"@types/moment-timezone": "^0.5.10",
"@types/reactstrap": "^8.0.5",
@ -73,7 +76,11 @@
"eslint-plugin-prettier": "^3.1.1",
"eslint-plugin-react": "7.x",
"eslint-plugin-react-hooks": "1.x",
"prettier": "^1.18.2"
"prettier": "^1.18.2",
"@types/sinon": "^7.5.0",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.15.1",
"sinon": "^7.5.0"
},
"proxy": "http://localhost:9090"
}

View file

@ -1,10 +0,0 @@
import './globals';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});

View file

@ -0,0 +1,22 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import App from './App';
import Navigation from './Navbar';
import { Container } from 'reactstrap';
import { Router } from '@reach/router';
import { Alerts, Config, Flags, Rules, Services, Status, Targets, PanelList } from './pages';
describe('App', () => {
const app = shallow(<App />);
it('navigates', () => {
expect(app.find(Navigation)).toHaveLength(1);
});
it('routes', () => {
[Alerts, Config, Flags, Rules, Services, Status, Targets, PanelList].forEach(component =>
expect(app.find(component)).toHaveLength(1)
);
expect(app.find(Router)).toHaveLength(1);
expect(app.find(Container)).toHaveLength(1);
});
});

View file

@ -0,0 +1,65 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import Checkbox from './Checkbox';
import { FormGroup, Label, Input } from 'reactstrap';
const MockCmp: React.FC = () => <div className="mock" />;
describe('Checkbox', () => {
it('renders with subcomponents', () => {
const checkBox = shallow(<Checkbox />);
[FormGroup, Input, Label].forEach(component => expect(checkBox.find(component)).toHaveLength(1));
});
it('passes down the correct FormGroup props', () => {
const checkBoxProps = { wrapperStyles: { color: 'orange' } };
const checkBox = shallow(<Checkbox {...checkBoxProps} />);
const formGroup = checkBox.find(FormGroup);
expect(Object.keys(formGroup.props())).toHaveLength(4);
expect(formGroup.prop('className')).toEqual('custom-control custom-checkbox');
expect(formGroup.prop('children')).toHaveLength(2);
expect(formGroup.prop('style')).toEqual({ color: 'orange' });
expect(formGroup.prop('tag')).toEqual('div');
});
it('passes down the correct FormGroup Input props', () => {
const results: string[] = [];
const checkBoxProps = {
onChange: (): void => {
results.push('clicked');
},
};
const checkBox = shallow(<Checkbox {...checkBoxProps} id="1" />);
const input = checkBox.find(Input);
expect(Object.keys(input.props())).toHaveLength(4);
expect(input.prop('className')).toEqual('custom-control-input');
expect(input.prop('id')).toMatch('1');
expect(input.prop('type')).toEqual('checkbox');
input.simulate('change');
expect(results).toHaveLength(1);
expect(results[0]).toEqual('clicked');
});
it('passes down the correct Label props', () => {
const checkBox = shallow(
<Checkbox id="1">
<MockCmp />
</Checkbox>
);
const label = checkBox.find(Label);
expect(Object.keys(label.props())).toHaveLength(6);
expect(label.prop('className')).toEqual('custom-control-label');
expect(label.find(MockCmp)).toHaveLength(1);
expect(label.prop('for')).toMatch('1');
expect(label.prop('style')).toEqual({ userSelect: 'none' });
expect(label.prop('tag')).toEqual('label');
});
it('shares checkbox `id` uuid with Input/Label subcomponents', () => {
const checkBox = shallow(<Checkbox id="2" />);
const input = checkBox.find(Input);
const label = checkBox.find(Label);
expect(label.prop('for')).toBeDefined();
expect(label.prop('for')).toEqual(input.prop('id'));
});
});

View file

@ -0,0 +1,267 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import DataTable, { QueryResult } from './DataTable';
import { Alert, Table } from 'reactstrap';
import SeriesName from './SeriesName';
describe('DataTable', () => {
describe('when data is null', () => {
it('renders an alert', () => {
const table = shallow(<DataTable data={null} />);
const alert = table.find(Alert);
expect(Object.keys(alert.props())).toHaveLength(7);
expect(alert.prop('color')).toEqual('light');
expect(alert.prop('children')).toEqual('No data queried yet');
});
});
describe('when data.result is empty', () => {
it('renders an alert', () => {
const dataTableProps: QueryResult = {
data: {
resultType: 'vector',
result: [],
},
};
const table = shallow(<DataTable {...dataTableProps} />);
const alert = table.find(Alert);
expect(Object.keys(alert.props())).toHaveLength(7);
expect(alert.prop('color')).toEqual('secondary');
expect(alert.prop('children')).toEqual('Empty query result');
});
});
describe('when resultType is a vector with values', () => {
const dataTableProps: QueryResult = {
data: {
resultType: 'vector',
result: [
{
metric: {
__name__: 'metric_name_1',
label1: 'value_1',
labeln: 'value_n',
},
value: [1572098246.599, '0'],
},
{
metric: {
__name__: 'metric_name_2',
label1: 'value_1',
labeln: 'value_n',
},
value: [1572098246.599, '1'],
},
],
},
};
const dataTable = shallow(<DataTable {...dataTableProps} />);
it('renders a table', () => {
const table = dataTable.find(Table);
expect(table.prop('hover')).toBe(true);
expect(table.prop('size')).toEqual('sm');
expect(table.prop('className')).toEqual('data-table');
expect(table.find('tbody')).toHaveLength(1);
});
it('renders rows', () => {
const table = dataTable.find(Table);
table.find('tr').forEach((row, idx) => {
expect(row.find(SeriesName)).toHaveLength(1);
expect(
row
.find('td')
.at(1)
.text()
).toEqual(`${idx}`);
});
});
});
describe('when resultType is a vector with too many values', () => {
const dataTableProps: QueryResult = {
data: {
resultType: 'vector',
result: Array.from(Array(10001).keys()).map(i => {
return {
metric: {
__name__: `metric_name_${i}`,
label1: 'value_1',
labeln: 'value_n',
},
value: [1572098246.599, `${i}`],
};
}),
},
};
const dataTable = shallow(<DataTable {...dataTableProps} />);
it('renders limited rows', () => {
const table = dataTable.find(Table);
expect(table.find('tr')).toHaveLength(10000);
});
it('renders a warning', () => {
const alert = dataTable.find(Alert);
expect(alert.render().text()).toEqual('Warning: Fetched 10001 metrics, only displaying first 10000.');
});
});
describe('when result type is a matrix', () => {
const dataTableProps: QueryResult = {
data: {
resultType: 'matrix',
result: [
{
metric: {
__name__: 'promhttp_metric_handler_requests_total',
code: '200',
instance: 'localhost:9090',
job: 'prometheus',
},
values: [
[1572097950.93, '9'],
[1572097965.931, '10'],
[1572097980.929, '11'],
[1572097995.931, '12'],
[1572098010.932, '13'],
[1572098025.933, '14'],
[1572098040.93, '15'],
[1572098055.93, '16'],
[1572098070.93, '17'],
[1572098085.936, '18'],
[1572098100.936, '19'],
[1572098115.933, '20'],
[1572098130.932, '21'],
[1572098145.932, '22'],
[1572098160.933, '23'],
[1572098175.934, '24'],
[1572098190.937, '25'],
[1572098205.934, '26'],
[1572098220.933, '27'],
[1572098235.934, '28'],
],
},
{
metric: {
__name__: 'promhttp_metric_handler_requests_total',
code: '500',
instance: 'localhost:9090',
job: 'prometheus',
},
values: [
[1572097950.93, '0'],
[1572097965.931, '0'],
[1572097980.929, '0'],
[1572097995.931, '0'],
[1572098010.932, '0'],
[1572098025.933, '0'],
[1572098040.93, '0'],
[1572098055.93, '0'],
[1572098070.93, '0'],
[1572098085.936, '0'],
[1572098100.936, '0'],
[1572098115.933, '0'],
[1572098130.932, '0'],
[1572098145.932, '0'],
[1572098160.933, '0'],
[1572098175.934, '0'],
[1572098190.937, '0'],
[1572098205.934, '0'],
[1572098220.933, '0'],
[1572098235.934, '0'],
],
},
{
metric: {
__name__: 'promhttp_metric_handler_requests_total',
code: '503',
instance: 'localhost:9090',
job: 'prometheus',
},
values: [
[1572097950.93, '0'],
[1572097965.931, '0'],
[1572097980.929, '0'],
[1572097995.931, '0'],
[1572098010.932, '0'],
[1572098025.933, '0'],
[1572098040.93, '0'],
[1572098055.93, '0'],
[1572098070.93, '0'],
[1572098085.936, '0'],
[1572098100.936, '0'],
[1572098115.933, '0'],
[1572098130.932, '0'],
[1572098145.932, '0'],
[1572098160.933, '0'],
[1572098175.934, '0'],
[1572098190.937, '0'],
[1572098205.934, '0'],
[1572098220.933, '0'],
[1572098235.934, '0'],
],
},
],
},
};
const dataTable = shallow(<DataTable {...dataTableProps} />);
it('renders rows', () => {
const table = dataTable.find(Table);
const rows = table.find('tr');
expect(table.find('tr')).toHaveLength(3);
const row = rows.at(0);
expect(row.text()).toEqual(`<SeriesName />1 @1572097950.93
1 @1572097965.931
1 @1572097980.929
1 @1572097995.931
1 @1572098010.932
1 @1572098025.933
1 @1572098040.93
1 @1572098055.93
1 @1572098070.93
1 @1572098085.936
1 @1572098100.936
1 @1572098115.933
1 @1572098130.932
1 @1572098145.932
1 @1572098160.933
1 @1572098175.934
1 @1572098190.937
1 @1572098205.934
1 @1572098220.933
1 @1572098235.934`);
});
});
describe('when resultType is a scalar', () => {
const dataTableProps: QueryResult = {
data: {
resultType: 'scalar',
result: [1572098246.599, '5'],
},
};
const dataTable = shallow(<DataTable {...dataTableProps} />);
it('renders a scalar row', () => {
const table = dataTable.find(Table);
const rows = table.find('tr');
expect(rows.text()).toEqual('scalar5');
});
});
describe('when resultType is a string', () => {
const dataTableProps: QueryResult = {
data: {
resultType: 'string',
result: 'string',
},
};
const dataTable = shallow(<DataTable {...dataTableProps} />);
it('renders a string row', () => {
const table = dataTable.find(Table);
const rows = table.find('tr');
expect(rows.text()).toEqual('scalart');
});
});
});

View file

@ -100,7 +100,7 @@ class DataTable extends PureComponent<QueryResult> {
break;
case 'scalar':
rows.push(
<tr>
<tr key="0">
<td>scalar</td>
<td>{data.result[1]}</td>
</tr>
@ -108,7 +108,7 @@ class DataTable extends PureComponent<QueryResult> {
break;
case 'string':
rows.push(
<tr>
<tr key="0">
<td>scalar</td>
<td>{data.result[1]}</td>
</tr>

View file

@ -0,0 +1,145 @@
import * as React from 'react';
import { mount } from 'enzyme';
import ExpressionInput from './ExpressionInput';
import Downshift from 'downshift';
import { Button, InputGroup, InputGroupAddon, Input } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSearch, faSpinner } from '@fortawesome/free-solid-svg-icons';
import SanitizeHTML from './components/SanitizeHTML';
const getKeyEvent = (key: string): React.KeyboardEvent<HTMLInputElement> =>
({
key,
nativeEvent: {},
preventDefault: () => {},
} as React.KeyboardEvent<HTMLInputElement>);
describe('ExpressionInput', () => {
const metricNames = ['instance:node_cpu_utilisation:rate1m', 'node_cpu_guest_seconds_total', 'node_cpu_seconds_total'];
const expressionInputProps = {
value: 'node_cpu',
autocompleteSections: {
'Query History': [],
'Metric Names': metricNames,
},
executeQuery: (): void => {},
loading: false,
};
const expressionInput = mount(<ExpressionInput {...expressionInputProps} />);
it('renders a downshift component', () => {
const downshift = expressionInput.find(Downshift);
expect(downshift.prop('inputValue')).toEqual('node_cpu');
});
it('renders an InputGroup', () => {
const inputGroup = expressionInput.find(InputGroup);
expect(inputGroup.prop('className')).toEqual('expression-input');
});
it('renders a search icon when it is not loading', () => {
const addon = expressionInput.find(InputGroupAddon).filterWhere(addon => addon.prop('addonType') === 'prepend');
const icon = addon.find(FontAwesomeIcon);
expect(icon.prop('icon')).toEqual(faSearch);
});
it('renders a loading icon when it is loading', () => {
const expressionInput = mount(<ExpressionInput {...expressionInputProps} loading={true} />);
const addon = expressionInput.find(InputGroupAddon).filterWhere(addon => addon.prop('addonType') === 'prepend');
const icon = addon.find(FontAwesomeIcon);
expect(icon.prop('icon')).toEqual(faSpinner);
expect(icon.prop('spin')).toBe(true);
});
it('renders an Input', () => {
const expressionInput = mount(<ExpressionInput {...expressionInputProps} />);
const input = expressionInput.find(Input);
expect(input.prop('style')).toEqual({ height: 0 });
expect(input.prop('autoFocus')).toEqual(true);
expect(input.prop('type')).toEqual('textarea');
expect(input.prop('rows')).toEqual('1');
expect(input.prop('placeholder')).toEqual('Expression (press Shift+Enter for newlines)');
expect(expressionInput.state('value')).toEqual('node_cpu');
});
describe('when autosuggest is closed', () => {
it('prevents Downshift default on Home, End, Arrows', () => {
const downshift = expressionInput.find(Downshift);
const input = downshift.find(Input);
downshift.setState({ isOpen: false });
const onKeyDown = input.prop('onKeyDown');
['Home', 'End', 'ArrowUp', 'ArrowDown'].forEach(key => {
const event = getKeyEvent(key);
input.simulate('keydown', event);
const nativeEvent = event.nativeEvent as any;
expect(nativeEvent.preventDownshiftDefault).toBe(true);
});
});
it('does not render an autosuggest', () => {
const downshift = expressionInput.find(Downshift);
downshift.setState({ isOpen: false });
const ul = downshift.find('ul');
expect(ul).toHaveLength(0);
});
});
describe('when downshift is open', () => {
it('closes the menu on "Enter"', () => {
const downshift = expressionInput.find(Downshift);
const input = downshift.find(Input);
downshift.setState({ isOpen: true });
const event = getKeyEvent('Enter');
input.simulate('keydown', event);
expect(downshift.state('isOpen')).toBe(false);
});
it('noops on ArrowUp or ArrowDown', () => {
const downshift = expressionInput.find(Downshift);
const input = downshift.find(Input);
downshift.setState({ isOpen: true });
['ArrowUp', 'ArrowDown'].forEach(key => {
const event = getKeyEvent(key);
input.simulate('keydown', event);
const nativeEvent = event.nativeEvent as any;
expect(nativeEvent.preventDownshiftDefault).toBeUndefined();
});
});
it('does not render an autosuggest if there are no matches', () => {
const expressionInputProps = {
value: 'foo',
autocompleteSections: {
'Query History': [],
'Metric Names': [],
},
executeQuery: (): void => {},
loading: false,
};
const expressionInput = mount(<ExpressionInput {...expressionInputProps} />);
const downshift = expressionInput.find(Downshift);
downshift.setState({ isOpen: true });
const ul = downshift.find('ul');
expect(ul).toHaveLength(0);
});
it('renders an autosuggest if there are matches', () => {
const downshift = expressionInput.find(Downshift);
downshift.setState({ isOpen: true });
const ul = downshift.find('ul');
expect(ul.prop('className')).toEqual('card list-group');
const items = ul.find(SanitizeHTML);
expect(items.map(item => item.text()).join(', ')).toEqual(
'node_cpu_guest_seconds_total, node_cpu_seconds_total, instance:node_cpu_utilisation:rate1m'
);
});
});
it('renders an execute Button', () => {
const addon = expressionInput.find(InputGroupAddon).filterWhere(addon => addon.prop('addonType') === 'append');
const button = addon.find(Button);
expect(button.prop('className')).toEqual('execute-btn');
expect(button.prop('color')).toEqual('primary');
expect(button.text()).toEqual('Execute');
});
});

View file

@ -0,0 +1,105 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import Graph from './Graph';
import { Alert } from 'reactstrap';
import ReactResizeDetector from 'react-resize-detector';
import Legend from './Legend';
describe('Graph', () => {
[
{
data: null,
color: 'light',
children: 'No data queried yet',
},
{
data: { resultType: 'invalid' },
color: 'danger',
children: `Query result is of wrong type '`,
},
{
data: {
resultType: 'matrix',
result: [],
},
color: 'secondary',
children: 'Empty query result',
},
].forEach(testCase => {
it(`renders an alert if data is "${testCase.data}"`, () => {
const props = {
data: testCase.data,
stacked: false,
queryParams: {
startTime: 1572100210000,
endTime: 1572100217898,
resolution: 10,
},
};
const graph = shallow(<Graph {...props} />);
const alert = graph.find(Alert);
expect(alert.prop('color')).toEqual(testCase.color);
expect(alert.childAt(0).text()).toEqual(testCase.children);
});
});
describe('data is returned', () => {
const props = {
queryParams: {
startTime: 1572128592,
endTime: 1572130692,
resolution: 28,
},
stacked: false,
data: {
resultType: 'matrix',
result: [
{
metric: {
code: '200',
handler: '/graph',
instance: 'localhost:9090',
job: 'prometheus',
},
values: [
[1572128592, '23'],
[1572128620, '2'],
[1572128648, '4'],
[1572128676, '1'],
[1572128704, '2'],
[1572128732, '12'],
[1572128760, '1'],
[1572128788, '0'],
[1572128816, '0'],
[1572128844, '2'],
[1572128872, '5'],
[1572130384, '6'],
[1572130412, '7'],
[1572130440, '19'],
[1572130468, '33'],
[1572130496, '14'],
[1572130524, '7'],
[1572130552, '6'],
[1572130580, '0'],
[1572130608, '0'],
[1572130636, '0'],
[1572130664, '0'],
[1572130692, '0'],
],
},
],
},
};
it('renders a graph with props', () => {
const graph = shallow(<Graph {...props} />);
const div = graph.find('div').filterWhere(elem => elem.prop('className') === 'graph');
const resize = div.find(ReactResizeDetector);
const innerdiv = div.find('div').filterWhere(elem => elem.prop('className') === 'graph-chart');
const legend = graph.find(Legend);
expect(resize.prop('handleWidth')).toBe(true);
expect(div).toHaveLength(1);
expect(innerdiv).toHaveLength(1);
expect(legend).toHaveLength(1);
});
});
});

View file

@ -4,6 +4,7 @@ import ReactResizeDetector from 'react-resize-detector';
import { Alert } from 'reactstrap';
import Legend from './Legend';
import { escapeHTML } from './utils/html';
require('flot');
require('flot/source/jquery.flot.crosshair');
@ -32,26 +33,11 @@ class Graph extends PureComponent<GraphProps> {
private id: number = getGraphID();
private chartRef = React.createRef<HTMLDivElement>();
escapeHTML(str: string) {
const entityMap: { [key: string]: string } = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
};
return String(str).replace(/[&<>"'/]/g, function(s) {
return entityMap[s];
});
}
renderLabels(labels: { [key: string]: string }) {
const labelStrings: string[] = [];
let labelStrings: string[] = [];
for (const label in labels) {
if (label !== '__name__') {
labelStrings.push('<strong>' + label + '</strong>: ' + this.escapeHTML(labels[label]));
labelStrings.push('<strong>' + label + '</strong>: ' + escapeHTML(labels[label]));
}
}
return '<div class="labels">' + labelStrings.join('<br>') + '</div>';

View file

@ -0,0 +1,165 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import GraphControls from './GraphControls';
import { Button, ButtonGroup, Form, InputGroup, InputGroupAddon, Input } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPlus, faMinus, faChartArea, faChartLine } from '@fortawesome/free-solid-svg-icons';
import TimeInput from './TimeInput';
const defaultGraphControlProps = {
range: 60 * 60 * 24,
endTime: 1572100217898,
resolution: 10,
stacked: false,
onChangeRange: (): void => {},
onChangeEndTime: (): void => {},
onChangeResolution: (): void => {},
onChangeStacking: (): void => {},
};
describe('GraphControls', () => {
it('renders a form', () => {
const controls = shallow(<GraphControls {...defaultGraphControlProps} />);
const form = controls.find(Form);
expect(form).toHaveLength(1);
expect(form.prop('className')).toEqual('graph-controls');
expect(form.prop('inline')).toBe(true);
});
it('renders an Input Group for range', () => {
const controls = shallow(<GraphControls {...defaultGraphControlProps} />);
const form = controls.find(InputGroup);
expect(form).toHaveLength(1);
expect(form.prop('className')).toEqual('range-input');
expect(form.prop('size')).toBe('sm');
});
it('renders a decrease/increase range buttons', () => {
[
{
position: 'prepend',
title: 'Decrease range',
icon: faMinus,
},
{
position: 'append',
title: 'Increase range',
icon: faPlus,
},
].forEach(testCase => {
const controls = shallow(<GraphControls {...defaultGraphControlProps} />);
const addon = controls.find(InputGroupAddon).filterWhere(addon => addon.prop('addonType') === testCase.position);
const button = addon.find(Button);
const icon = button.find(FontAwesomeIcon);
expect(button.prop('title')).toEqual(testCase.title);
expect(icon).toHaveLength(1);
expect(icon.prop('icon')).toEqual(testCase.icon);
expect(icon.prop('fixedWidth')).toBe(true);
});
});
it('renders an Input for range', () => {
const controls = shallow(<GraphControls {...defaultGraphControlProps} />);
const form = controls.find(InputGroup);
const input = form.find(Input);
expect(input).toHaveLength(1);
expect(input.prop('defaultValue')).toEqual('1d');
expect(input.prop('innerRef')).toEqual({ current: null });
});
it('renders a TimeInput with props', () => {
const controls = shallow(<GraphControls {...defaultGraphControlProps} />);
const timeInput = controls.find(TimeInput);
expect(timeInput).toHaveLength(1);
expect(timeInput.prop('time')).toEqual(1572100217898);
expect(timeInput.prop('range')).toEqual(86400);
expect(timeInput.prop('placeholder')).toEqual('End time');
});
it('renders a TimeInput with a callback', () => {
const results: (number | null)[] = [];
const onChange = (endTime: number | null): void => {
results.push(endTime);
};
const controls = shallow(<GraphControls {...defaultGraphControlProps} onChangeEndTime={onChange} />);
const timeInput = controls.find(TimeInput);
const onChangeTime = timeInput.prop('onChangeTime');
if (onChangeTime) {
onChangeTime(5);
expect(results).toHaveLength(1);
expect(results[0]).toEqual(5);
results.pop();
} else {
fail('Expected onChangeTime to be defined but it was not');
}
});
it('renders a resolution Input with props', () => {
const controls = shallow(<GraphControls {...defaultGraphControlProps} />);
const input = controls.find(Input).filterWhere(input => input.prop('className') === 'resolution-input');
expect(input.prop('placeholder')).toEqual('Res. (s)');
expect(input.prop('defaultValue')).toEqual('10');
expect(input.prop('innerRef')).toEqual({ current: null });
expect(input.prop('bsSize')).toEqual('sm');
});
it('renders a button group', () => {
const controls = shallow(<GraphControls {...defaultGraphControlProps} />);
const group = controls.find(ButtonGroup);
expect(group.prop('className')).toEqual('stacked-input');
expect(group.prop('size')).toEqual('sm');
});
it('renders buttons inside the button group', () => {
[
{
title: 'Show unstacked line graph',
icon: faChartLine,
active: true,
},
{
title: 'Show stacked graph',
icon: faChartArea,
active: false,
},
].forEach(testCase => {
const controls = shallow(<GraphControls {...defaultGraphControlProps} />);
const group = controls.find(ButtonGroup);
const btn = group.find(Button).filterWhere(btn => btn.prop('title') === testCase.title);
expect(btn.prop('active')).toEqual(testCase.active);
const icon = btn.find(FontAwesomeIcon);
expect(icon.prop('icon')).toEqual(testCase.icon);
});
});
it('renders buttons with callbacks', () => {
[
{
title: 'Show unstacked line graph',
active: true,
},
{
title: 'Show stacked graph',
active: false,
},
].forEach(testCase => {
const results: boolean[] = [];
const onChange = (stacked: boolean): void => {
results.push(stacked);
};
const controls = shallow(<GraphControls {...defaultGraphControlProps} onChangeStacking={onChange} />);
const group = controls.find(ButtonGroup);
const btn = group.find(Button).filterWhere(btn => btn.prop('title') === testCase.title);
const onClick = btn.prop('onClick');
if (onClick) {
onClick({} as React.MouseEvent);
expect(results).toHaveLength(1);
expect(results[0]).toBe(!testCase.active);
results.pop();
} else {
fail('Expected onClick to be defined but it was not');
}
});
});
});

View file

@ -0,0 +1,93 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import Legend from './Legend';
import SeriesName from './SeriesName';
describe('Legend', () => {
describe('regardless of series', () => {
it('renders a table', () => {
const legend = shallow(<Legend series={[]} />);
expect(legend.type()).toEqual('table');
expect(legend.prop('className')).toEqual('graph-legend');
const tbody = legend.children();
expect(tbody.type()).toEqual('tbody');
});
});
describe('when series is empty', () => {
it('renders props as empty legend table', () => {
const legend = shallow(<Legend series={[]} />);
const tbody = legend.children();
expect(tbody.children()).toHaveLength(0);
});
});
describe('when series has one element', () => {
const legendProps = {
series: [
{
index: 1,
color: 'red',
labels: {
__name__: 'metric_name',
label1: 'value_1',
labeln: 'value_n',
},
},
],
};
it('renders a row of the one series', () => {
const legend = shallow(<Legend {...legendProps} />);
const tbody = legend.children();
expect(tbody.children()).toHaveLength(1);
const row = tbody.find('tr');
expect(row.prop('className')).toEqual('legend-item');
});
it('renders a legend swatch', () => {
const legend = shallow(<Legend {...legendProps} />);
const tbody = legend.children();
const row = tbody.find('tr');
const swatch = row.childAt(0);
expect(swatch.type()).toEqual('td');
expect(swatch.children().prop('className')).toEqual('legend-swatch');
expect(swatch.children().prop('style')).toEqual({
backgroundColor: 'red',
});
});
it('renders a series name', () => {
const legend = shallow(<Legend {...legendProps} />);
const tbody = legend.children();
const row = tbody.find('tr');
const series = row.childAt(1);
expect(series.type()).toEqual('td');
const seriesName = series.find(SeriesName);
expect(seriesName).toHaveLength(1);
expect(seriesName.prop('labels')).toEqual(legendProps.series[0].labels);
expect(seriesName.prop('format')).toBe(true);
});
});
describe('when series has _n_ elements', () => {
const range = Array.from(Array(20).keys());
const legendProps = {
series: range.map(i => ({
index: i,
color: 'red',
labels: {
__name__: `metric_name_${i}`,
label1: 'value_1',
labeln: 'value_n',
},
})),
};
it('renders _n_ rows', () => {
const legend = shallow(<Legend {...legendProps} />);
const tbody = legend.children();
expect(tbody.children()).toHaveLength(20);
const rows = tbody.find('tr');
rows.forEach(row => {
expect(row.prop('className')).toEqual('legend-item');
expect(row.find(SeriesName)).toHaveLength(1);
});
});
});
});

View file

@ -0,0 +1,25 @@
import metricToSeriesName from './MetricFormat';
describe('metricToSeriesName', () => {
it('returns "{}" if labels is empty', () => {
const labels = {};
expect(metricToSeriesName(labels)).toEqual('{}');
});
it('returns "metric_name{}" if labels only contains __name__', () => {
const labels = { __name__: 'metric_name' };
expect(metricToSeriesName(labels)).toEqual('metric_name{}');
});
it('returns "{label1=value_1, ..., labeln=value_n} if there are many labels and no name', () => {
const labels = { label1: 'value_1', label2: 'value_2', label3: 'value_3' };
expect(metricToSeriesName(labels)).toEqual('{label1="value_1", label2="value_2", label3="value_3"}');
});
it('returns "metric_name{label1=value_1, ... ,labeln=value_n}" if there are many labels and a name', () => {
const labels = {
__name__: 'metric_name',
label1: 'value_1',
label2: 'value_2',
label3: 'value_3',
};
expect(metricToSeriesName(labels)).toEqual('metric_name{label1="value_1", label2="value_2", label3="value_3"}');
});
});

View file

@ -0,0 +1,93 @@
import * as React from 'react';
import { mount, shallow } from 'enzyme';
import Panel, { PanelOptions, PanelType } from './Panel';
import ExpressionInput from './ExpressionInput';
import GraphControls from './GraphControls';
import Graph from './Graph';
import { NavLink, TabPane } from 'reactstrap';
import TimeInput from './TimeInput';
import DataTable from './DataTable';
describe('Panel', () => {
const props = {
options: {
expr: 'prometheus_engine',
type: PanelType.Table,
range: 10,
endTime: 1572100217898,
resolution: 28,
stacked: false,
},
onOptionsChanged: (): void => {},
pastQueries: [],
metricNames: [
'prometheus_engine_queries',
'prometheus_engine_queries_concurrent_max',
'prometheus_engine_query_duration_seconds',
],
removePanel: (): void => {},
onExecuteQuery: (): void => {},
};
const panel = shallow(<Panel {...props} />);
it('renders an ExpressionInput', () => {
const input = panel.find(ExpressionInput);
expect(input.prop('value')).toEqual('prometheus_engine');
expect(input.prop('autocompleteSections')).toEqual({
'Metric Names': [
'prometheus_engine_queries',
'prometheus_engine_queries_concurrent_max',
'prometheus_engine_query_duration_seconds',
],
'Query History': [],
});
});
it('renders NavLinks', () => {
const results: PanelOptions[] = [];
const onOptionsChanged = (opts: PanelOptions): void => {
results.push(opts);
};
const panel = shallow(<Panel {...props} onOptionsChanged={onOptionsChanged} />);
const links = panel.find(NavLink);
[{ panelType: 'Table', active: true }, { panelType: 'Graph', active: false }].forEach(
(tc: { panelType: string; active: boolean }, i: number) => {
const link = links.at(i);
const className = tc.active ? 'active' : '';
expect(link.prop('className')).toEqual(className);
link.simulate('click');
expect(results).toHaveLength(1);
expect(results[0].type).toEqual(tc.panelType.toLowerCase());
results.pop();
}
);
});
it('renders a TabPane with a TimeInput and a DataTable when in table mode', () => {
const tab = panel.find(TabPane).filterWhere(tab => tab.prop('tabId') === 'table');
const timeInput = tab.find(TimeInput);
expect(timeInput.prop('time')).toEqual(props.options.endTime);
expect(timeInput.prop('range')).toEqual(props.options.range);
expect(timeInput.prop('placeholder')).toEqual('Evaluation time');
expect(tab.find(DataTable)).toHaveLength(1);
});
it('renders a TabPane with a Graph and GraphControls when in graph mode', () => {
const options = {
expr: 'prometheus_engine',
type: PanelType.Graph,
range: 10,
endTime: 1572100217898,
resolution: 28,
stacked: false,
};
const graphPanel = mount(<Panel {...props} options={options} />);
const controls = graphPanel.find(GraphControls);
const graph = graphPanel.find(Graph);
expect(controls.prop('endTime')).toEqual(props.options.endTime);
expect(controls.prop('range')).toEqual(props.options.range);
expect(controls.prop('resolution')).toEqual(props.options.resolution);
expect(controls.prop('stacked')).toEqual(props.options.stacked);
expect(graph.prop('stacked')).toEqual(props.options.stacked);
});
});

View file

@ -0,0 +1,40 @@
import * as React from 'react';
import { mount, shallow } from 'enzyme';
import PanelList from './pages/PanelList';
import Checkbox from './Checkbox';
import { Alert, Button } from 'reactstrap';
import Panel from './Panel';
describe('PanelList', () => {
it('renders a query history checkbox', () => {
const panelList = shallow(<PanelList />);
const checkbox = panelList.find(Checkbox);
expect(checkbox.prop('id')).toEqual('query-history-checkbox');
expect(checkbox.prop('wrapperStyles')).toEqual({
margin: '0 0 0 15px',
alignSelf: 'center',
});
expect(checkbox.prop('defaultChecked')).toBe(false);
expect(checkbox.children().text()).toBe('Enable query history');
});
it('renders an alert when no data is queried yet', () => {
const panelList = mount(<PanelList />);
const alert = panelList.find(Alert);
expect(alert.prop('color')).toEqual('light');
expect(alert.children().text()).toEqual('No data queried yet');
});
it('renders panels', () => {
const panelList = shallow(<PanelList />);
const panels = panelList.find(Panel);
expect(panels.length).toBeGreaterThan(0);
});
it('renders a button to add a panel', () => {
const panelList = shallow(<PanelList />);
const btn = panelList.find(Button).filterWhere(btn => btn.prop('className') === 'add-panel-btn');
expect(btn.prop('color')).toEqual('primary');
expect(btn.children().text()).toEqual('Add Panel');
});
});

View file

@ -0,0 +1,17 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import QueryStatsView from './QueryStatsView';
describe('QueryStatsView', () => {
it('renders props as query stats', () => {
const queryStatsProps = {
loadTime: 100,
resolution: 5,
resultSeries: 10000,
};
const queryStatsView = shallow(<QueryStatsView {...queryStatsProps} />);
expect(queryStatsView.prop('className')).toEqual('query-stats');
expect(queryStatsView.children().prop('className')).toEqual('float-right');
expect(queryStatsView.children().text()).toEqual('Load time: 100ms Resolution: 5s Result series: 10000');
});
});

View file

@ -0,0 +1,81 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import SeriesName from './SeriesName';
describe('SeriesName', () => {
describe('with labels=null', () => {
const seriesNameProps = {
labels: null,
format: false,
};
const seriesName = shallow(<SeriesName {...seriesNameProps} />);
it('renders the string "scalar"', () => {
expect(seriesName.text()).toEqual('scalar');
});
});
describe('with labels defined and format false', () => {
const seriesNameProps = {
labels: {
__name__: 'metric_name',
label1: 'value_1',
label2: 'value_2',
label3: 'value_3',
},
format: false,
};
const seriesName = shallow(<SeriesName {...seriesNameProps} />);
it('renders the series name as a string', () => {
expect(seriesName.text()).toEqual('metric_name{label1="value_1", label2="value_2", label3="value_3"}');
});
});
describe('with labels defined and format true', () => {
const seriesNameProps = {
labels: {
__name__: 'metric_name',
label1: 'value_1',
label2: 'value_2',
label3: 'value_3',
},
format: true,
};
const seriesName = shallow(<SeriesName {...seriesNameProps} />);
it('renders the series name as a series of spans', () => {
expect(seriesName.children()).toHaveLength(6);
const testCases = [
{ name: 'metric_name', className: 'legend-metric-name' },
{ name: '{', className: 'legend-label-brace' },
{ name: 'label1', value: 'value_1', className: 'legend-label-name' },
{ name: 'label2', value: 'value_2', className: 'legend-label-name' },
{ name: 'label3', value: 'value_3', className: 'legend-label-name' },
{ name: '}', className: 'legend-label-brace' },
];
testCases.forEach((tc, i) => {
const child = seriesName.childAt(i);
const text = child
.children()
.map(ch => ch.text())
.join('');
switch (child.children().length) {
case 1:
expect(text).toEqual(tc.name);
expect(child.prop('className')).toEqual(tc.className);
break;
case 3:
expect(text).toEqual(`${tc.name}="${tc.value}"`);
expect(child.childAt(0).prop('className')).toEqual('legend-label-name');
expect(child.childAt(2).prop('className')).toEqual('legend-label-value');
break;
case 4:
expect(text).toEqual(`, ${tc.name}="${tc.value}"`);
expect(child.childAt(1).prop('className')).toEqual('legend-label-name');
expect(child.childAt(3).prop('className')).toEqual('legend-label-value');
break;
default:
fail('incorrect number of children: ' + child.children().length);
}
});
});
});
});

View file

@ -1,4 +1,5 @@
import React, { PureComponent } from 'react';
import metricToSeriesName from './MetricFormat';
interface SeriesNameProps {
labels: { [key: string]: string } | null;
@ -40,16 +41,7 @@ class SeriesName extends PureComponent<SeriesNameProps> {
renderPlain() {
const labels = this.props.labels!;
let tsName = (labels.__name__ || '') + '{';
const labelStrings: string[] = [];
for (const label in labels) {
if (label !== '__name__') {
labelStrings.push(label + '="' + labels[label] + '"');
}
}
tsName += labelStrings.join(', ') + '}';
return tsName;
return metricToSeriesName(labels);
}
render() {

View file

@ -0,0 +1,58 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import sinon from 'sinon';
import TimeInput from './TimeInput';
import { Button, InputGroup, InputGroupAddon, Input } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faChevronLeft, faChevronRight, faTimes } from '@fortawesome/free-solid-svg-icons';
describe('TimeInput', () => {
const timeInputProps = {
time: 1572102237932,
range: 60 * 60 * 7,
placeholder: 'time input',
onChangeTime: (): void => {},
};
const timeInput = shallow(<TimeInput {...timeInputProps} />);
it('renders the string "scalar"', () => {
const inputGroup = timeInput.find(InputGroup);
expect(inputGroup.prop('className')).toEqual('time-input');
expect(inputGroup.prop('size')).toEqual('sm');
});
it('renders buttons to adjust time', () => {
[
{
position: 'prepend',
title: 'Decrease time',
icon: faChevronLeft,
},
{
position: 'append',
title: 'Clear time',
icon: faTimes,
},
{
position: 'append',
title: 'Increase time',
icon: faChevronRight,
},
].forEach(button => {
const onChangeTime = sinon.spy();
const timeInput = shallow(<TimeInput {...timeInputProps} onChangeTime={onChangeTime} />);
const addon = timeInput.find(InputGroupAddon).filterWhere(addon => addon.prop('addonType') === button.position);
const btn = addon.find(Button).filterWhere(btn => btn.prop('title') === button.title);
const icon = btn.find(FontAwesomeIcon);
expect(icon.prop('icon')).toEqual(button.icon);
expect(icon.prop('fixedWidth')).toBe(true);
btn.simulate('click');
expect(onChangeTime.calledOnce).toBe(true);
});
});
it('renders an Input', () => {
const input = timeInput.find(Input);
expect(input.prop('placeholder')).toEqual(timeInputProps.placeholder);
expect(input.prop('innerRef')).toEqual({ current: null });
});
});

View file

@ -0,0 +1,25 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import SanitizeHTML from '.';
describe('SanitizeHTML', () => {
it(`renders allowed html`, () => {
const props = {
allowedTags: ['strong'],
};
const html = shallow(<SanitizeHTML {...props}>{'<strong>text</strong>'}</SanitizeHTML>);
const elem = html.find('div');
expect(elem).toHaveLength(1);
expect(elem.html()).toEqual(`<div><strong>text</strong></div>`);
});
it('does not render disallowed tags', () => {
const props = {
tag: 'span' as keyof JSX.IntrinsicElements,
allowedTags: ['strong'],
};
const html = shallow(<SanitizeHTML {...props}>{'<a href="www.example.com">link</a>'}</SanitizeHTML>);
const elem = html.find('span');
expect(elem.html()).toEqual('<span>link</span>');
});
});

View file

@ -1,12 +0,0 @@
/**
* SanitizeHTML tests
*/
import React from 'react';
import ReactDOM from 'react-dom';
import SanitizeHTML from '../SanitizeHTML';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<SanitizeHTML />, div);
ReactDOM.unmountComponentAtNode(div);
});

View file

@ -0,0 +1,5 @@
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import './globals';
configure({ adapter: new Adapter() });

View file

@ -1,5 +0,0 @@
export const uuidGen = () =>
'_' +
Math.random()
.toString(36)
.substr(2, 9);

View file

@ -0,0 +1,9 @@
import { escapeHTML } from './html';
describe('escapeHTML', (): void => {
it('escapes html sequences', () => {
expect(escapeHTML(`<strong>'example'&"another/example"</strong>`)).toEqual(
'&lt;strong&gt;&#39;example&#39;&amp;&quot;another&#x2F;example&quot;&lt;&#x2F;strong&gt;'
);
});
});

View file

@ -0,0 +1,14 @@
export const escapeHTML = (str: string): string => {
const entityMap: { [key: string]: string } = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
};
return String(str).replace(/[&<>"'/]/g, function(s) {
return entityMap[s];
});
};

View file

@ -0,0 +1,37 @@
import { formatTime, parseTime, formatRange, parseRange } from './timeFormat';
describe('formatTime', () => {
it('returns a time string representing the time in seconds', () => {
expect(formatTime(1572049380000)).toEqual('2019-10-26 00:23');
expect(formatTime(0)).toEqual('1970-01-01 00:00');
});
});
describe('parseTime', () => {
it('returns a time string representing the time in seconds', () => {
expect(parseTime('2019-10-26 00:23')).toEqual(1572049380000);
expect(parseTime('1970-01-01 00:00')).toEqual(0);
});
});
describe('formatRange', () => {
it('returns a time string representing the time in seconds in one unit', () => {
expect(formatRange(60 * 60 * 24 * 365)).toEqual('1y');
expect(formatRange(60 * 60 * 24 * 7)).toEqual('1w');
expect(formatRange(2 * 60 * 60 * 24)).toEqual('2d');
expect(formatRange(60 * 60)).toEqual('1h');
expect(formatRange(7 * 60)).toEqual('7m');
expect(formatRange(63)).toEqual('63s');
});
});
describe('parseRange', () => {
it('returns a time string representing the time in seconds in one unit', () => {
expect(parseRange('1y')).toEqual(60 * 60 * 24 * 365);
expect(parseRange('1w')).toEqual(60 * 60 * 24 * 7);
expect(parseRange('2d')).toEqual(2 * 60 * 60 * 24);
expect(parseRange('1h')).toEqual(60 * 60);
expect(parseRange('7m')).toEqual(7 * 60);
expect(parseRange('63s')).toEqual(63);
});
});

View file

@ -0,0 +1,47 @@
import { decodePanelOptionsFromQueryString, encodePanelOptionsToQueryString } from './urlParams';
import { PanelType } from '../Panel';
const panels = [
{
key: '0',
options: {
endTime: 1572046620000,
expr: 'rate(node_cpu_seconds_total{mode="system"}[1m])',
range: 3600,
resolution: null,
stacked: false,
type: PanelType.Graph,
},
},
{
key: '1',
options: {
endTime: null,
expr: 'node_filesystem_avail_bytes',
range: 3600,
resolution: null,
stacked: false,
type: PanelType.Table,
},
},
];
const query =
'?g0.expr=rate(node_cpu_seconds_total%7Bmode%3D%22system%22%7D%5B1m%5D)&g0.tab=0&g0.stacked=0&g0.range_input=1h&g0.end_input=2019-10-25%2023%3A37&g0.moment_input=2019-10-25%2023%3A37&g1.expr=node_filesystem_avail_bytes&g1.tab=1&g1.stacked=0&g1.range_input=1h';
describe('decodePanelOptionsFromQueryString', () => {
it('returns [] when query is empty', () => {
expect(decodePanelOptionsFromQueryString('')).toEqual([]);
});
it('returns and array of parsed params when query string is non-empty', () => {
expect(decodePanelOptionsFromQueryString(query)).toEqual(panels);
});
});
describe('encodePanelOptionsToQueryString', () => {
it('returns ? when panels is empty', () => {
expect(encodePanelOptionsToQueryString([])).toEqual('?');
});
it('returns an encoded query string otherwise', () => {
expect(encodePanelOptionsToQueryString(panels)).toEqual(query);
});
});

View file

@ -1150,6 +1150,35 @@
react-lifecycles-compat "^3.0.4"
warning "^3.0.0"
"@sinonjs/commons@^1", "@sinonjs/commons@^1.3.0", "@sinonjs/commons@^1.4.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.6.0.tgz#ec7670432ae9c8eb710400d112c201a362d83393"
integrity sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg==
dependencies:
type-detect "4.0.8"
"@sinonjs/formatio@^3.2.1":
version "3.2.2"
resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-3.2.2.tgz#771c60dfa75ea7f2d68e3b94c7e888a78781372c"
integrity sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==
dependencies:
"@sinonjs/commons" "^1"
"@sinonjs/samsam" "^3.1.0"
"@sinonjs/samsam@^3.1.0", "@sinonjs/samsam@^3.3.3":
version "3.3.3"
resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-3.3.3.tgz#46682efd9967b259b81136b9f120fd54585feb4a"
integrity sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==
dependencies:
"@sinonjs/commons" "^1.3.0"
array-from "^2.1.1"
lodash "^4.17.15"
"@sinonjs/text-encoding@^0.7.1":
version "0.7.1"
resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5"
integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==
"@svgr/babel-plugin-add-jsx-attribute@^4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz#dadcb6218503532d6884b210e7f3c502caaa44b1"
@ -1286,6 +1315,13 @@
dependencies:
"@babel/types" "^7.3.0"
"@types/cheerio@*":
version "0.22.13"
resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.13.tgz#5eecda091a24514185dcba99eda77e62bf6523e6"
integrity sha512-OZd7dCUOUkiTorf97vJKwZnSja/DmHfuBAroe1kREZZTCf/tlFecwHhsOos3uVHxeKGZDwzolIrCUApClkdLuA==
dependencies:
"@types/node" "*"
"@types/domhandler@*":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@types/domhandler/-/domhandler-2.4.1.tgz#7b3b347f7762180fbcb1ece1ce3dd0ebbb8c64cf"
@ -1298,6 +1334,21 @@
dependencies:
"@types/domhandler" "*"
"@types/enzyme-adapter-react-16@^1.0.5":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.5.tgz#1bf30a166f49be69eeda4b81e3f24113c8b4e9d5"
integrity sha512-K7HLFTkBDN5RyRmU90JuYt8OWEY2iKUn43SDWEoBOXd/PowUWjLZ3Q6qMBiQuZeFYK/TOstaZxsnI0fXoAfLpg==
dependencies:
"@types/enzyme" "*"
"@types/enzyme@*", "@types/enzyme@^3.10.3":
version "3.10.3"
resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.10.3.tgz#02b6c5ac7d0472005944a652e79045e2f6c66804"
integrity sha512-f/Kcb84sZOSZiBPCkr4He9/cpuSLcKRyQaEE20Q30Prx0Dn6wcyMAWI0yofL6yvd9Ht9G7EVkQeRqK0n5w8ILw==
dependencies:
"@types/cheerio" "*"
"@types/react" "*"
"@types/eslint-visitor-keys@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
@ -1349,10 +1400,10 @@
resolved "https://registry.yarnpkg.com/@types/jest-diff/-/jest-diff-20.0.1.tgz#35cc15b9c4f30a18ef21852e255fdb02f6d59b89"
integrity sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==
"@types/jest@^24.0.4":
version "24.0.19"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.19.tgz#f7036058d2a5844fe922609187c0ad8be430aff5"
integrity sha512-YYiqfSjocv7lk5H/T+v5MjATYjaTMsUkbDnjGqSMoO88jWdtJXJV4ST/7DKZcoMHMBvB2SeSfyOzZfkxXHR5xg==
"@types/jest@^24.0.20":
version "24.0.20"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.20.tgz#729d5fe8684e7fb06368d3bd557ac6d91289d861"
integrity sha512-M8ebEkOpykGdLoRrmew7UowTZ1DANeeP0HiSIChl/4DGgmnSC1ntitNtkyNSXjMTsZvXuaxJrxjImEnRWNPsPw==
dependencies:
"@types/jest-diff" "*"
@ -1442,6 +1493,11 @@
dependencies:
"@types/htmlparser2" "*"
"@types/sinon@^7.5.0":
version "7.5.0"
resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-7.5.0.tgz#f5a10c27175465a0b001b68d8b9f761582967cc6"
integrity sha512-NyzhuSBy97B/zE58cDw4NyGvByQbAHNP9069KVSgnXt/sc0T6MFRh0InKAeBVHJWdSXG1S3+PxgVIgKo9mTHbw==
"@types/sizzle@*":
version "2.3.2"
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47"
@ -1769,6 +1825,22 @@ adjust-sourcemap-loader@2.0.0:
object-path "0.11.4"
regex-parser "2.2.10"
airbnb-prop-types@^2.15.0:
version "2.15.0"
resolved "https://registry.yarnpkg.com/airbnb-prop-types/-/airbnb-prop-types-2.15.0.tgz#5287820043af1eb469f5b0af0d6f70da6c52aaef"
integrity sha512-jUh2/hfKsRjNFC4XONQrxo/n/3GG4Tn6Hl0WlFQN5PY9OMC9loSCoAYKnZsWaP8wEfd5xcrPloK0Zg6iS1xwVA==
dependencies:
array.prototype.find "^2.1.0"
function.prototype.name "^1.1.1"
has "^1.0.3"
is-regex "^1.0.4"
object-is "^1.0.1"
object.assign "^4.1.0"
object.entries "^1.1.0"
prop-types "^15.7.2"
prop-types-exact "^1.2.0"
react-is "^16.9.0"
ajv-errors@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d"
@ -1912,6 +1984,11 @@ array-equal@^1.0.0:
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=
array-filter@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83"
integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=
array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
@ -1922,6 +1999,11 @@ array-flatten@^2.1.0:
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099"
integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==
array-from@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/array-from/-/array-from-2.1.1.tgz#cfe9d8c26628b9dc5aecc62a9f5d8f1f352c1195"
integrity sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=
array-includes@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d"
@ -1947,6 +2029,23 @@ array-unique@^0.3.2:
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
array.prototype.find@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.1.0.tgz#630f2eaf70a39e608ac3573e45cf8ccd0ede9ad7"
integrity sha512-Wn41+K1yuO5p7wRZDl7890c3xvv5UBrfVXTVIe28rSQb6LS0fZMDrQB6PAcxQFRFy6vJTLDc3A2+3CjQdzVKRg==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.13.0"
array.prototype.flat@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.2.tgz#8f3c71d245ba349b6b64b4078f76f5576f1fd723"
integrity sha512-VXjh7lAL4KXKF2hY4FnEW9eRW6IhdvFW1sN/JwLbmECbCgACCnBHNyP3lFiYuttr0jxRN9Bsc5+G27dMseSWqQ==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.15.0"
function-bind "^1.1.1"
arrify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
@ -2629,6 +2728,18 @@ chardet@^0.7.0:
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
cheerio@^1.0.0-rc.2:
version "1.0.0-rc.3"
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.3.tgz#094636d425b2e9c0f4eb91a46c05630c9a1a8bf6"
integrity sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==
dependencies:
css-select "~1.2.0"
dom-serializer "~0.1.1"
entities "~1.1.1"
htmlparser2 "^3.9.1"
lodash "^4.15.0"
parse5 "^3.0.1"
chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.4:
version "2.1.8"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
@ -2837,7 +2948,7 @@ commander@2.20.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
commander@^2.11.0, commander@^2.20.0:
commander@^2.11.0, commander@^2.19.0, commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@ -3169,7 +3280,7 @@ css-select-base-adapter@^0.1.1:
resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7"
integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==
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"
integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=
@ -3548,6 +3659,11 @@ diff-sequences@^24.9.0:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==
diff@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
diffie-hellman@^5.0.0:
version "5.0.3"
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
@ -3565,6 +3681,11 @@ dir-glob@2.0.0:
arrify "^1.0.1"
path-type "^3.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"
integrity sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=
dns-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
@ -3629,12 +3750,20 @@ dom-serializer@0:
domelementtype "^2.0.1"
entities "^2.0.0"
dom-serializer@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0"
integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==
dependencies:
domelementtype "^1.3.0"
entities "^1.1.1"
domain-browser@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
domelementtype@1, domelementtype@^1.3.1:
domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
@ -3786,7 +3915,7 @@ enhanced-resolve@^4.1.0:
memory-fs "^0.5.0"
tapable "^1.0.0"
entities@^1.1.1:
entities@^1.1.1, entities@~1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
@ -3796,6 +3925,68 @@ entities@^2.0.0:
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4"
integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==
enzyme-adapter-react-16@^1.15.1:
version "1.15.1"
resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.1.tgz#8ad55332be7091dc53a25d7d38b3485fc2ba50d5"
integrity sha512-yMPxrP3vjJP+4wL/qqfkT6JAIctcwKF+zXO6utlGPgUJT2l4tzrdjMDWGd/Pp1BjHBcljhN24OzNEGRteibJhA==
dependencies:
enzyme-adapter-utils "^1.12.1"
enzyme-shallow-equal "^1.0.0"
has "^1.0.3"
object.assign "^4.1.0"
object.values "^1.1.0"
prop-types "^15.7.2"
react-is "^16.10.2"
react-test-renderer "^16.0.0-0"
semver "^5.7.0"
enzyme-adapter-utils@^1.12.1:
version "1.12.1"
resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.12.1.tgz#e828e0d038e2b1efa4b9619ce896226f85c9dd88"
integrity sha512-KWiHzSjZaLEoDCOxY8Z1RAbUResbqKN5bZvenPbfKtWorJFVETUw754ebkuCQ3JKm0adx1kF8JaiR+PHPiP47g==
dependencies:
airbnb-prop-types "^2.15.0"
function.prototype.name "^1.1.1"
object.assign "^4.1.0"
object.fromentries "^2.0.1"
prop-types "^15.7.2"
semver "^5.7.0"
enzyme-shallow-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.0.tgz#d8e4603495e6ea279038eef05a4bf4887b55dc69"
integrity sha512-VUf+q5o1EIv2ZaloNQQtWCJM9gpeux6vudGVH6vLmfPXFLRuxl5+Aq3U260wof9nn0b0i+P5OEUXm1vnxkRpXQ==
dependencies:
has "^1.0.3"
object-is "^1.0.1"
enzyme@^3.10.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.10.0.tgz#7218e347c4a7746e133f8e964aada4a3523452f6"
integrity sha512-p2yy9Y7t/PFbPoTvrWde7JIYB2ZyGC+NgTNbVEGvZ5/EyoYSr9aG/2rSbVvyNvMHEhw9/dmGUJHWtfQIEiX9pg==
dependencies:
array.prototype.flat "^1.2.1"
cheerio "^1.0.0-rc.2"
function.prototype.name "^1.1.0"
has "^1.0.3"
html-element-map "^1.0.0"
is-boolean-object "^1.0.0"
is-callable "^1.1.4"
is-number-object "^1.0.3"
is-regex "^1.0.4"
is-string "^1.0.4"
is-subset "^0.1.1"
lodash.escape "^4.0.1"
lodash.isequal "^4.5.0"
object-inspect "^1.6.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"
string.prototype.trim "^1.1.2"
errno@^0.1.3, errno@~0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
@ -3826,6 +4017,22 @@ es-abstract@^1.12.0, es-abstract@^1.15.0, es-abstract@^1.5.1, es-abstract@^1.7.0
string.prototype.trimleft "^2.1.0"
string.prototype.trimright "^2.1.0"
es-abstract@^1.13.0:
version "1.16.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.0.tgz#d3a26dc9c3283ac9750dca569586e976d9dcc06d"
integrity sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==
dependencies:
es-to-primitive "^1.2.0"
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.0"
is-callable "^1.1.4"
is-regex "^1.0.4"
object-inspect "^1.6.0"
object-keys "^1.1.1"
string.prototype.trimleft "^2.1.0"
string.prototype.trimright "^2.1.0"
es-to-primitive@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377"
@ -4635,11 +4842,26 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
function.prototype.name@^1.1.0, function.prototype.name@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.1.tgz#6d252350803085abc2ad423d4fe3be2f9cbda392"
integrity sha512-e1NzkiJuw6xqVH7YSdiW/qDHebcmMhPNe6w+4ZYYEg0VA+LaLzx37RimbPLuonHhYGFGPx1ME2nSi74JiaCr/Q==
dependencies:
define-properties "^1.1.3"
function-bind "^1.1.1"
functions-have-names "^1.1.1"
is-callable "^1.1.4"
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"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
functions-have-names@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.0.tgz#83da7583e4ea0c9ac5ff530f73394b033e0bf77d"
integrity sha512-zKXyzksTeaCSw5wIX79iCA40YAa6CJMJgNg9wdkU/ERBrIdPSimPICYiLp65lRbSBqtiHql/HZfS2DyI/AH6tQ==
fuzzy@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/fuzzy/-/fuzzy-0.1.3.tgz#4c76ec2ff0ac1a36a9dccf9a00df8623078d4ed8"
@ -4957,6 +5179,13 @@ html-comment-regex@^1.1.0:
resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7"
integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==
html-element-map@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/html-element-map/-/html-element-map-1.1.0.tgz#e5aab9a834caf883b421f8bd9eaedcaac887d63c"
integrity sha512-iqiG3dTZmy+uUaTmHarTL+3/A2VW9ox/9uasKEZC+R/wAtUrTcRlXPSaPqsnWPfIu8wqn09jQNwMRqzL54jSYA==
dependencies:
array-filter "^1.0.0"
html-encoding-sniffer@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8"
@ -4994,7 +5223,7 @@ html-webpack-plugin@4.0.0-beta.5:
tapable "^1.1.0"
util.promisify "1.0.0"
htmlparser2@^3.10.0, htmlparser2@^3.3.0:
htmlparser2@^3.10.0, htmlparser2@^3.3.0, htmlparser2@^3.9.1:
version "3.10.1"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==
@ -5351,6 +5580,11 @@ is-binary-path@~2.1.0:
dependencies:
binary-extensions "^2.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"
integrity sha1-mPiygDBoQhmpXzdc+9iM40Bd/5M=
is-buffer@^1.0.2, is-buffer@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
@ -5470,6 +5704,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
dependencies:
is-extglob "^2.1.1"
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"
integrity sha1-8mWrian0RQNO9q/xWo8AsA9VF5k=
is-number@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
@ -5550,6 +5789,16 @@ is-stream@^1.0.1, is-stream@^1.1.0:
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
is-string@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.4.tgz#cc3a9b69857d621e963725a24caeec873b826e64"
integrity sha1-zDqbaYV9Yh6WNyWiTK7shzuCbmQ=
is-subset@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6"
integrity sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=
is-svg@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75"
@ -5579,6 +5828,11 @@ is-wsl@^1.1.0:
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
isarray@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@ -6259,6 +6513,11 @@ jsx-ast-utils@^2.1.0, jsx-ast-utils@^2.2.1:
array-includes "^3.0.3"
object.assign "^4.1.0"
just-extend@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.0.2.tgz#f3f47f7dfca0f989c55410a7ebc8854b07108afc"
integrity sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==
killable@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
@ -6416,11 +6675,26 @@ lodash.clonedeep@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
lodash.escape@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98"
integrity sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=
lodash.escaperegexp@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347"
integrity sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=
lodash.flattendeep@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
lodash.isfunction@^3.0.9:
version "3.0.9"
resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051"
@ -6486,7 +6760,7 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5:
"lodash@>=3.5 <5", lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
@ -6496,6 +6770,11 @@ loglevel@^1.4.1:
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.4.tgz#f408f4f006db8354d0577dcf6d33485b3cb90d56"
integrity sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g==
lolex@^4.1.0, lolex@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.2.0.tgz#ddbd7f6213ca1ea5826901ab1222b65d714b3cd7"
integrity sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
@ -6816,6 +7095,11 @@ moment-timezone@^0.5.11, moment-timezone@^0.5.23:
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
moo@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/moo/-/moo-0.4.3.tgz#3f847a26f31cf625a956a87f2b10fbc013bfd10e"
integrity sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw==
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@ -6888,6 +7172,17 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
nearley@^2.7.10:
version "2.19.0"
resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.19.0.tgz#37717781d0fd0f2bfc95e233ebd75678ca4bda46"
integrity sha512-2v52FTw7RPqieZr3Gth1luAXZR7Je6q3KaDHY5bjl/paDUdMu35fZ8ICNgiYJRr3tf3NMvIQQR1r27AvEr9CRA==
dependencies:
commander "^2.19.0"
moo "^0.4.3"
railroad-diagrams "^1.0.0"
randexp "0.4.6"
semver "^5.4.1"
needle@^2.2.1:
version "2.4.0"
resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
@ -6917,6 +7212,17 @@ nice-try@^1.0.4:
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
nise@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/nise/-/nise-1.5.2.tgz#b6d29af10e48b321b307e10e065199338eeb2652"
integrity sha512-/6RhOUlicRCbE9s+94qCUsyE+pKlVJ5AhIv+jEE7ESKwnbXqulKZ1FYU+XAtHHWE9TinYvAxDUJAb912PwPoWA==
dependencies:
"@sinonjs/formatio" "^3.2.1"
"@sinonjs/text-encoding" "^0.7.1"
just-extend "^4.0.2"
lolex "^4.1.0"
path-to-regexp "^1.7.0"
no-case@^2.2.0:
version "2.3.2"
resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
@ -7173,7 +7479,7 @@ object.assign@^4.1.0:
has-symbols "^1.0.0"
object-keys "^1.0.11"
object.entries@^1.1.0:
object.entries@^1.0.4, object.entries@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519"
integrity sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==
@ -7183,7 +7489,7 @@ object.entries@^1.1.0:
function-bind "^1.1.1"
has "^1.0.3"
object.fromentries@^2.0.0:
object.fromentries@^2.0.0, object.fromentries@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.1.tgz#050f077855c7af8ae6649f45c80b16ee2d31e704"
integrity sha512-PUQv8Hbg3j2QX0IQYv3iAGCbGcu4yY4KQ92/dhA4sFSixBmSmp13UpDLs6jGK8rBtbmhNNIK99LD2k293jpiGA==
@ -7208,7 +7514,7 @@ object.pick@^1.3.0:
dependencies:
isobject "^3.0.1"
object.values@^1.1.0:
object.values@^1.0.4, object.values@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.0.tgz#bf6810ef5da3e5325790eaaa2be213ea84624da9"
integrity sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==
@ -7465,6 +7771,13 @@ parse5@5.1.0:
resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2"
integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==
parse5@^3.0.1:
version "3.0.3"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
integrity sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==
dependencies:
"@types/node" "*"
parseurl@~1.3.2, parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
@ -7522,6 +7835,13 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
path-to-regexp@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=
dependencies:
isarray "0.0.1"
path-type@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
@ -8402,6 +8722,15 @@ prompts@^2.0.1:
kleur "^3.0.3"
sisteransi "^1.0.3"
prop-types-exact@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/prop-types-exact/-/prop-types-exact-1.2.0.tgz#825d6be46094663848237e3925a98c6e944e9869"
integrity sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA==
dependencies:
has "^1.0.3"
object.assign "^4.1.0"
reflect.ownkeys "^0.2.0"
prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
@ -8524,13 +8853,26 @@ raf-schd@^4.0.2:
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.2.tgz#bd44c708188f2e84c810bf55fcea9231bcaed8a0"
integrity sha512-VhlMZmGy6A6hrkJWHLNTGl5gtgMUm+xfGza6wbwnE914yeQ5Ybm18vgM734RZhMgfw4tacUrWseGZlpUrrakEQ==
raf@3.4.1:
raf@3.4.1, raf@^3.4.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
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"
integrity sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=
randexp@0.4.6:
version "0.4.6"
resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3"
integrity sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==
dependencies:
discontinuous-range "1.0.0"
ret "~0.1.10"
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
@ -8637,6 +8979,11 @@ react-error-overlay@^6.0.3:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.3.tgz#c378c4b0a21e88b2e159a3e62b2f531fd63bf60d"
integrity sha512-bOUvMWFQVk5oz8Ded9Xb7WVdEi3QGLC8tH7HmYP0Fdp4Bn3qw0tRFmr5TW6mvahzvmrK4a6bqWGfCevBflP+Xw==
react-is@^16.10.2, react-is@^16.8.6:
version "16.11.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.11.0.tgz#b85dfecd48ad1ce469ff558a882ca8e8313928fa"
integrity sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw==
react-is@^16.8.1, react-is@^16.8.4, react-is@^16.9.0:
version "16.10.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.10.2.tgz#984120fd4d16800e9a738208ab1fba422d23b5ab"
@ -8731,6 +9078,16 @@ react-scripts@^3.2.0:
optionalDependencies:
fsevents "2.0.7"
react-test-renderer@^16.0.0-0:
version "16.11.0"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.11.0.tgz#72574566496462c808ac449b0287a4c0a1a7d8f8"
integrity sha512-nh9gDl8R4ut+ZNNb2EeKO5VMvTKxwzurbSMuGBoKtjpjbg8JK/u3eVPVNi1h1Ue+eYK9oSzJjb+K3lzLxyA4ag==
dependencies:
object-assign "^4.1.1"
prop-types "^15.6.2"
react-is "^16.8.6"
scheduler "^0.17.0"
react-transition-group@^2.3.1:
version "2.9.0"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
@ -8851,6 +9208,11 @@ recursive-readdir@2.2.2:
dependencies:
minimatch "3.0.4"
reflect.ownkeys@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460"
integrity sha1-dJrO7H8/34tj+SegSAnpDFwLNGA=
regenerate-unicode-properties@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
@ -9135,6 +9497,14 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
hash-base "^3.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"
integrity sha1-gbIw6i/MYGbInjRy3nlChdmwPZE=
dependencies:
lodash.flattendeep "^4.4.0"
nearley "^2.7.10"
rsvp@^4.8.4:
version "4.8.5"
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
@ -9245,6 +9615,14 @@ scheduler@^0.16.2:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler@^0.17.0:
version "0.17.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.17.0.tgz#7c9c673e4ec781fac853927916d1c426b6f3ddfe"
integrity sha512-7rro8Io3tnCPuY4la/NuI5F2yfESpnfZyT6TtkXnSWVkcu0BCDJ+8gk5ozUaFaxpIyNuWAPXrH0yFcSi28fnDA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
schema-utils@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770"
@ -9274,7 +9652,7 @@ selfsigned@^1.9.1:
dependencies:
node-forge "0.9.0"
"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@ -9420,6 +9798,19 @@ simple-swizzle@^0.2.2:
dependencies:
is-arrayish "^0.3.1"
sinon@^7.5.0:
version "7.5.0"
resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.5.0.tgz#e9488ea466070ea908fd44a3d6478fd4923c67ec"
integrity sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==
dependencies:
"@sinonjs/commons" "^1.4.0"
"@sinonjs/formatio" "^3.2.1"
"@sinonjs/samsam" "^3.3.3"
diff "^3.5.0"
lolex "^4.2.0"
nise "^1.5.2"
supports-color "^5.5.0"
sisteransi@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.3.tgz#98168d62b79e3a5e758e27ae63c4a053d748f4eb"
@ -9755,6 +10146,15 @@ string-width@^3.0.0, string-width@^3.1.0:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^5.1.0"
string.prototype.trim@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.0.tgz#75a729b10cfc1be439543dae442129459ce61e3d"
integrity sha512-9EIjYD/WdlvLpn987+ctkLf0FfvBefOCuiEr2henD8X+7jfwPnyvTdmW8OJhj5p+M0/96mBdynLWkxUr+rHlpg==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.13.0"
function-bind "^1.1.1"
string.prototype.trimleft@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634"
@ -9865,7 +10265,7 @@ supports-color@^2.0.0:
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
supports-color@^5.3.0:
supports-color@^5.3.0, supports-color@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
@ -10167,6 +10567,11 @@ type-check@~0.3.2:
dependencies:
prelude-ls "~1.1.2"
type-detect@4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
type-fest@^0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.5.2.tgz#d6ef42a0356c6cd45f49485c3b6281fc148e48a2"