Skip to content

Commit ac21eb6

Browse files
committed
Update unit tests
1 parent 6fdb154 commit ac21eb6

File tree

2 files changed

+43
-31
lines changed

2 files changed

+43
-31
lines changed

app/ContactFormComponent.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@ import redux from 'redux'
22
import React, { Component, PropTypes } from 'react'
33
import { Field } from 'redux-form'
44

5-
const renderField = ({ input, label, type, meta: { touched, error } }) => (
6-
<div>
7-
<label>{label}</label>
8-
{' '}
9-
<input {...input}/>
10-
{' '}
11-
{touched && error && <span className='help-block'>{error}</span>}
12-
</div>
13-
)
5+
export const renderTextInput = field => {
6+
const { input, label, type, meta: { touched, error } } = field
7+
return (
8+
<div>
9+
<label>{label}</label>
10+
{' '}
11+
<input {...input} type={type}/>
12+
{' '}
13+
{touched && error && <span className='help-block'>{error}</span>}
14+
</div>
15+
)
16+
}
1417

1518
class ContactForm extends Component {
1619
mySubmit(values) {
@@ -24,7 +27,7 @@ class ContactForm extends Component {
2427
return (
2528
<form onSubmit={this.props.handleSubmit(this.mySubmit.bind(this))}>
2629
<h1>Contact Form</h1>
27-
<Field name="firstName" component={renderField} type="text" label="First name"/>
30+
<Field name="firstName" component={renderTextInput} type="text" label="First name"/>
2831
<p></p>
2932
<button type="submit" disabled={this.props.submitting}>
3033
{this.props.submitting ? 'Submitting (takes 1 s)' : 'Submit'}

tests/unit/index.js

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import ContactFormComponent from '../../app/ContactFormComponent'
1+
import ContactFormComponent, { renderTextInput } from '../../app/ContactFormComponent'
22
import React from 'react'
33

44
// See README for discussion of chai, enzyme, and sinon
@@ -13,17 +13,16 @@ chai.use(chaiEnzyme())
1313
// really has nothing to do with Redux-Form at this point. We can pass in our
1414
// own props (e.g. `submitting`) and make sure our form renders as we expect.
1515

16-
describe("ContactFormComponent", () => {
16+
describe.only("ContactFormComponent", () => {
1717
let subject = null
18-
let submitting, touched, error, resetForm, onSave, onSaveResponse
18+
let submitting, touched, error, reset, onSave, onSaveResponse
1919
beforeEach(() => {
2020
submitting = false
2121
touched = false
2222
error = null
23-
resetForm = sinon.spy()
23+
reset = sinon.spy()
2424
onSaveResponse = Promise.resolve()
25-
onSave = sinon.stub()
26-
onSave.returns(onSaveResponse)
25+
onSave = sinon.stub().returns(onSaveResponse)
2726
})
2827
const buildSubject = () => {
2928
const props = {
@@ -40,42 +39,52 @@ describe("ContactFormComponent", () => {
4039
}
4140
},
4241
handleSubmit: fn => fn,
43-
resetForm
42+
reset
4443
}
4544
return shallow(<ContactFormComponent {...props}/>)
4645
}
4746

4847
// Here we show we can test asychronous actions triggered by our form.
49-
it("calls resetForm after onSave", (done) => {
48+
it("calls reset after onSave", () => {
5049
subject = buildSubject()
5150
subject.find('form').simulate('submit')
5251
expect(onSave.callCount).to.equal(1)
53-
onSaveResponse.then(() => {
54-
expect(resetForm.callCount).to.equal(1)
55-
done()
52+
return onSaveResponse.then(() => {
53+
expect(reset.callCount).to.equal(1)
5654
})
5755
})
5856

5957
// This is a very simle test, making sure that if we pass in a certain
6058
// prop value, our form renders appropriately.
6159
context("when submitting", () => {
62-
it("shows a spinner while submitting", () => {
60+
it("shows a wait message while submitting", () => {
6361
submitting = true
6462
subject = buildSubject()
65-
const icon = subject.find('button[type="submit"]').find('i')
66-
expect(icon).to.have.className('glyphicon-refresh glyphicon-spin')
63+
const icon = subject.find('button[type="submit"]')
64+
expect(icon).to.have.text('Submitting (takes 1 s)')
6765
})
6866
})
6967

70-
// Again, we show that what we render is based on the props we send it. If
71-
// we set the props to include an error state, our form should render that
72-
// fact.
68+
})
69+
70+
// renderTextInput is a stateless functional component, aka just a method that
71+
// returns a React element, so it's trivial to test. We export it from the
72+
// ContactFormComponent file. It could be named whatever we want, but it
73+
// should be named based on what type of input component it creates, since you
74+
// would create a similar function for each type of component you need to
75+
// render. If you look in renderTextInput, it outputs an <input/>, but you
76+
// would need a different method if you wanted to output a <select/>,
77+
// <textarea>, etc.
78+
describe.only('renderTextInput', () => {
79+
let subject
7380
context("when in an error state", () => {
7481
it("renders an error message for the input", () => {
75-
touched = true
76-
error = "Required"
77-
subject = buildSubject()
78-
const firstNameHelpBlock = subject.find('.help-block')
82+
const input = { name: 'firstName', value: '' }
83+
const label = 'First name'
84+
const meta = { touched: true, error: 'Required' }
85+
const element = renderTextInput({ input, label, meta })
86+
subject = shallow(element)
87+
const firstNameHelpBlock = subject.find('.help-block').first()
7988
expect(firstNameHelpBlock).to.exist
8089
expect(firstNameHelpBlock.text()).to.equal('Required')
8190
})

0 commit comments

Comments
 (0)