Add tests more tests to TeamConnector.test.tsx

This commit is contained in:
Jerko Steiner 2019-03-26 14:29:44 +08:00
parent 9dd6994498
commit 289ea00de8
3 changed files with 96 additions and 25 deletions

View File

@ -1,16 +1,36 @@
import * as Feature from './' import * as Feature from './'
// export ReactDOM from 'react-dom' // export ReactDOM from 'react-dom'
// import T from 'react-dom/test-utils' import T from 'react-dom/test-utils'
import {HTTPClientMock, TestUtils/*, getError*/} from '../test-utils' import {HTTPClientMock, TestUtils, getError} from '../test-utils'
import {IAPIDef, ITeam, IUserInTeam} from '@rondo/common' import {IAPIDef, ITeam, IUserInTeam} from '@rondo/common'
import React from 'react' import React from 'react'
import {MemoryRouter} from 'react-router-dom'
const test = new TestUtils() const test = new TestUtils()
describe('TeamConnector', () => { describe('TeamConnector', () => {
const http = new HTTPClientMock<IAPIDef>() let teamActions!: Feature.TeamActions
const teamActions = new Feature.TeamActions(http) let http: HTTPClientMock<IAPIDef>
beforeEach(() => {
http = new HTTPClientMock<IAPIDef>()
http.mockAdd({
method: 'get',
url: '/my/teams',
}, teams)
http.mockAdd({
method: 'get',
url: '/teams/:teamId/users',
params: {
teamId: 123,
},
}, users)
teamActions = new Feature.TeamActions(http)
})
const historyEntries = ['/teams']
const createTestProvider = () => test.withProvider({ const createTestProvider = () => test.withProvider({
reducers: {Team: Feature.Team}, reducers: {Team: Feature.Team},
@ -20,7 +40,11 @@ describe('TeamConnector', () => {
new Feature new Feature
.TeamConnector(teamActions) .TeamConnector(teamActions)
.connect(select)) .connect(select))
.withJSX((Component, props) => <Component {...props} />) .withJSX((Component, props) =>
<MemoryRouter initialEntries={historyEntries}>
<Component {...props} />
</MemoryRouter>,
)
const teams: ITeam[] = [{id: 100, name: 'my-team', userId: 1}] const teams: ITeam[] = [{id: 100, name: 'my-team', userId: 1}]
@ -33,20 +57,52 @@ describe('TeamConnector', () => {
}] }]
it('it fetches user teams on render', async () => { it('it fetches user teams on render', async () => {
http.mockAdd({ const {node} = createTestProvider().render({})
method: 'get',
url: '/my/teams',
}, teams)
http.mockAdd({
method: 'get',
url: '/teams/:teamId/users',
params: {
teamId: 123,
},
}, users)
const {node} = createTestProvider().render({editTeamId123: 123})
await http.wait() await http.wait()
expect(node.innerHTML).toContain('my-team') expect(node.innerHTML).toContain('my-team')
}) })
describe('add team', () => {
it('sends a POST request to POST /teams', async () => {
const newTeam: Partial<ITeam> = {id: 101, name: 'new-team'}
http.mockAdd({
method: 'post',
url: '/teams',
data: {name: 'new-team'},
}, newTeam)
const {render, store} = createTestProvider()
const {node} = render({})
const addTeamForm = node.querySelector('.team-add') as HTMLFormElement
const nameInput = addTeamForm
.querySelector('input') as HTMLInputElement
T.Simulate.change(nameInput, {target: {value: newTeam.name}} as any)
T.Simulate.submit(addTeamForm)
await http.wait()
expect(nameInput.value).toEqual('')
const {Team} = store.getState()
expect(Team.teamIds).toEqual([100, 101])
expect(Team.teamsById[101]).toEqual(newTeam)
})
it('displays an error', async () => {
const error = {error: 'An error'}
http.mockAdd({
method: 'post',
url: '/teams',
data: {name: 'test'},
}, error, 400)
const {render} = createTestProvider()
const {node} = render({})
const addTeamForm = node.querySelector('.team-add') as HTMLFormElement
const nameInput = addTeamForm
.querySelector('input') as HTMLInputElement
T.Simulate.change(nameInput, {target: {value: 'test'}} as any)
T.Simulate.submit(addTeamForm)
const error2 = await getError(http.wait())
expect(error2.message).toMatch(/HTTP Status: 400/)
expect(nameInput.value).toEqual('test')
expect(addTeamForm.innerHTML).toMatch(/HTTP Status: 400/)
})
})
}) })

View File

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import {Button, Control, Heading, Input} from 'bloomer' import {Button, Control, Heading, Help, Input} from 'bloomer'
import {ITeam} from '@rondo/common' import {ITeam} from '@rondo/common'
import {TeamActions} from './TeamActions' import {TeamActions} from './TeamActions'
import {FaPlusSquare, FaCheck, FaEdit} from 'react-icons/fa' import {FaPlusSquare, FaCheck, FaEdit} from 'react-icons/fa'
@ -14,6 +14,8 @@ export type ITeamEditorProps = {
} }
export interface ITeamEditorState { export interface ITeamEditorState {
// TODO use redux state for errors!
error: string
name: string name: string
} }
@ -22,6 +24,7 @@ extends React.PureComponent<ITeamEditorProps, ITeamEditorState> {
constructor(props: ITeamEditorProps) { constructor(props: ITeamEditorProps) {
super(props) super(props)
this.state = { this.state = {
error: '',
name: props.type === 'update' ? this.getName(props.team) : '', name: props.type === 'update' ? this.getName(props.team) : '',
} }
} }
@ -45,15 +48,22 @@ extends React.PureComponent<ITeamEditorProps, ITeamEditorState> {
handleSubmit = async (event: React.FormEvent) => { handleSubmit = async (event: React.FormEvent) => {
event.preventDefault() event.preventDefault()
const {name} = this.state const {name} = this.state
if (this.props.type === 'update') { try {
const {team} = this.props if (this.props.type === 'update') {
await this.props.onUpdateTeam({id: team.id, name}) const {team} = this.props
} else { await this.props.onUpdateTeam({id: team.id, name}).payload
await this.props.onAddTeam({name}) } else {
await this.props.onAddTeam({name}).payload
}
} catch (err) {
this.setState({error: err.message})
return
} }
this.setState({name: ''}) this.setState({error: '', name: ''})
} }
render() { render() {
const {error} = this.state
return ( return (
<form <form
autoComplete='off' autoComplete='off'
@ -72,6 +82,9 @@ extends React.PureComponent<ITeamEditorProps, ITeamEditorState> {
<span className='icon is-left'> <span className='icon is-left'>
{this.props.type === 'update' ? <FaEdit /> : <FaPlusSquare />} {this.props.type === 'update' ? <FaEdit /> : <FaPlusSquare />}
</span> </span>
{error && (
<Help isColor='danger'>{error}</Help>
)}
</Control> </Control>
<div className='text-right mt-1'> <div className='text-right mt-1'>
<Button <Button

View File

@ -128,7 +128,9 @@ export class HTTPClientMock<T extends IRoutes> extends HTTPClient<T> {
const result: IReqRes = await new Promise((resolve, reject) => { const result: IReqRes = await new Promise((resolve, reject) => {
this.waitPromise = {resolve, reject} this.waitPromise = {resolve, reject}
}) })
await new Promise(resolve => setImmediate(resolve)) // TODO think of a better way to do this.
// We wait for all http request promise handlers to execute...
await new Promise(resolve => setTimeout(resolve))
return result return result
} }