web dependency upgrade: get tests to pass

This commit is contained in:
Maximilian Hils 2021-06-09 12:00:11 +02:00
parent 2c5c6cfa5a
commit d3f33b90a6
13 changed files with 164 additions and 92 deletions

18
web/jest.config.js Normal file
View File

@ -0,0 +1,18 @@
process.env.TZ = 'UTC';
module.exports = {
"testRegex": "__tests__/.*Spec.js$",
"roots": [
"<rootDir>/src/js"
],
"unmockedModulePathPatterns": [
"react"
],
"coverageDirectory": "./coverage",
"coveragePathIgnorePatterns": [
"<rootDir>/src/js/filt/filt.js"
],
"collectCoverageFrom": [
"src/js/**/*.{js,jsx}"
]
};

View File

@ -2,7 +2,7 @@
"name": "mitmproxy",
"private": true,
"scripts": {
"test": "TZ=UTC jest --coverage",
"test": "jest --coverage",
"build": "gulp prod",
"start": "gulp"
},
@ -31,7 +31,7 @@
"react": "^17.0.2",
"react-codemirror": "^1.0.0",
"react-dom": "^17.0.2",
"react-redux": "7.1.0",
"react-redux": "^7.2.4",
"react-test-renderer": "^17.0.2",
"redux": "^4.1.0",
"redux-logger": "^3.0.6",

View File

@ -6,7 +6,7 @@ import { ViewServer, ViewImage, PureViewServer, Edit } from '../../../components
import { TFlow, TStore } from '../../ducks/tutils'
import mockXMLHttpRequest from 'mock-xmlhttprequest'
global.XMLHttpRequest = mockXMLHttpRequest
window.XMLHttpRequest = mockXMLHttpRequest
let tflow = new TFlow()
describe('ViewImage Component', () => {

View File

@ -27,31 +27,31 @@ describe('EventLog Component', () => {
debugToggleButton.props.onClick()
})
provider = TestUtils.renderIntoDocument(
provider = renderer.create(
<Provider store={store}><EventLog/></Provider>)
let eventLog = TestUtils.findRenderedComponentWithType(provider, PureEventLog),
let eventLog = provider.root.findByType(PureEventLog),
mockEvent = { preventDefault: jest.fn() }
it('should handle DragStart', () => {
eventLog.onDragStart(mockEvent)
eventLog.instance.onDragStart(mockEvent)
expect(mockEvent.preventDefault).toBeCalled()
expect(window.addEventListener).toBeCalledWith('mousemove', eventLog.onDragMove)
expect(window.addEventListener).toBeCalledWith('mouseup', eventLog.onDragStop)
expect(window.addEventListener).toBeCalledWith('dragend', eventLog.onDragStop)
expect(window.addEventListener).toBeCalledWith('mousemove', eventLog.instance.onDragMove)
expect(window.addEventListener).toBeCalledWith('mouseup', eventLog.instance.onDragStop)
expect(window.addEventListener).toBeCalledWith('dragend', eventLog.instance.onDragStop)
mockEvent.preventDefault.mockClear()
})
it('should handle DragMove', () => {
eventLog.onDragMove(mockEvent)
eventLog.instance.onDragMove(mockEvent)
expect(mockEvent.preventDefault).toBeCalled()
mockEvent.preventDefault.mockClear()
})
console.error = jest.fn() // silent the error.
it('should handle DragStop', () => {
eventLog.onDragStop(mockEvent)
eventLog.instance.onDragStop(mockEvent)
expect(mockEvent.preventDefault).toBeCalled()
expect(window.removeEventListener).toBeCalledWith('mousemove', eventLog.onDragMove)
expect(window.removeEventListener).toBeCalledWith('mousemove', eventLog.instance.onDragMove)
})
})

View File

@ -15,36 +15,36 @@ describe('FlowTable Component', () => {
it('should render correctly', () => {
let provider = renderer.create(
<Provider store={store}>
<FlowTable onSelect={selectFn} flows={[tflow]}/>
<FlowTable selectFlow={selectFn} flows={[tflow]}/>
</Provider>),
tree = provider.toJSON()
expect(tree).toMatchSnapshot()
})
let provider = TestUtils.renderIntoDocument(
let provider = renderer.create(
<Provider store={store} >
<FlowTable onSelect={selectFn} flows={[tflow]}/>
<FlowTable selectFlow={selectFn} flows={[tflow]}/>
</Provider>),
flowTable = TestUtils.findRenderedComponentWithType(provider, FlowTable)
flowTable = provider.root.findByType(FlowTable)
it('should handle componentWillUnmount', () => {
flowTable.componentWillUnmount()
expect(window.addEventListener).toBeCalledWith('resize', flowTable.onViewportUpdate)
flowTable.instance.UNSAFE_componentWillUnmount()
expect(window.addEventListener).toBeCalledWith('resize', flowTable.instance.onViewportUpdate)
})
it('should handle componentDidUpdate', () => {
// flowTable.shouldScrollIntoView == false
expect(flowTable.componentDidUpdate()).toEqual(undefined)
expect(flowTable.instance.componentDidUpdate()).toEqual(undefined)
// rowTop - headHeight < viewportTop
flowTable.shouldScrollIntoView = true
flowTable.componentDidUpdate()
flowTable.instance.shouldScrollIntoView = true
flowTable.instance.componentDidUpdate()
// rowBottom > viewportTop + viewportHeight
flowTable.shouldScrollIntoView = true
flowTable.componentDidUpdate()
flowTable.instance.shouldScrollIntoView = true
flowTable.instance.componentDidUpdate()
})
it('should handle componentWillReceiveProps', () => {
flowTable.componentWillReceiveProps({selected: tflow})
expect(flowTable.shouldScrollIntoView).toBeTruthy()
flowTable.instance.UNSAFE_componentWillReceiveProps({selected: tflow})
expect(flowTable.instance.shouldScrollIntoView).toBeTruthy()
})
})

View File

@ -1,12 +1,11 @@
jest.mock('../../../components/ContentView')
jest.mock('../../../components/ContentView', () => () => null)
import React from 'react'
import renderer from 'react-test-renderer'
import TestUtils from 'react-dom/test-utils'
import { Request, Response, ErrorView } from '../../../components/FlowView/Messages'
import { Provider } from 'react-redux'
import { TFlow, TStore } from '../../ducks/tutils'
import { updateEdit } from '../../../ducks/ui/flow'
import { parseUrl } from '../../../flow/utils'
import {ErrorView, Request, Response} from '../../../components/FlowView/Messages'
import {Provider} from 'react-redux'
import {TFlow, TStore} from '../../ducks/tutils'
import {updateEdit} from '../../../ducks/ui/flow'
import {parseUrl} from '../../../flow/utils'
import ContentView from '../../../components/ContentView'
import ContentViewOptions from '../../../components/ContentView/ContentViewOptions'
import Headers from '../../../components/FlowView/Headers'
@ -20,7 +19,9 @@ store.getState().ui.flow.modifiedFlow = false
describe('Request Component', () => {
afterEach(() => {store.clearActions()})
afterEach(() => {
store.clearActions()
})
it('should render correctly', () => {
let provider = renderer.create(
@ -32,45 +33,47 @@ describe('Request Component', () => {
expect(tree).toMatchSnapshot()
})
let provider = TestUtils.renderIntoDocument(
let provider = renderer.create(
<Provider store={store}>
<Request/>
</Provider>),
valueEditors = TestUtils.scryRenderedComponentsWithType(provider, ValueEditor)
valueEditors = provider.root.findAllByType(ValueEditor)
it('should handle done on flow request method', () => {
let valueEditor = valueEditors[0]
valueEditor.props.onDone('foo')
expect(store.getActions()).toEqual([updateEdit({ request: { method: 'foo' }})])
expect(store.getActions()).toEqual([updateEdit({request: {method: 'foo'}})])
})
it('should handle done on flow request url', () => {
let valueEditor = valueEditors[1],
url = 'http://foo/bar'
valueEditor.props.onDone(url)
expect(store.getActions()).toEqual([updateEdit({ request: { path: '', ...parseUrl(url)}})])
expect(store.getActions()).toEqual([updateEdit({request: {path: '', ...parseUrl(url)}})])
})
it('should handle done on flow request http version', () => {
let valueEditor = valueEditors[2]
valueEditor.props.onDone('HTTP/9.9')
expect(store.getActions()).toEqual([updateEdit({ request: { http_version: 'HTTP/9.9' }})])
expect(store.getActions()).toEqual([updateEdit({request: {http_version: 'HTTP/9.9'}})])
})
it('should handle change on flow request header', () => {
let headers = TestUtils.scryRenderedComponentsWithType(provider, Headers).filter(headers => headers.props.type === 'headers')[0]
let headers = provider.root.findAllByType(Headers).filter(headers => headers.props.type === 'headers')[0]
headers.props.onChange('foo')
expect(store.getActions()).toEqual([updateEdit({ request: { headers: 'foo' }})])
expect(store.getActions()).toEqual([updateEdit({request: {headers: 'foo'}})])
})
it('should handle change on flow request contentView', () => {
let contentView = TestUtils.findRenderedComponentWithType(provider, ContentView)
let contentView = provider.root.findByType(ContentView)
contentView.props.onContentChange('foo')
expect(store.getActions()).toEqual([updateEdit({ request: { content: 'foo' }})])
expect(store.getActions()).toEqual([updateEdit({request: {content: 'foo'}})])
})
it('should handle uploadContent on flow request ContentViewOptions', () => {
let contentViewOptions = TestUtils.findRenderedComponentWithType(provider, ContentViewOptions)
// The line below shouldn't have .type, this is a workaround for https://github.com/facebook/react/issues/17301.
// If this test breaks, just remove it.
let contentViewOptions = provider.root.findByType(ContentViewOptions.type)
contentViewOptions.props.uploadContent('foo')
expect(fetch).toBeCalled()
fetch.mockClear()
@ -78,56 +81,60 @@ describe('Request Component', () => {
})
describe('Response Component', () => {
afterEach(() => {store.clearActions()})
afterEach(() => {
store.clearActions()
})
it('should render correctly', () => {
let provider = renderer.create(
<Provider store={store}>
<Response/>
</Provider>
),
),
tree = provider.toJSON()
expect(tree).toMatchSnapshot()
})
let provider = TestUtils.renderIntoDocument(
let provider = renderer.create(
<Provider store={store}>
<Response/>
</Provider>),
valueEditors = TestUtils.scryRenderedComponentsWithType(provider, ValueEditor)
valueEditors = provider.root.findAllByType(ValueEditor)
it('should handle done on flow response http version', () => {
let valueEditor = valueEditors[0]
valueEditor.props.onDone('HTTP/9.9')
expect(store.getActions()).toEqual([updateEdit({ response: { http_version: 'HTTP/9.9' }})])
expect(store.getActions()).toEqual([updateEdit({response: {http_version: 'HTTP/9.9'}})])
})
it('should handle done on flow response status code', () => {
let valueEditor = valueEditors[1]
valueEditor.props.onDone('404')
expect(store.getActions()).toEqual([updateEdit({ response: { code: parseInt('404') }})])
expect(store.getActions()).toEqual([updateEdit({response: {code: parseInt('404')}})])
})
it('should handle done on flow response reason', () => {
let valueEdiotr = valueEditors[2]
valueEdiotr.props.onDone('foo')
expect(store.getActions()).toEqual([updateEdit( { response: { msg: 'foo' }})])
expect(store.getActions()).toEqual([updateEdit({response: {msg: 'foo'}})])
})
it('should handle change on flow response headers', () => {
let headers = TestUtils.scryRenderedComponentsWithType(provider, Headers).filter(headers => headers.props.type === 'headers')[0]
let headers = provider.root.findAllByType(Headers).filter(headers => headers.props.type === 'headers')[0]
headers.props.onChange('foo')
expect(store.getActions()).toEqual([updateEdit( { response: { headers: 'foo' }})])
expect(store.getActions()).toEqual([updateEdit({response: {headers: 'foo'}})])
})
it('should handle change on flow response ContentView', () => {
let contentView = TestUtils.findRenderedComponentWithType(provider, ContentView)
let contentView = provider.root.findByType(ContentView)
contentView.props.onContentChange('foo')
expect(store.getActions()).toEqual([updateEdit( { response: { content: 'foo' }})])
expect(store.getActions()).toEqual([updateEdit({response: {content: 'foo'}})])
})
it('should handle updateContent on flow response ContentViewOptions', () => {
let contentViewOptions = TestUtils.findRenderedComponentWithType(provider, ContentViewOptions)
// The line below shouldn't have .type, this is a workaround for https://github.com/facebook/react/issues/17301.
// If this test breaks, just remove it.
let contentViewOptions = provider.root.findByType(ContentViewOptions.type)
contentViewOptions.props.uploadContent('foo')
expect(fetch).toBeCalled()
fetch.mockClear()

View File

@ -23,9 +23,9 @@ describe('ValidateEditor Component', () => {
isValid: s => s.length == 3,
content: "bar"
}
validateEditor.componentWillReceiveProps(mockProps)
validateEditor.UNSAFE_componentWillReceiveProps(mockProps)
expect(validateEditor.state.valid).toBeTruthy()
validateEditor.componentWillReceiveProps({...mockProps, content: "bars"})
validateEditor.UNSAFE_componentWillReceiveProps({...mockProps, content: "bars"})
expect(validateEditor.state.valid).toBeFalsy()
})

View File

@ -32,11 +32,11 @@ class FlowTable extends React.Component {
this.onViewportUpdate = this.onViewportUpdate.bind(this)
}
componentWillMount() {
UNSAFE_componentWillMount() {
window.addEventListener('resize', this.onViewportUpdate)
}
componentWillUnmount() {
UNSAFE_componentWillUnmount() {
window.removeEventListener('resize', this.onViewportUpdate)
}
@ -69,7 +69,7 @@ class FlowTable extends React.Component {
}
}
componentWillReceiveProps(nextProps) {
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.selected && nextProps.selected !== this.props.selected) {
this.shouldScrollIntoView = true
}
@ -77,11 +77,11 @@ class FlowTable extends React.Component {
onViewportUpdate() {
const viewport = ReactDOM.findDOMNode(this)
const viewportTop = viewport.scrollTop
const viewportTop = viewport.scrollTop || 0
const vScroll = calcVScroll({
viewportTop,
viewportHeight: viewport.offsetHeight,
viewportHeight: viewport.offsetHeight || 0,
itemCount: this.props.flows.length,
rowHeight: this.props.rowHeight,
})
@ -103,7 +103,7 @@ class FlowTable extends React.Component {
<FlowTableHead />
</thead>
<tbody>
<tr style={{ height: vScroll.paddingTop }}></tr>
<tr style={{ height: vScroll.paddingTop }}/>
{flows.slice(vScroll.start, vScroll.end).map(flow => (
<FlowRow
key={flow.id}
@ -113,7 +113,7 @@ class FlowTable extends React.Component {
onSelect={this.props.selectFlow}
/>
))}
<tr style={{ height: vScroll.paddingBottom }}></tr>
<tr style={{ height: vScroll.paddingBottom }}/>
</tbody>
</table>
</div>

View File

@ -20,14 +20,14 @@ export function TimeStamp({ t, deltaTo, title }) {
)
}
export function ConnectionInfo({ conn }) {
export function ConnectionInfo({ conn }) {
return (
<table className="connection-table">
<tbody>
<tr key="address">
<td>Address:</td>
<td>{conn.address.join(':')}</td>
</tr>
</tr>
{conn.sni && (
<tr key="sni">
<td><abbr title="TLS Server Name Indication">TLS SNI:</abbr></td>
@ -148,13 +148,13 @@ export default function Details({ flow }) {
<h4>Client Connection</h4>
<ConnectionInfo conn={flow.client_conn}/>
{flow.server_conn.address &&
{flow.server_conn.address &&
[
<h4>Server Connection</h4>,
<ConnectionInfo conn={flow.server_conn}/>
]
<h4 key="sc">Server Connection</h4>,
<ConnectionInfo key="sc-ci" conn={flow.server_conn}/>
]
}
<CertificateInfo flow={flow}/>
<Timing flow={flow}/>

View File

@ -100,6 +100,12 @@ export class Request extends Component {
/>
<hr/>
<ContentView
readonly={!isEdit}
flow={flow}
onContentChange={content => updateFlow({ request: {content}})}
message={flow.request}/>
<hr/>
<Headers
message={flow.request}
@ -146,6 +152,12 @@ export class Response extends Component {
onChange={headers => updateFlow({ response: { headers } })}
/>
<hr/>
<ContentView
readonly={!isEdit}
flow={flow}
onContentChange={content => updateFlow({ response: {content}})}
message={flow.response}
/>
<hr/>
<Headers
message={flow.response}

View File

@ -21,7 +21,7 @@ export default class ValidateEditor extends Component {
this.onDone = this.onDone.bind(this)
}
componentWillReceiveProps(nextProps) {
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({ valid: nextProps.isValid(nextProps.content) })
}

View File

@ -8,7 +8,7 @@ export default Component => Object.assign(class AutoScrollWrapper extends Compon
static displayName = Component.name;
componentWillUpdate() {
UNSAFE_componentWillUpdate() {
const viewport = ReactDOM.findDOMNode(this);
this[symShouldStick] = viewport.scrollTop && isAtBottom(viewport);
super.componentWillUpdate && super.componentWillUpdate();

View File

@ -18,7 +18,7 @@
esutils "^2.0.2"
js-tokens "^4.0.0"
"@babel/runtime@^7.4.5", "@babel/runtime@^7.9.2":
"@babel/runtime@^7.12.1", "@babel/runtime@^7.9.2":
version "7.14.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6"
integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==
@ -42,6 +42,43 @@
normalize-path "^2.0.1"
through2 "^2.0.3"
"@types/hoist-non-react-statics@^3.3.0":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
dependencies:
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
"@types/prop-types@*":
version "15.7.3"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
"@types/react-redux@^7.1.16":
version "7.1.16"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.16.tgz#0fbd04c2500c12105494c83d4a3e45c084e3cb21"
integrity sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==
dependencies:
"@types/hoist-non-react-statics" "^3.3.0"
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
redux "^4.0.0"
"@types/react@*":
version "17.0.10"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.10.tgz#c8bb4e37cc642f7cc5532959cb5e2ead6c74dec9"
integrity sha512-+Tc5aGO49L/cjFBfpIPB398ztmAUChglc+a+EYlvphMOMvwUEzmLiyfmnEseGE7inMO6XiSffHmXVPC8GonksQ==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/scheduler@*":
version "0.16.1"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275"
integrity sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==
JSONStream@^1.0.3:
version "1.3.0"
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.0.tgz#680ab9ac6572a8a1a207e0b38721db1c77b215e5"
@ -2106,6 +2143,11 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
dependencies:
cssom "0.3.x"
csstype@^3.0.2:
version "3.0.8"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340"
integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==
currently-unhandled@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
@ -3774,7 +3816,7 @@ hoek@2.x.x:
version "2.16.3"
resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
hoist-non-react-statics@^3.3.0:
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@ -3987,13 +4029,6 @@ invariant@^2.2.0, invariant@^2.2.2:
dependencies:
loose-envify "^1.0.0"
invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
dependencies:
loose-envify "^1.0.0"
invert-kv@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
@ -6343,22 +6378,22 @@ react-dom@^17.0.2:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6:
react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-redux@7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.1.0.tgz#72af7cf490a74acdc516ea9c1dd80e25af9ea0b2"
integrity sha512-hyu/PoFK3vZgdLTg9ozbt7WF3GgX5+Yn3pZm5/96/o4UueXA+zj08aiSC9Mfj2WtD1bvpIb3C5yvskzZySzzaw==
react-redux@^7.2.4:
version "7.2.4"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.4.tgz#1ebb474032b72d806de2e0519cd07761e222e225"
integrity sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==
dependencies:
"@babel/runtime" "^7.4.5"
hoist-non-react-statics "^3.3.0"
invariant "^2.2.4"
"@babel/runtime" "^7.12.1"
"@types/react-redux" "^7.1.16"
hoist-non-react-statics "^3.3.2"
loose-envify "^1.4.0"
prop-types "^15.7.2"
react-is "^16.8.6"
react-is "^16.13.1"
react-shallow-renderer@^16.13.1:
version "16.14.1"
@ -6538,7 +6573,7 @@ redux-thunk@^2.3.0:
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
redux@^4.1.0:
redux@^4.0.0, redux@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.0.tgz#eb049679f2f523c379f1aff345c8612f294c88d4"
integrity sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==