Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP][web] Add tests for components/ContentView (con't) #2376

Merged
merged 11 commits into from Jun 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions web/package.json
Expand Up @@ -26,6 +26,7 @@
"bootstrap": "^3.3.7",
"classnames": "^2.2.5",
"lodash": "^4.17.4",
"mock-xmlhttprequest": "^1.1.0",
"prop-types": "^15.5.0",
"react": "^15.4.2",
"react-codemirror": "^0.3.0",
Expand Down
74 changes: 74 additions & 0 deletions web/src/js/__tests__/components/ContentView/ContentLoaderSpec.js
@@ -0,0 +1,74 @@
import React from 'react'
import renderer from 'react-test-renderer'
import withContentLoader from '../../../components/ContentView/ContentLoader'
import { TFlow } from '../../ducks/tutils'
import TestUtils from 'react-dom/test-utils'
import mockXMLHttpRequest from 'mock-xmlhttprequest'

global.XMLHttpRequest = mockXMLHttpRequest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I understand this without a comment - which purpose does this serve here and in ContentViewSpec.js?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we use XMLHttpRequest here:

// We use XMLHttpRequest instead of fetch() because fetch() is not (yet) abortable.

Introducing mock-xmlhttprequest dependency can save us a lot of troubles.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, but we never tell the mock function what to return, so what would happen if we didn't do this here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't mock XMLHttpRequest, it fails like this:
default

class tComponent extends React.Component {
constructor(props, context){
super(props, context)
}
render() {
return (<p>foo</p>)
}
}

let tflow = new TFlow(),
ContentLoader = withContentLoader(tComponent)

describe('ContentLoader Component', () => {
it('should render correctly', () => {
let contentLoader = renderer.create(<ContentLoader flow={tflow} message={tflow.response}/>),
tree = contentLoader.toJSON()
expect(tree).toMatchSnapshot()
})

let contentLoader = TestUtils.renderIntoDocument(<ContentLoader flow={tflow} message={tflow.response}/>)

it('should handle updateContent', () => {
tflow.response.content = 'foo'
contentLoader.updateContent({flow: tflow, message: tflow.response})
expect(contentLoader.state.request).toEqual(undefined)
expect(contentLoader.state.content).toEqual('foo')
// when content length is 0 or null
tflow.response.contentLength = 0
tflow.response.content = undefined
contentLoader.updateContent({flow: tflow, message: tflow.response})
expect(contentLoader.state.request).toEqual(undefined)
expect(contentLoader.state.content).toEqual('')
})

it('should handle componentWillReceiveProps', () => {
contentLoader.updateContent = jest.fn()
contentLoader.componentWillReceiveProps({flow: tflow, message: tflow.request})
expect(contentLoader.updateContent).toBeCalled()
})

it('should handle requestComplete', () => {
expect(contentLoader.requestComplete(tflow.request, {})).toEqual(undefined)
// request == this.state.request
contentLoader.state.request = tflow.request
contentLoader.requestComplete(tflow.request, {})
expect(contentLoader.state.content).toEqual(tflow.request.responseText)
expect(contentLoader.state.request).toEqual(undefined)
})

it('should handle requestFailed', () => {
console.error = jest.fn()
expect(contentLoader.requestFailed(tflow.request, {})).toEqual(undefined)
//request == this.state.request
contentLoader.state.request = tflow.request
contentLoader.requestFailed(tflow.request, 'foo error')
expect(contentLoader.state.content).toEqual('Error getting content.')
expect(contentLoader.state.request).toEqual(undefined)
expect(console.error).toBeCalledWith('foo error')
})

it('should handle componentWillUnmount', () => {
contentLoader.state.request = { abort : jest.fn() }
contentLoader.componentWillUnmount()
expect(contentLoader.state.request.abort).toBeCalled()
})
})
85 changes: 85 additions & 0 deletions web/src/js/__tests__/components/ContentView/ContentViewSpec.js
@@ -0,0 +1,85 @@
import React from 'react'
import renderer from 'react-test-renderer'
import TestUtils from 'react-dom/test-utils'
import { Provider } from 'react-redux'
import { ViewServer, ViewImage, PureViewServer, Edit } from '../../../components/ContentView/ContentViews'
import { TFlow, TStore } from '../../ducks/tutils'
import mockXMLHttpRequest from 'mock-xmlhttprequest'

global.XMLHttpRequest = mockXMLHttpRequest
let tflow = new TFlow()

describe('ViewImage Component', () => {
let viewImage = renderer.create(<ViewImage flow={tflow} message={tflow.response}/>),
tree = viewImage.toJSON()

it('should render correctly', () => {
expect(tree).toMatchSnapshot()
})
})

describe('ViewServer Component', () => {
let store = TStore(),
setContentViewDescFn = jest.fn(),
setContentFn = jest.fn()

it('should render correctly and connect to state', () => {
let provider = renderer.create(
<Provider store={store}>
<ViewServer
setContentViewDescription={setContentViewDescFn}
setContent={setContentFn}
flow={tflow}
message={tflow.response}
/>
</Provider>),
tree = provider.toJSON()
expect(tree).toMatchSnapshot()

let viewServer = renderer.create(
<PureViewServer
showFullContent={true}
maxLines={10}
setContentViewDescription={setContentViewDescFn}
setContent={setContentViewDescFn}
flow={tflow}
message={tflow.response}
content={JSON.stringify({lines: [['k1', 'v1']]})}
/>
)
tree = viewServer.toJSON()
expect(tree).toMatchSnapshot()
})

it('should handle componentWillReceiveProps', () => {
// case of fail to parse content
let viewSever = TestUtils.renderIntoDocument(
<PureViewServer
showFullContent={true}
maxLines={10}
setContentViewDescription={setContentViewDescFn}
setContent={setContentViewDescFn}
flow={tflow}
message={tflow.response}
content={JSON.stringify({lines: [['k1', 'v1']]})}
/>
)
viewSever.componentWillReceiveProps({...viewSever.props, content: '{foo' })
let e = ''
try {JSON.parse('{foo') } catch(err){ e = err.message}
expect(viewSever.data).toEqual({ description: e, lines: [] })
})
})

describe('Edit Component', () => {
it('should render correctly', () => {
let edit = renderer.create(<Edit
content="foo"
onChange={jest.fn}
flow={tflow}
message={tflow.response}
/>),
tree = edit.toJSON()
expect(tree).toMatchSnapshot()
})
})
@@ -0,0 +1,15 @@
import React from 'react'
import renderer from 'react-test-renderer'
import DownloadContentButton from '../../../components/ContentView/DownloadContentButton'
import { TFlow } from '../../ducks/tutils'

let tflow = new TFlow()
describe('DownloadContentButton Component', () => {
it('should render correctly', () => {
let downloadContentButton = renderer.create(
<DownloadContentButton flow={tflow} message={tflow.response}/>
),
tree = downloadContentButton.toJSON()
expect(tree).toMatchSnapshot()
})
})
37 changes: 37 additions & 0 deletions web/src/js/__tests__/components/ContentView/MetaViewsSpec.js
@@ -0,0 +1,37 @@
import React from 'react'
import renderer from 'react-test-renderer'
import { ContentEmpty, ContentMissing, ContentTooLarge } from '../../../components/ContentView/MetaViews'
import { TFlow } from '../../ducks/tutils'

let tflow = new TFlow()

describe('ContentEmpty Components', () => {
it('should render correctly', () => {
let contentEmpty = renderer.create(<ContentEmpty flow={tflow} message={tflow.response}/>),
tree = contentEmpty.toJSON()
expect(tree).toMatchSnapshot()
})
})

describe('ContentMissing Components', () => {
it('should render correctly', () => {
let contentMissing = renderer.create(<ContentMissing flow={tflow} message={tflow.response}/>),
tree = contentMissing.toJSON()
expect(tree).toMatchSnapshot()
})
})

describe('ContentTooLarge Components', () => {
it('should render correctly', () => {
let clickFn = jest.fn(),
uploadContentFn = jest.fn(),
contentTooLarge = renderer.create(<ContentTooLarge
flow={tflow}
message={tflow.response}
onClick={clickFn}
uploadContent={uploadContentFn}
/>),
tree = contentTooLarge.toJSON()
expect(tree).toMatchSnapshot()
})
})
@@ -0,0 +1,39 @@
import React from 'react'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import ConnectedComponent, { ShowFullContentButton } from '../../../components/ContentView/ShowFullContentButton'
import { TStore } from '../../ducks/tutils'


describe('ShowFullContentButton Component', () => {
let setShowFullContentFn = jest.fn(),
showFullContentButton = renderer.create(
<ShowFullContentButton
setShowFullContent={setShowFullContentFn}
showFullContent={false}
visibleLines={10}
contentLines={20}
/>
),
tree = showFullContentButton.toJSON()

it('should render correctly', () => {
expect(tree).toMatchSnapshot()
})

it('should handle click', () => {
tree.children[0].props.onClick()
expect(setShowFullContentFn).toBeCalled()
})

it('should connect to state', () => {
let store = TStore(),
provider = renderer.create(
<Provider store={store}>
<ConnectedComponent/>
</Provider>
),
tree = provider.toJSON()
expect(tree).toMatchSnapshot()
})
})
@@ -0,0 +1,12 @@
import React from 'react'
import renderer from 'react-test-renderer'
import UploadContentButton from '../../../components/ContentView/UploadContentButton'

describe('UpdateContentButton Component', () => {
it('should render correctly', () => {
let uploadContentFn = jest.fn(),
uploadContentButton = renderer.create(<UploadContentButton uploadContent={uploadContentFn}/>),
tree = uploadContentButton.toJSON()
expect(tree).toMatchSnapshot()
})
})
38 changes: 38 additions & 0 deletions web/src/js/__tests__/components/ContentView/ViewSelectorSpec.js
@@ -0,0 +1,38 @@
import React from 'react'
import renderer from 'react-test-renderer'
import ConnectedComponent, { ViewSelector } from '../../../components/ContentView/ViewSelector'
import { Provider } from 'react-redux'
import { TStore } from '../../ducks/tutils'


describe('ViewSelector Component', () => {
let contentViews = ['Auto', 'Raw', 'Text'],
activeView = 'Auto',
setContentViewFn = jest.fn(),
viewSelector = renderer.create(
<ViewSelector contentViews={contentViews} activeView={activeView} setContentView={setContentViewFn}/>
),
tree = viewSelector.toJSON()

it('should render correctly', () => {
expect(tree).toMatchSnapshot()
})

it('should handle click', () => {
let mockEvent = { preventDefault: jest.fn() },
tab = tree.children[1].children[0].children[1]
tab.props.onClick(mockEvent)
expect(mockEvent.preventDefault).toBeCalled()
})

it('should connect to state', () => {
let store = TStore(),
provider = renderer.create(
<Provider store={store}>
<ConnectedComponent/>
</Provider>
),
tree = provider.toJSON()
expect(tree).toMatchSnapshot()
})
})
@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ContentLoader Component should render correctly 1`] = `
<div
className="text-center"
>
<i
className="fa fa-spinner fa-spin"
/>
</div>
`;
@@ -0,0 +1,52 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Edit Component should render correctly 1`] = `
<div
className="text-center"
>
<i
className="fa fa-spinner fa-spin"
/>
</div>
`;

exports[`ViewImage Component should render correctly 1`] = `
<div
className="flowview-image"
>
<img
alt="preview"
className="img-thumbnail"
src="/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content"
/>
</div>
`;

exports[`ViewServer Component should render correctly and connect to state 1`] = `
<div
className="text-center"
>
<i
className="fa fa-spinner fa-spin"
/>
</div>
`;

exports[`ViewServer Component should render correctly and connect to state 2`] = `
<div>
<pre>
<div>
<span
className="k"
>
1
</span>
<span
className="v"
>
1
</span>
</div>
</pre>
</div>
`;
@@ -0,0 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`DownloadContentButton Component should render correctly 1`] = `
<a
className="btn btn-default btn-xs"
href="/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content"
title="Download the content of the flow."
>
<i
className="fa fa-download"
/>
</a>
`;