diff --git a/web/jest.config.js b/web/jest.config.js new file mode 100644 index 000000000..3f4a9df60 --- /dev/null +++ b/web/jest.config.js @@ -0,0 +1,18 @@ +process.env.TZ = 'UTC'; + +module.exports = { + "testRegex": "__tests__/.*Spec.js$", + "roots": [ + "/src/js" + ], + "unmockedModulePathPatterns": [ + "react" + ], + "coverageDirectory": "./coverage", + "coveragePathIgnorePatterns": [ + "/src/js/filt/filt.js" + ], + "collectCoverageFrom": [ + "src/js/**/*.{js,jsx}" + ] +}; diff --git a/web/package.json b/web/package.json index 55d555090..e71a93f50 100644 --- a/web/package.json +++ b/web/package.json @@ -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", diff --git a/web/src/js/__tests__/components/ContentView/ContentViewSpec.js b/web/src/js/__tests__/components/ContentView/ContentViewSpec.js index f519185dd..499da6e8a 100644 --- a/web/src/js/__tests__/components/ContentView/ContentViewSpec.js +++ b/web/src/js/__tests__/components/ContentView/ContentViewSpec.js @@ -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', () => { diff --git a/web/src/js/__tests__/components/EventLogSpec.js b/web/src/js/__tests__/components/EventLogSpec.js index 8510de557..e29b74592 100644 --- a/web/src/js/__tests__/components/EventLogSpec.js +++ b/web/src/js/__tests__/components/EventLogSpec.js @@ -27,31 +27,31 @@ describe('EventLog Component', () => { debugToggleButton.props.onClick() }) - provider = TestUtils.renderIntoDocument( + provider = renderer.create( ) - 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) }) }) diff --git a/web/src/js/__tests__/components/FlowTableSpec.js b/web/src/js/__tests__/components/FlowTableSpec.js index f63b28fcb..0006c4308 100644 --- a/web/src/js/__tests__/components/FlowTableSpec.js +++ b/web/src/js/__tests__/components/FlowTableSpec.js @@ -15,36 +15,36 @@ describe('FlowTable Component', () => { it('should render correctly', () => { let provider = renderer.create( - + ), tree = provider.toJSON() expect(tree).toMatchSnapshot() }) - let provider = TestUtils.renderIntoDocument( + let provider = renderer.create( - + ), - 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() }) }) diff --git a/web/src/js/__tests__/components/FlowView/MessagesSpec.js b/web/src/js/__tests__/components/FlowView/MessagesSpec.js index c972a2e06..79b9a9a41 100644 --- a/web/src/js/__tests__/components/FlowView/MessagesSpec.js +++ b/web/src/js/__tests__/components/FlowView/MessagesSpec.js @@ -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( ), - 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( - ), + ), tree = provider.toJSON() expect(tree).toMatchSnapshot() }) - let provider = TestUtils.renderIntoDocument( + let provider = renderer.create( ), - 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() diff --git a/web/src/js/__tests__/components/ValueEditor/ValidateEditorSpec.js b/web/src/js/__tests__/components/ValueEditor/ValidateEditorSpec.js index 32dabe591..329a9a85a 100644 --- a/web/src/js/__tests__/components/ValueEditor/ValidateEditorSpec.js +++ b/web/src/js/__tests__/components/ValueEditor/ValidateEditorSpec.js @@ -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() }) diff --git a/web/src/js/components/FlowTable.jsx b/web/src/js/components/FlowTable.jsx index a6381d0d8..58618e031 100644 --- a/web/src/js/components/FlowTable.jsx +++ b/web/src/js/components/FlowTable.jsx @@ -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 { - + {flows.slice(vScroll.start, vScroll.end).map(flow => ( ))} - + diff --git a/web/src/js/components/FlowView/Details.jsx b/web/src/js/components/FlowView/Details.jsx index d231afc71..8fa5c3f99 100644 --- a/web/src/js/components/FlowView/Details.jsx +++ b/web/src/js/components/FlowView/Details.jsx @@ -20,14 +20,14 @@ export function TimeStamp({ t, deltaTo, title }) { ) } -export function ConnectionInfo({ conn }) { +export function ConnectionInfo({ conn }) { return ( - + {conn.sni && ( @@ -148,13 +148,13 @@ export default function Details({ flow }) {

Client Connection

- {flow.server_conn.address && + {flow.server_conn.address && [ -

Server Connection

, - - ] +

Server Connection

, + + ] } - + diff --git a/web/src/js/components/FlowView/Messages.jsx b/web/src/js/components/FlowView/Messages.jsx index 4d67b5c69..ceb48ce0c 100644 --- a/web/src/js/components/FlowView/Messages.jsx +++ b/web/src/js/components/FlowView/Messages.jsx @@ -100,6 +100,12 @@ export class Request extends Component { />
+ updateFlow({ request: {content}})} + message={flow.request}/> +
updateFlow({ response: { headers } })} />
+ updateFlow({ response: {content}})} + message={flow.response} + />
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(); diff --git a/web/yarn.lock b/web/yarn.lock index f007aa4f8..1479f0c4f 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -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==
Address: {conn.address.join(':')}
TLS SNI: