Skip to content

Commit

Permalink
reduxjs#1944 converting test suite from Mocha to Jest (reduxjs#1951)
Browse files Browse the repository at this point in the history
* Fix Jest spy code in documentation

While looking into reduxjs#1944 I noticed that the examples in the documentation
still uses expect's createSpy() instead of Jest's fn() approach

* reduxjs#1944 Converting tests from Mocha to Jest

Added Jest dependencies
Removed expect from files
Updated mocks to use `jest.fn()`
Current `expect.spyOn` replacement can be improved on
TODO: Fix linter not to complain about using `console`

* Disable eslint no-console for console related tests

* Made changes suggested by @Florian-R that enable no-args jest.fn() calls

https://github.com/reactjs/redux/pull/1951/files/927bf45f1c7666e42ae8c4c390cc726a75cab903#r78733124

* Removed moch, expect and isparta

Updated test:cov command to use jest's --coverage option

* Update typescript.spec.js
  • Loading branch information
HeinrichFilter authored and seantcoyote committed Jan 14, 2018
1 parent 9cc3dfd commit 62854ad
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 142 deletions.
6 changes: 3 additions & 3 deletions docs/recipes/WritingTests.md
Expand Up @@ -304,7 +304,7 @@ import Header from '../../components/Header'

function setup() {
const props = {
addTodo: expect.createSpy()
addTodo: jest.fn()
}

const enzymeWrapper = shallow(<Header {...props} />)
Expand Down Expand Up @@ -333,9 +333,9 @@ describe('components', () => {
const { enzymeWrapper, props } = setup()
const input = enzymeWrapper.find('TodoTextInput')
input.props().onSave('')
expect(props.addTodo.calls.length).toBe(0)
expect(props.addTodo.mock.calls.length).toBe(0)
input.props().onSave('Use Redux')
expect(props.addTodo.calls.length).toBe(1)
expect(props.addTodo.mock.calls.length).toBe(1)
})
})
})
Expand Down
12 changes: 7 additions & 5 deletions package.json
Expand Up @@ -18,9 +18,9 @@
"lint": "npm run lint:src && npm run lint:examples",
"lint:src": "eslint src test build",
"lint:examples": "eslint examples",
"test": "cross-env BABEL_ENV=commonjs mocha --compilers js:babel-register --recursive",
"test": "cross-env BABEL_ENV=commonjs jest",
"test:watch": "npm test -- --watch",
"test:cov": "cross-env BABEL_ENV=commonjs babel-node $(npm bin)/isparta cover $(npm bin)/_mocha -- --recursive",
"test:cov": "npm test -- --coverage",
"test:examples": "cross-env BABEL_ENV=commonjs babel-node examples/testAll.js",
"check:src": "npm run lint:src && npm run test",
"check:examples": "npm run build:examples && npm run lint:examples && npm run test:examples",
Expand Down Expand Up @@ -73,6 +73,7 @@
"babel-cli": "^6.3.15",
"babel-core": "^6.3.15",
"babel-eslint": "^4.1.6",
"babel-jest": "^15.0.0",
"babel-loader": "^6.2.0",
"babel-plugin-check-es2015-constants": "^6.3.13",
"babel-plugin-transform-es2015-arrow-functions": "^6.3.13",
Expand Down Expand Up @@ -101,11 +102,9 @@
"eslint": "^1.10.3",
"eslint-config-rackt": "^1.1.1",
"eslint-plugin-react": "^3.16.1",
"expect": "^1.8.0",
"gitbook-cli": "^2.3.0",
"glob": "^6.0.4",
"isparta": "^4.0.0",
"mocha": "^2.2.5",
"jest": "^15.1.1",
"rimraf": "^2.3.4",
"rxjs": "^5.0.0-beta.6",
"typescript": "^1.8.0",
Expand All @@ -125,5 +124,8 @@
"transform": [
"loose-envify"
]
},
"jest": {
"testRegex": "(/test/.*\\.spec.js)$"
}
}
2 changes: 1 addition & 1 deletion test/.eslintrc
@@ -1,5 +1,5 @@
{
"env": {
"mocha": true
"jest": true
}
}
11 changes: 5 additions & 6 deletions test/applyMiddleware.spec.js
@@ -1,4 +1,3 @@
import expect from 'expect'
import { createStore, applyMiddleware } from '../src/index'
import * as reducers from './helpers/reducers'
import { addTodo, addTodoAsync, addTodoIfEmpty } from './helpers/actionCreators'
Expand All @@ -13,15 +12,15 @@ describe('applyMiddleware', () => {
}
}

const spy = expect.createSpy(() => {})
const spy = jest.fn()
const store = applyMiddleware(test(spy), thunk)(createStore)(reducers.todos)

store.dispatch(addTodo('Use Redux'))
store.dispatch(addTodo('Flux FTW!'))

expect(spy.calls.length).toEqual(1)
expect(spy.mock.calls.length).toEqual(1)

expect(Object.keys(spy.calls[0].arguments[0])).toEqual([
expect(Object.keys(spy.mock.calls[0][0])).toEqual([
'getState',
'dispatch'
])
Expand All @@ -37,11 +36,11 @@ describe('applyMiddleware', () => {
}
}

const spy = expect.createSpy(() => {})
const spy = jest.fn()
const store = applyMiddleware(test(spy), thunk)(createStore)(reducers.todos)

return store.dispatch(addTodoAsync('Use Redux')).then(() => {
expect(spy.calls.length).toEqual(2)
expect(spy.mock.calls.length).toEqual(2)
})
})

Expand Down
1 change: 0 additions & 1 deletion test/bindActionCreators.spec.js
@@ -1,4 +1,3 @@
import expect from 'expect'
import { bindActionCreators, createStore } from '../src'
import { todos } from './helpers/reducers'
import * as actionCreators from './helpers/actionCreators'
Expand Down
68 changes: 42 additions & 26 deletions test/combineReducers.spec.js
@@ -1,4 +1,4 @@
import expect from 'expect'
/* eslint-disable no-console */
import { combineReducers } from '../src'
import createStore, { ActionTypes } from '../src/createStore'

Expand Down Expand Up @@ -32,21 +32,24 @@ describe('Utils', () => {
})

it('warns if a reducer prop is undefined', () => {
const spy = expect.spyOn(console, 'error')
const preSpy = console.error
const spy = jest.fn()
console.error = spy

let isNotDefined
combineReducers({ isNotDefined })
expect(spy.calls[0].arguments[0]).toMatch(
expect(spy.mock.calls[0][0]).toMatch(
/No reducer provided for key "isNotDefined"/
)

spy.reset()
spy.mockClear()
combineReducers({ thing: undefined })
expect(spy.calls[0].arguments[0]).toMatch(
expect(spy.mock.calls[0][0]).toMatch(
/No reducer provided for key "thing"/
)

spy.restore()
spy.mockClear()
console.error = preSpy
})

it('throws an error if a reducer returns undefined handling an action', () => {
Expand Down Expand Up @@ -166,7 +169,7 @@ describe('Utils', () => {
})

const initialState = reducer(undefined, '@@INIT')
expect(reducer(initialState, { type: 'increment' })).toNotBe(initialState)
expect(reducer(initialState, { type: 'increment' })).not.toBe(initialState)
})

it('throws an error on first call if a reducer attempts to handle a private action', () => {
Expand All @@ -191,17 +194,24 @@ describe('Utils', () => {
})

it('warns if no reducers are passed to combineReducers', () => {
const spy = expect.spyOn(console, 'error')
const preSpy = console.error
const spy = jest.fn()
console.error = spy

const reducer = combineReducers({ })
reducer({ })
expect(spy.calls[0].arguments[0]).toMatch(
expect(spy.mock.calls[0][0]).toMatch(
/Store does not have a valid reducer/
)
spy.restore()
spy.mockClear()
console.error = preSpy
})

it('warns if input state does not match reducer shape', () => {
const spy = expect.spyOn(console, 'error')
const preSpy = console.error
const spy = jest.fn()
console.error = spy

const reducer = combineReducers({
foo(state = { bar: 1 }) {
return state
Expand All @@ -212,69 +222,75 @@ describe('Utils', () => {
})

reducer()
expect(spy.calls.length).toBe(0)
expect(spy.mock.calls.length).toBe(0)

reducer({ foo: { bar: 2 } })
expect(spy.calls.length).toBe(0)
expect(spy.mock.calls.length).toBe(0)

reducer({
foo: { bar: 2 },
baz: { qux: 4 }
})
expect(spy.calls.length).toBe(0)
expect(spy.mock.calls.length).toBe(0)

createStore(reducer, { bar: 2 })
expect(spy.calls[0].arguments[0]).toMatch(
expect(spy.mock.calls[0][0]).toMatch(
/Unexpected key "bar".*createStore.*instead: "foo", "baz"/
)

createStore(reducer, { bar: 2, qux: 4, thud: 5 })
expect(spy.calls[1].arguments[0]).toMatch(
expect(spy.mock.calls[1][0]).toMatch(
/Unexpected keys "qux", "thud".*createStore.*instead: "foo", "baz"/
)

createStore(reducer, 1)
expect(spy.calls[2].arguments[0]).toMatch(
expect(spy.mock.calls[2][0]).toMatch(
/createStore has unexpected type of "Number".*keys: "foo", "baz"/
)

reducer({ corge: 2 })
expect(spy.calls[3].arguments[0]).toMatch(
expect(spy.mock.calls[3][0]).toMatch(
/Unexpected key "corge".*reducer.*instead: "foo", "baz"/
)

reducer({ fred: 2, grault: 4 })
expect(spy.calls[4].arguments[0]).toMatch(
expect(spy.mock.calls[4][0]).toMatch(
/Unexpected keys "fred", "grault".*reducer.*instead: "foo", "baz"/
)

reducer(1)
expect(spy.calls[5].arguments[0]).toMatch(
expect(spy.mock.calls[5][0]).toMatch(
/reducer has unexpected type of "Number".*keys: "foo", "baz"/
)

spy.restore()
spy.mockClear()
console.error = preSpy
})

it('only warns for unexpected keys once', () => {
const spy = expect.spyOn(console, 'error')
const preSpy = console.error
const spy = jest.fn()
console.error = spy

const foo = (state = { foo: 1 }) => state
const bar = (state = { bar: 2 }) => state

expect(spy.calls.length).toBe(0)
expect(spy.mock.calls.length).toBe(0)
const reducer = combineReducers({ foo, bar })
const state = { foo: 1, bar: 2, qux: 3 }
reducer(state, {})
reducer(state, {})
reducer(state, {})
reducer(state, {})
expect(spy.calls.length).toBe(1)
expect(spy.mock.calls.length).toBe(1)
reducer({ ...state, baz: 5 }, {})
reducer({ ...state, baz: 5 }, {})
reducer({ ...state, baz: 5 }, {})
reducer({ ...state, baz: 5 }, {})
expect(spy.calls.length).toBe(2)
spy.restore()
expect(spy.mock.calls.length).toBe(2)

spy.mockClear()
console.error = preSpy
})
})
})
1 change: 0 additions & 1 deletion test/compose.spec.js
@@ -1,4 +1,3 @@
import expect from 'expect'
import { compose } from '../src'

describe('Utils', () => {
Expand Down

0 comments on commit 62854ad

Please sign in to comment.