mirror of
https://github.com/prometheus/prometheus.git
synced 2025-01-11 13:57:36 -08:00
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:
parent
8340db5614
commit
e0443e6fa3
2
Makefile
2
Makefile
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
22
web/ui/react-app/src/App.test.tsx
Executable file
22
web/ui/react-app/src/App.test.tsx
Executable 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);
|
||||
});
|
||||
});
|
65
web/ui/react-app/src/Checkbox.test.tsx
Executable file
65
web/ui/react-app/src/Checkbox.test.tsx
Executable 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'));
|
||||
});
|
||||
});
|
267
web/ui/react-app/src/DataTable.test.tsx
Executable file
267
web/ui/react-app/src/DataTable.test.tsx
Executable 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');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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>
|
||||
|
|
145
web/ui/react-app/src/ExpressionInput.test.tsx
Normal file
145
web/ui/react-app/src/ExpressionInput.test.tsx
Normal 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');
|
||||
});
|
||||
});
|
105
web/ui/react-app/src/Graph.test.tsx
Normal file
105
web/ui/react-app/src/Graph.test.tsx
Normal 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);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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 } = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'/': '/',
|
||||
};
|
||||
|
||||
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>';
|
||||
|
|
165
web/ui/react-app/src/GraphControls.test.tsx
Executable file
165
web/ui/react-app/src/GraphControls.test.tsx
Executable 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');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
93
web/ui/react-app/src/Legend.test.tsx
Executable file
93
web/ui/react-app/src/Legend.test.tsx
Executable 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
25
web/ui/react-app/src/MetricFormat.test.ts
Normal file
25
web/ui/react-app/src/MetricFormat.test.ts
Normal 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"}');
|
||||
});
|
||||
});
|
93
web/ui/react-app/src/Panel.test.tsx
Normal file
93
web/ui/react-app/src/Panel.test.tsx
Normal 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);
|
||||
});
|
||||
});
|
40
web/ui/react-app/src/PanelList.test.tsx
Executable file
40
web/ui/react-app/src/PanelList.test.tsx
Executable 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');
|
||||
});
|
||||
});
|
17
web/ui/react-app/src/QueryStatsView.test.tsx
Executable file
17
web/ui/react-app/src/QueryStatsView.test.tsx
Executable 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');
|
||||
});
|
||||
});
|
81
web/ui/react-app/src/SeriesName.test.tsx
Executable file
81
web/ui/react-app/src/SeriesName.test.tsx
Executable 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);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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() {
|
||||
|
|
58
web/ui/react-app/src/TimeInput.test.tsx
Normal file
58
web/ui/react-app/src/TimeInput.test.tsx
Normal 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 });
|
||||
});
|
||||
});
|
|
@ -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>');
|
||||
});
|
||||
});
|
|
@ -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);
|
||||
});
|
5
web/ui/react-app/src/setupTests.ts
Normal file
5
web/ui/react-app/src/setupTests.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { configure } from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import './globals';
|
||||
|
||||
configure({ adapter: new Adapter() });
|
|
@ -1,5 +0,0 @@
|
|||
export const uuidGen = () =>
|
||||
'_' +
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.substr(2, 9);
|
9
web/ui/react-app/src/utils/html.test.ts
Normal file
9
web/ui/react-app/src/utils/html.test.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { escapeHTML } from './html';
|
||||
|
||||
describe('escapeHTML', (): void => {
|
||||
it('escapes html sequences', () => {
|
||||
expect(escapeHTML(`<strong>'example'&"another/example"</strong>`)).toEqual(
|
||||
'<strong>'example'&"another/example"</strong>'
|
||||
);
|
||||
});
|
||||
});
|
14
web/ui/react-app/src/utils/html.ts
Normal file
14
web/ui/react-app/src/utils/html.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
export const escapeHTML = (str: string): string => {
|
||||
const entityMap: { [key: string]: string } = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'/': '/',
|
||||
};
|
||||
|
||||
return String(str).replace(/[&<>"'/]/g, function(s) {
|
||||
return entityMap[s];
|
||||
});
|
||||
};
|
37
web/ui/react-app/src/utils/timeFormat.test.ts
Normal file
37
web/ui/react-app/src/utils/timeFormat.test.ts
Normal 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);
|
||||
});
|
||||
});
|
47
web/ui/react-app/src/utils/urlParams.test.ts
Normal file
47
web/ui/react-app/src/utils/urlParams.test.ts
Normal 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);
|
||||
});
|
||||
});
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue