Merge pull request #2219 from MatthewShao/jest-dev

[web] Coverage++ for ducks/flows.js
This commit is contained in:
Maximilian Hils 2017-04-25 20:26:45 +02:00 committed by GitHub
commit 7ee0abbe0c
4 changed files with 243 additions and 50 deletions

1
.gitignore vendored
View File

@ -22,3 +22,4 @@ sslkeylogfile.log
.tox/
.python-version
coverage.xml
web/coverage/

View File

@ -1,31 +1,225 @@
jest.unmock('../../ducks/flows');
jest.mock('../../utils')
import reduceFlows, * as flowActions from '../../ducks/flows'
import * as storeActions from '../../ducks/utils/store'
import reduceFlows from "../../ducks/flows"
import * as flowActions from "../../ducks/flows"
import reduceStore from "../../ducks/utils/store"
import {fetchApi} from "../../utils"
import {createStore} from "./tutils"
describe('select flow', () => {
let state = reduceFlows(undefined, {})
describe('flow reducer', () => {
let state = undefined
for (let i of [1, 2, 3, 4]) {
state = reduceFlows(state, storeActions.add({ id: i }))
state = reduceFlows(state, { type: flowActions.ADD, data: { id: i }, cmd: 'add' })
}
it('should be possible to select a single flow', () => {
expect(reduceFlows(state, flowActions.select(2))).toEqual(
{
...state,
selected: [2],
}
)
it('should return initial state', () => {
expect(reduceFlows(undefined, {})).toEqual({
highlight: null,
filter: null,
sort: { column: null, desc: false },
selected: [],
...reduceStore(undefined, {})
})
})
it('should be possible to deselect a flow', () => {
expect(reduceFlows({ ...state, selected: [1] }, flowActions.select())).toEqual(
{
...state,
selected: [],
}
)
describe('selections', () => {
it('should be possible to select a single flow', () => {
expect(reduceFlows(state, flowActions.select(2))).toEqual(
{
...state,
selected: [2],
}
)
})
it('should be possible to deselect a flow', () => {
expect(reduceFlows({ ...state, selected: [1] }, flowActions.select())).toEqual(
{
...state,
selected: [],
}
)
})
it('should be possible to select relative', () => {
// haven't selected any flow
expect(
flowActions.selectRelative(state, 1)
).toEqual(
flowActions.select(4)
)
// already selected some flows
expect(
flowActions.selectRelative({ ...state, selected: [2] }, 1)
).toEqual(
flowActions.select(3)
)
})
it('should update state.selected on remove', () => {
let next
next = reduceFlows({ ...state, selected: [2] }, {
type: flowActions.REMOVE,
data: 2,
cmd: 'remove'
})
expect(next.selected).toEqual([3])
//last row
next = reduceFlows({ ...state, selected: [4] }, {
type: flowActions.REMOVE,
data: 4,
cmd: 'remove'
})
expect(next.selected).toEqual([3])
//multiple selection
next = reduceFlows({ ...state, selected: [2, 3, 4] }, {
type: flowActions.REMOVE,
data: 3,
cmd: 'remove'
})
expect(next.selected).toEqual([2, 4])
})
})
it('should be possible to set filter', () => {
let filt = "~u 123"
expect(reduceFlows(undefined, flowActions.setFilter(filt)).filter).toEqual(filt)
})
it('should be possible to set highlight', () => {
let key = "foo"
expect(reduceFlows(undefined, flowActions.setHighlight(key)).highlight).toEqual(key)
})
it('should be possible to set sort', () => {
let sort = { column: "TLSColumn", desc: 1 }
expect(reduceFlows(undefined, flowActions.setSort(sort.column, sort.desc)).sort).toEqual(sort)
})
})
describe('flows actions', () => {
let store = createStore({reduceFlows})
let tflow = { id: 1 }
it('should handle resume action', () => {
store.dispatch(flowActions.resume(tflow))
expect(fetchApi).toBeCalledWith('/flows/1/resume', { method: 'POST' })
})
it('should handle resumeAll action', () => {
store.dispatch(flowActions.resumeAll())
expect(fetchApi).toBeCalledWith('/flows/resume', { method: 'POST' })
})
it('should handle kill action', () => {
store.dispatch(flowActions.kill(tflow))
expect(fetchApi).toBeCalledWith('/flows/1/kill', { method: 'POST' })
})
it('should handle killAll action', () => {
store.dispatch(flowActions.killAll())
expect(fetchApi).toBeCalledWith('/flows/kill', { method: 'POST' })
})
it('should handle remove action', () => {
store.dispatch(flowActions.remove(tflow))
expect(fetchApi).toBeCalledWith('/flows/1', { method: 'DELETE' })
})
it('should handle duplicate action', () => {
store.dispatch(flowActions.duplicate(tflow))
expect(fetchApi).toBeCalledWith('/flows/1/duplicate', { method: 'POST' })
})
it('should handle replay action', () => {
store.dispatch(flowActions.replay(tflow))
expect(fetchApi).toBeCalledWith('/flows/1/replay', { method: 'POST' })
})
it('should handle revert action', () => {
store.dispatch(flowActions.revert(tflow))
expect(fetchApi).toBeCalledWith('/flows/1/revert', { method: 'POST' })
})
it('should handle update action', () => {
store.dispatch(flowActions.update(tflow, 'foo'))
expect(fetchApi.put).toBeCalledWith('/flows/1', 'foo')
})
it('should handle uploadContent action', () => {
let body = new FormData(),
file = new window.Blob(['foo'], { type: 'plain/text' })
body.append('file', file)
store.dispatch(flowActions.uploadContent(tflow, 'foo', 'foo'))
expect(fetchApi).toBeCalledWith('/flows/1/foo/content', { method: 'POST', body})
})
it('should handle clear action', () => {
store.dispatch(flowActions.clear())
expect(fetchApi).toBeCalledWith('/clear', { method: 'POST'} )
})
it('should handle download action', () => {
let state = reduceFlows(undefined, {})
expect(reduceFlows(state, flowActions.download())).toEqual(state)
})
it('should handle upload action', () => {
let body = new FormData()
body.append('file', 'foo')
store.dispatch(flowActions.upload('foo'))
expect(fetchApi).toBeCalledWith('/flows/dump', { method: 'POST', body })
})
})
describe('makeSort', () => {
it('should be possible to sort by TLSColumn', () => {
let sort = flowActions.makeSort({ column: 'TLSColumn', desc: true }),
a = { request: { scheme: 'http' } },
b = { request: { scheme: 'https' } }
expect(sort(a, b)).toEqual(1)
})
it('should be possible to sort by PathColumn', () => {
let sort = flowActions.makeSort({ column: 'PathColumn', desc: true }),
a = { request: {} },
b = { request: {} }
expect(sort(a, b)).toEqual(0)
})
it('should be possible to sort by MethodColumn', () => {
let sort = flowActions.makeSort({ column: 'MethodColumn', desc: true }),
a = { request: { method: 'GET' } },
b = { request: { method: 'POST' } }
expect(sort(b, a)).toEqual(-1)
})
it('should be possible to sort by StatusColumn', () => {
let sort = flowActions.makeSort({ column: 'StatusColumn', desc: false }),
a = { response: { status_code: 200 } },
b = { response: { status_code: 404 } }
expect(sort(a, b)).toEqual(-1)
})
it('should be possible to sort by TimeColumn', () => {
let sort = flowActions.makeSort({ column: 'TimeColumn', desc: false }),
a = { response: { timestamp_end: 9 }, request: { timestamp_start: 8 } },
b = { response: { timestamp_end: 10 }, request: { timestamp_start: 8 } }
expect(sort(b, a)).toEqual(1)
})
it('should be possible to sort by SizeColumn', () => {
let sort = flowActions.makeSort({ column: 'SizeColumn', desc: true }),
a = { request: { contentLength: 1 }, response: { contentLength: 1 } },
b = { request: { contentLength: 1 } }
expect(sort(a, b)).toEqual(-1)
})
})

View File

@ -1,5 +1,6 @@
import { fetchApi } from "../utils"
import reduceStore, * as storeActions from "./utils/store"
import reduceStore from "./utils/store"
import * as storeActions from "./utils/store"
import Filt from "../filt/filt"
import { RequestUtils } from "../flow/utils"
@ -29,8 +30,6 @@ export default function reduce(state = defaultState, action) {
case UPDATE:
case REMOVE:
case RECEIVE:
// FIXME: Update state.selected on REMOVE:
// The selected flow may have been removed, we need to select the next one in the view.
let storeAction = storeActions[action.cmd](
action.data,
makeFilter(state.filter),
@ -152,22 +151,20 @@ export function setSort(column, desc) {
return { type: SET_SORT, sort: { column, desc } }
}
export function selectRelative(shift) {
return (dispatch, getState) => {
let currentSelectionIndex = getState().flows.viewIndex[getState().flows.selected[0]]
let minIndex = 0
let maxIndex = getState().flows.view.length - 1
let newIndex
if (currentSelectionIndex === undefined) {
newIndex = (shift < 0) ? minIndex : maxIndex
} else {
newIndex = currentSelectionIndex + shift
newIndex = window.Math.max(newIndex, minIndex)
newIndex = window.Math.min(newIndex, maxIndex)
}
let flow = getState().flows.view[newIndex]
dispatch(select(flow ? flow.id : undefined))
export function selectRelative(flows, shift) {
let currentSelectionIndex = flows.viewIndex[flows.selected[0]]
let minIndex = 0
let maxIndex = flows.view.length - 1
let newIndex
if (currentSelectionIndex === undefined) {
newIndex = (shift < 0) ? minIndex : maxIndex
} else {
newIndex = currentSelectionIndex + shift
newIndex = window.Math.max(newIndex, minIndex)
newIndex = window.Math.min(newIndex, maxIndex)
}
let flow = flows.view[newIndex]
return select(flow ? flow.id : undefined)
}
@ -212,7 +209,7 @@ export function uploadContent(flow, file, type) {
const body = new FormData()
file = new window.Blob([file], { type: 'plain/text' })
body.append('file', file)
return dispatch => fetchApi(`/flows/${flow.id}/${type}/content`, { method: 'post', body })
return dispatch => fetchApi(`/flows/${flow.id}/${type}/content`, { method: 'POST', body })
}
@ -228,7 +225,7 @@ export function download() {
export function upload(file) {
const body = new FormData()
body.append('file', file)
return dispatch => fetchApi('/flows/dump', { method: 'post', body })
return dispatch => fetchApi('/flows/dump', { method: 'POST', body })
}

View File

@ -9,39 +9,40 @@ export function onKeyDown(e) {
return () => {
}
}
var key = e.keyCode
var shiftKey = e.shiftKey
let key = e.keyCode,
shiftKey = e.shiftKey
e.preventDefault()
return (dispatch, getState) => {
const flow = getState().flows.byId[getState().flows.selected[0]]
const flows = getState().flows,
flow = flows.byId[getState().flows.selected[0]]
switch (key) {
case Key.K:
case Key.UP:
dispatch(flowsActions.selectRelative(-1))
dispatch(flowsActions.selectRelative(flows, -1))
break
case Key.J:
case Key.DOWN:
dispatch(flowsActions.selectRelative(+1))
dispatch(flowsActions.selectRelative(flows, +1))
break
case Key.SPACE:
case Key.PAGE_DOWN:
dispatch(flowsActions.selectRelative(+10))
dispatch(flowsActions.selectRelative(flows, +10))
break
case Key.PAGE_UP:
dispatch(flowsActions.selectRelative(-10))
dispatch(flowsActions.selectRelative(flows, -10))
break
case Key.END:
dispatch(flowsActions.selectRelative(+1e10))
dispatch(flowsActions.selectRelative(flows, +1e10))
break
case Key.HOME:
dispatch(flowsActions.selectRelative(-1e10))
dispatch(flowsActions.selectRelative(flows, -1e10))
break
case Key.ESC: