diff options
author | Maximilian Hils <git@maximilianhils.com> | 2017-05-18 13:05:15 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-18 13:05:15 +0200 |
commit | a9e002af18b82a6f476507a9ff03eebcc19f867c (patch) | |
tree | 943790e81a810d4fd2fb4fc185109aff0049823b /web/src | |
parent | 4b1cd76f3ea1255620ae8db3eb8ba3bb33840166 (diff) | |
parent | 4e4be8bd6854f8e5364049fa30e51e8ab0127e9b (diff) | |
download | mitmproxy-a9e002af18b82a6f476507a9ff03eebcc19f867c.tar.gz mitmproxy-a9e002af18b82a6f476507a9ff03eebcc19f867c.tar.bz2 mitmproxy-a9e002af18b82a6f476507a9ff03eebcc19f867c.zip |
Merge pull request #2337 from MatthewShao/jest-dev
[WIP][web] Add tests for UI components
Diffstat (limited to 'web/src')
7 files changed, 529 insertions, 0 deletions
diff --git a/web/src/js/__tests__/components/FlowTable/FlowColumnsSpec.js b/web/src/js/__tests__/components/FlowTable/FlowColumnsSpec.js new file mode 100644 index 00000000..576838f4 --- /dev/null +++ b/web/src/js/__tests__/components/FlowTable/FlowColumnsSpec.js @@ -0,0 +1,102 @@ +import React from 'react' +import renderer from 'react-test-renderer' +import * as Columns from '../../../components/FlowTable/FlowColumns' +import { TFlow } from '../../ducks/tutils' + +describe('FlowColumns Components', () => { + + let tFlow = new TFlow() + it('should render TLSColumn', () => { + let tlsColumn = renderer.create(<Columns.TLSColumn flow={tFlow}/>), + tree = tlsColumn.toJSON() + expect(tree).toMatchSnapshot() + }) + + it('should render IconColumn', () => { + let iconColumn = renderer.create(<Columns.IconColumn flow={tFlow}/>), + tree = iconColumn.toJSON() + // plain + expect(tree).toMatchSnapshot() + // not modified + tFlow.response.status_code = 304 + iconColumn = renderer.create(<Columns.IconColumn flow={tFlow}/>) + tree = iconColumn.toJSON() + expect(tree).toMatchSnapshot() + // redirect + tFlow.response.status_code = 302 + iconColumn = renderer.create(<Columns.IconColumn flow={tFlow}/>) + tree = iconColumn.toJSON() + expect(tree).toMatchSnapshot() + // image + let imageFlow = new TFlow() + imageFlow.response.headers = [['Content-Type', 'image/jpeg']] + iconColumn = renderer.create(<Columns.IconColumn flow={imageFlow}/>) + tree = iconColumn.toJSON() + expect(tree).toMatchSnapshot() + // javascript + let jsFlow = new TFlow() + jsFlow.response.headers = [['Content-Type', 'application/x-javascript']] + iconColumn = renderer.create(<Columns.IconColumn flow={jsFlow}/>) + tree = iconColumn.toJSON() + expect(tree).toMatchSnapshot() + // css + let cssFlow = new TFlow() + cssFlow.response.headers = [['Content-Type', 'text/css']] + iconColumn = renderer.create(<Columns.IconColumn flow={cssFlow}/>) + tree = iconColumn.toJSON() + expect(tree).toMatchSnapshot() + // default + let fooFlow = new TFlow() + fooFlow.response.headers = [['Content-Type', 'foo']] + iconColumn = renderer.create(<Columns.IconColumn flow={fooFlow}/>) + tree = iconColumn.toJSON() + expect(tree).toMatchSnapshot() + // no response + tFlow.response = null + iconColumn = renderer.create(<Columns.IconColumn flow={tFlow}/>) + tree = iconColumn.toJSON() + expect(tree).toMatchSnapshot() + }) + + it('should render pathColumn', () => { + let pathColumn = renderer.create(<Columns.PathColumn flow={tFlow}/>), + tree = pathColumn.toJSON() + expect(tree).toMatchSnapshot() + + tFlow.error.msg = 'Connection killed' + tFlow.intercepted = true + pathColumn = renderer.create(<Columns.PathColumn flow={tFlow}/>) + tree = pathColumn.toJSON() + expect(tree).toMatchSnapshot() + }) + + it('should render MethodColumn', () => { + let methodColumn =renderer.create(<Columns.MethodColumn flow={tFlow}/>), + tree = methodColumn.toJSON() + expect(tree).toMatchSnapshot() + }) + + it('should render StatusColumn', () => { + let statusColumn = renderer.create(<Columns.StatusColumn flow={tFlow}/>), + tree = statusColumn.toJSON() + expect(tree).toMatchSnapshot() + }) + + it('should render SizeColumn', () => { + tFlow = new TFlow() + let sizeColumn = renderer.create(<Columns.SizeColumn flow={tFlow}/>), + tree = sizeColumn.toJSON() + expect(tree).toMatchSnapshot() + }) + + it('should render TimeColumn', () => { + let timeColumn = renderer.create(<Columns.TimeColumn flow={tFlow}/>), + tree = timeColumn.toJSON() + expect(tree).toMatchSnapshot() + + tFlow.response = null + timeColumn = renderer.create(<Columns.TimeColumn flow={tFlow}/>), + tree = timeColumn.toJSON() + expect(tree).toMatchSnapshot() + }) +}) diff --git a/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowColumnsSpec.js.snap b/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowColumnsSpec.js.snap new file mode 100644 index 00000000..ec260e1e --- /dev/null +++ b/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowColumnsSpec.js.snap @@ -0,0 +1,156 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`FlowColumns Components should render IconColumn 1`] = ` +<td + className="col-icon" +> + <div + className="resource-icon resource-icon-document" + /> +</td> +`; + +exports[`FlowColumns Components should render IconColumn 2`] = ` +<td + className="col-icon" +> + <div + className="resource-icon resource-icon-not-modified" + /> +</td> +`; + +exports[`FlowColumns Components should render IconColumn 3`] = ` +<td + className="col-icon" +> + <div + className="resource-icon resource-icon-redirect" + /> +</td> +`; + +exports[`FlowColumns Components should render IconColumn 4`] = ` +<td + className="col-icon" +> + <div + className="resource-icon resource-icon-image" + /> +</td> +`; + +exports[`FlowColumns Components should render IconColumn 5`] = ` +<td + className="col-icon" +> + <div + className="resource-icon resource-icon-js" + /> +</td> +`; + +exports[`FlowColumns Components should render IconColumn 6`] = ` +<td + className="col-icon" +> + <div + className="resource-icon resource-icon-css" + /> +</td> +`; + +exports[`FlowColumns Components should render IconColumn 7`] = ` +<td + className="col-icon" +> + <div + className="resource-icon resource-icon-plain" + /> +</td> +`; + +exports[`FlowColumns Components should render IconColumn 8`] = ` +<td + className="col-icon" +> + <div + className="resource-icon resource-icon-plain" + /> +</td> +`; + +exports[`FlowColumns Components should render MethodColumn 1`] = ` +<td + className="col-method" +> + GET +</td> +`; + +exports[`FlowColumns Components should render SizeColumn 1`] = ` +<td + className="col-size" +> + 100b +</td> +`; + +exports[`FlowColumns Components should render StatusColumn 1`] = ` +<td + className="col-status" +/> +`; + +exports[`FlowColumns Components should render TLSColumn 1`] = ` +<td + className="col-tls col-tls-http" +/> +`; + +exports[`FlowColumns Components should render TimeColumn 1`] = ` +<td + className="col-time" +> + 2min +</td> +`; + +exports[`FlowColumns Components should render TimeColumn 2`] = ` +<td + className="col-time" +> + ... +</td> +`; + +exports[`FlowColumns Components should render pathColumn 1`] = ` +<td + className="col-path" +> + <i + className="fa fa-fw fa-repeat pull-right" + /> + <i + className="fa fa-fw fa-exclamation pull-right" + /> + http://undefined:undefinedundefined +</td> +`; + +exports[`FlowColumns Components should render pathColumn 2`] = ` +<td + className="col-path" +> + <i + className="fa fa-fw fa-repeat pull-right" + /> + <i + className="fa fa-fw fa-pause pull-right" + /> + <i + className="fa fa-fw fa-times pull-right" + /> + http://undefined:undefinedundefined +</td> +`; diff --git a/web/src/js/__tests__/components/ValueEditor/ValidateEditorSpec.js b/web/src/js/__tests__/components/ValueEditor/ValidateEditorSpec.js new file mode 100644 index 00000000..32dabe59 --- /dev/null +++ b/web/src/js/__tests__/components/ValueEditor/ValidateEditorSpec.js @@ -0,0 +1,47 @@ +import React from 'react' +import renderer from 'react-test-renderer' +import TestUtils from 'react-dom/test-utils' +import ValidateEditor from '../../../components/ValueEditor/ValidateEditor' + +describe('ValidateEditor Component', () => { + let validateFn = jest.fn( content => content.length == 3), + doneFn = jest.fn() + + it('should render correctly', () => { + let validateEditor = renderer.create( + <ValidateEditor content="foo" onDone={doneFn} isValid={validateFn}/> + ), + tree = validateEditor.toJSON() + expect(tree).toMatchSnapshot() + }) + + let validateEditor = TestUtils.renderIntoDocument( + <ValidateEditor content="foo" onDone={doneFn} isValid={validateFn}/> + ) + it('should handle componentWillReceiveProps', () => { + let mockProps = { + isValid: s => s.length == 3, + content: "bar" + } + validateEditor.componentWillReceiveProps(mockProps) + expect(validateEditor.state.valid).toBeTruthy() + validateEditor.componentWillReceiveProps({...mockProps, content: "bars"}) + expect(validateEditor.state.valid).toBeFalsy() + + }) + + it('should handle input', () => { + validateEditor.onInput("foo bar") + expect(validateFn).toBeCalledWith("foo bar") + }) + + it('should handle done', () => { + // invalid + validateEditor.editor.reset = jest.fn() + validateEditor.onDone("foo bar") + expect(validateEditor.editor.reset).toBeCalled() + // valid + validateEditor.onDone("bar") + expect(doneFn).toBeCalledWith("bar") + }) +}) diff --git a/web/src/js/__tests__/components/ValueEditor/ValueEditorSpec.js b/web/src/js/__tests__/components/ValueEditor/ValueEditorSpec.js new file mode 100644 index 00000000..f94a6acc --- /dev/null +++ b/web/src/js/__tests__/components/ValueEditor/ValueEditorSpec.js @@ -0,0 +1,155 @@ +import React from 'react' +import renderer from 'react-test-renderer' +import TestUtils from 'react-dom/test-utils' +import ValueEditor from '../../../components/ValueEditor/ValueEditor' +import { Key } from '../../../utils' + +describe('ValueEditor Component', () => { + + let mockFn = jest.fn() + it ('should render correctly', () => { + let valueEditor = renderer.create( + <ValueEditor content="foo" onDone={mockFn}/> + ), + tree = valueEditor.toJSON() + expect(tree).toMatchSnapshot() + }) + + let valueEditor = TestUtils.renderIntoDocument( + <ValueEditor content="<script>foo</script>" onDone={mockFn}/> + ) + it('should handle this.blur', () => { + valueEditor.input.blur = jest.fn() + valueEditor.blur() + expect(valueEditor.input.blur).toHaveBeenCalled() + }) + + it('should handle reset', () => { + valueEditor.reset() + expect(valueEditor.input.innerHTML).toEqual( + "<script>foo</script>" + ) + }) + + it('should handle paste', () => { + let mockEvent = { + preventDefault: jest.fn(), + clipboardData: { getData: (t) => "foo content"} + } + document.execCommand = jest.fn() + valueEditor.onPaste(mockEvent) + expect(document.execCommand).toBeCalledWith('insertHTML', false, "foo content") + }) + + it('should handle mouseDown', () => { + window.addEventListener = jest.fn() + valueEditor.onMouseDown({}) + expect(valueEditor._mouseDown).toBeTruthy() + expect(window.addEventListener).toBeCalledWith('mouseup', valueEditor.onMouseUp) + }) + + it('should handle mouseUp', () => { + window.removeEventListener = jest.fn() + valueEditor.onMouseUp() + expect(window.removeEventListener).toBeCalledWith('mouseup', valueEditor.onMouseUp) + }) + + it('should handle focus', () => { + let mockEvent = { clientX: 1, clientY: 2 }, + mockSelection = { + rangeCount: 1, + getRangeAt: jest.fn( (index) => {return { selectNodeContents: jest.fn() }}), + removeAllRanges: jest.fn(), + addRange: jest.fn() + }, + clearState = (v) => { + v._mouseDown = false + v._ignore_events = false + v.state.editable = false + } + window.getSelection = () => mockSelection + + // return undefined when mouse down + valueEditor.onMouseDown() + expect(valueEditor.onFocus(mockEvent)).toEqual(undefined) + valueEditor.onMouseUp() + + // sel.rangeCount > 0 + valueEditor.onFocus(mockEvent) + expect(mockSelection.getRangeAt).toBeCalledWith(0) + expect(valueEditor.state.editable).toBeTruthy() + expect(mockSelection.removeAllRanges).toBeCalled() + expect(mockSelection.addRange).toBeCalled() + clearState(valueEditor) + + // document.caretPositionFromPoint + mockSelection.rangeCount = 0 + let mockRange = { setStart: jest.fn(), selectNodeContents: jest.fn() } + + document.caretPositionFromPoint = jest.fn((x, y) => { + return { offsetNode: 0, offset: x + y} + }) + document.createRange = jest.fn(() => mockRange) + valueEditor.onFocus(mockEvent) + expect(mockRange.setStart).toBeCalledWith(0, 3) + clearState(valueEditor) + document.caretPositionFromPoint = null + + //document.caretRangeFromPoint + document.caretRangeFromPoint = jest.fn(() => mockRange) + valueEditor.onFocus(mockEvent) + expect(document.caretRangeFromPoint).toBeCalledWith(1, 2) + clearState(valueEditor) + document.caretRangeFromPoint = null + + //else + valueEditor.onFocus(mockEvent) + expect(mockRange.selectNodeContents).toBeCalledWith(valueEditor.input) + clearState(valueEditor) + }) + + it('should handle click', () => { + valueEditor.onMouseUp = jest.fn() + valueEditor.onFocus = jest.fn() + valueEditor.onClick('foo') + expect(valueEditor.onMouseUp).toBeCalled() + expect(valueEditor.onFocus).toBeCalledWith('foo') + }) + + it('should handle blur', () => { + // return undefined + valueEditor._ignore_events = true + expect(valueEditor.onBlur({})).toEqual(undefined) + // else + valueEditor._ignore_events = false + valueEditor.onBlur({}) + expect(valueEditor.state.editable).toBeFalsy() + expect(valueEditor.props.onDone).toBeCalledWith(valueEditor.input.textContent) + }) + + it('should handle key down', () => { + let mockKeyEvent = (keyCode, shiftKey=false) => { + return { + keyCode: keyCode, + shiftKey: shiftKey, + stopPropagation: jest.fn(), + preventDefault: jest.fn() + } + } + valueEditor.reset = jest.fn() + valueEditor.blur = jest.fn() + valueEditor.onKeyDown(mockKeyEvent(Key.ESC)) + expect(valueEditor.reset).toBeCalled() + expect(valueEditor.blur).toBeCalled() + valueEditor.blur.mockReset() + + valueEditor.onKeyDown(mockKeyEvent(Key.ENTER)) + expect(valueEditor.blur).toBeCalled() + + valueEditor.onKeyDown(mockKeyEvent(Key.SPACE)) + }) + + it('should handle input', () => { + valueEditor.onInput() + }) +}) diff --git a/web/src/js/__tests__/components/ValueEditor/__snapshots__/ValidateEditorSpec.js.snap b/web/src/js/__tests__/components/ValueEditor/__snapshots__/ValidateEditorSpec.js.snap new file mode 100644 index 00000000..96b9ce19 --- /dev/null +++ b/web/src/js/__tests__/components/ValueEditor/__snapshots__/ValidateEditorSpec.js.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ValidateEditor Component should render correctly 1`] = ` +<div + className="inline-input editable has-success" + contentEditable={undefined} + dangerouslySetInnerHTML={ + Object { + "__html": "foo", + } + } + onBlur={[Function]} + onClick={[Function]} + onFocus={[Function]} + onInput={[Function]} + onKeyDown={[Function]} + onMouseDown={[Function]} + onPaste={[Function]} + tabIndex={0} +/> +`; diff --git a/web/src/js/__tests__/components/ValueEditor/__snapshots__/ValueEditorSpec.js.snap b/web/src/js/__tests__/components/ValueEditor/__snapshots__/ValueEditorSpec.js.snap new file mode 100644 index 00000000..91e8ee84 --- /dev/null +++ b/web/src/js/__tests__/components/ValueEditor/__snapshots__/ValueEditorSpec.js.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ValueEditor Component should render correctly 1`] = ` +<div + className="inline-input editable" + contentEditable={undefined} + dangerouslySetInnerHTML={ + Object { + "__html": "foo", + } + } + onBlur={[Function]} + onClick={[Function]} + onFocus={[Function]} + onInput={[Function]} + onKeyDown={[Function]} + onMouseDown={[Function]} + onPaste={[Function]} + tabIndex={0} +/> +`; diff --git a/web/src/js/__tests__/ducks/tutils.js b/web/src/js/__tests__/ducks/tutils.js index 6ae7f080..f140222d 100644 --- a/web/src/js/__tests__/ducks/tutils.js +++ b/web/src/js/__tests__/ducks/tutils.js @@ -7,3 +7,30 @@ export function createStore(parts) { applyMiddleware(...[thunk]) ) } + +export function TFlow(intercepted=false, marked=false, modified=false) { + return { + intercepted , + marked, + modified, + id: "foo", + request: { + scheme: 'http', + is_replay: true, + method: 'GET', + contentLength: 100 + }, + response: { + status_code: 200, + headers: [["Content-Type", 'text/html']], + timestamp_end: 200 + }, + error: { + msg: '' + }, + server_conn: { + timestamp_start: 100 + }, + type: 'http' + } +} |