Merge pull request #2337 from MatthewShao/jest-dev

[WIP][web] Add tests for UI components
This commit is contained in:
Maximilian Hils 2017-05-18 13:05:15 +02:00 committed by GitHub
commit a9e002af18
7 changed files with 529 additions and 0 deletions

View File

@ -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()
})
})

View File

@ -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>
`;

View File

@ -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")
})
})

View File

@ -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(
"&lt;script&gt;foo&lt;/script&gt;"
)
})
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()
})
})

View File

@ -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}
/>
`;

View File

@ -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}
/>
`;

View File

@ -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'
}
}