- Mock the API
- Mock the Store
- Test Success and Failure
-
Create the directory
src\projects\__mocks__
.__mocks__
begins and ends with two underscores and is case-sensitive -
Create the file
src\projects\__mocks__\projectAPI.js
to mock theprojectAPI
. -
Mock the
get
method.import { MOCK_PROJECTS } from '../MockProjects'; const projectAPI = { get(page = 1, limit = 20) { return Promise.resolve(MOCK_PROJECTS); }, }; export { projectAPI };
-
Open a
command prompt
(Windows) orterminal
(Mac). -
Change the current directory to
working\keeptrack
. -
Run one of the following sets of commands:
npm install redux-mock-store @types/redux-mock-store --save-dev
yarn add redux-mock-store @types/redux-mock-store --save-dev
-
Create the directory
src\projects\state\__tests__
.__tests__
begins and ends with two underscores and is case-sensitive -
Create the file
src\projects\state\__tests__\projectActions-test.js
-
Add the test setup code including mocking the store away.
import configureMockStore from 'redux-mock-store'; import ReduxThunk from 'redux-thunk'; import { initialAppState } from '../../../state'; import { loadProjects } from '../projectActions'; import { LOAD_PROJECTS_REQUEST, LOAD_PROJECTS_SUCCESS, LOAD_PROJECTS_FAILURE, } from '../projectTypes'; import { projectAPI } from '../../projectAPI'; import { MOCK_PROJECTS } from '../../MockProjects'; jest.mock('../../projectAPI'); const middlewares = [ReduxThunk]; const mockStoreCreator = configureMockStore(middlewares); describe('Project Actions', () => { let store; beforeEach(() => { store = mockStoreCreator(initialAppState); }); });
Note that the
jest.mock
replaces the actual implementation of theprojectAPI
with the mock we created in the last step. This is done by convention in Jest which replaces the implementation with the exported function or object in the__mocks__
directory.
-
At this point, you will receive the following error:
FAIL src/projects/state/__tests__/projectActions-test.js ● Test suite failed to run Your test suite must contain at least one test.
-
Test that an error is returned when loading projects fails.
import configureMockStore from 'redux-mock-store'; import ReduxThunk from 'redux-thunk'; import { initialAppState } from '../../../state'; import { loadProjects } from '../projectActions'; import { LOAD_PROJECTS_REQUEST, LOAD_PROJECTS_SUCCESS, LOAD_PROJECTS_FAILURE } from '../projectTypes'; import { projectAPI } from '../../projectAPI'; import { MOCK_PROJECTS } from '../../MockProjects'; jest.mock('../../projectAPI'); const middlewares = [ReduxThunk]; const mockStoreCreator = configureMockStore(middlewares); describe('Project Actions', () => { let store: any; beforeEach(() => { store = mockStoreCreator(initialAppState); }); + test('should return error', () => { + projectAPI.get = jest + .fn( + // leave this commented initially + // projectAPI.get + ) + .mockImplementationOnce(() => { + return Promise.reject('failed'); + }); + + const expectedActions = [ + { type: LOAD_PROJECTS_REQUEST }, + { + type: LOAD_PROJECTS_FAILURE, + payload: 'failed' + } + ]; + + return store.dispatch(loadProjects(1)).then(() => { + const actions = store.getActions(); + expect(actions).toEqual(expectedActions); + }); + }); });
-
The new test should pass.
PASS src/projects/state/__tests__/projectActions-test.js
-
Attempt to test that the projects load successfully by adding the code.
import configureMockStore from 'redux-mock-store'; import ReduxThunk from 'redux-thunk'; import { initialAppState } from '../../../state'; import { loadProjects } from '../projectActions'; import { LOAD_PROJECTS_REQUEST, LOAD_PROJECTS_SUCCESS, LOAD_PROJECTS_FAILURE } from '../projectTypes'; import { projectAPI } from '../../projectAPI'; import { MOCK_PROJECTS } from '../../MockProjects'; jest.mock('../../projectAPI'); const middlewares = [ReduxThunk]; const mockStoreCreator = configureMockStore(middlewares); describe('Project Actions', () => { let store; beforeEach(() => { store = mockStoreCreator(initialAppState); }); test('should return error', () => { projectAPI.get = jest .fn( // leave this commented initially // projectAPI.get ) .mockImplementationOnce(() => { return Promise.reject('failed'); }); const expectedActions = [ { type: LOAD_PROJECTS_REQUEST }, { type: LOAD_PROJECTS_FAILURE, payload: 'failed' } ]; return store.dispatch(loadProjects(1)).then(() => { const actions = store.getActions(); expect(actions).toEqual(expectedActions); }); }); + test('should load projects successfully', () => { + const expectedActions = [ + { type: LOAD_PROJECTS_REQUEST }, + { + type: LOAD_PROJECTS_SUCCESS, + payload: { projects: MOCK_PROJECTS, page: 1 } + } + ]; + + return store.dispatch(loadProjects(1)).then(() => { + const actions = store.getActions(); + expect(actions).toEqual(expectedActions); + }); + }); });
-
The test fails with the error below because no default mock implementation is set for the
get
method to revert back to after callingmockImplementationOnce
executes once for the error test case.TypeError: Cannot read property 'then' of undefined
-
Uncomment the line below to set the default mock implementation back to the method defined in
src\projects\__mocks__\projectAPI.js
.Be sure that projectAPI.get is inside the .fn() (
.fn(projectAPI.get)
).... describe('Project Actions', () => { let store; beforeEach(() => { store = mockStoreCreator(initialAppState); }); test('should return error', () => { projectAPI.get = jest .fn( // leave this commented initially - // projectAPI.get + projectAPI.get ) .mockImplementationOnce(() => { return Promise.reject('failed'); }); const expectedActions = [ { type: LOAD_PROJECTS_REQUEST }, { type: LOAD_PROJECTS_FAILURE, payload: 'failed' } ]; return store.dispatch(loadProjects(1)).then(() => { const actions = store.getActions(); expect(actions).toEqual(expectedActions); }); }); test('should load projects successfully', () => { const expectedActions = [ { type: LOAD_PROJECTS_REQUEST }, { type: LOAD_PROJECTS_SUCCESS, payload: { projects: MOCK_PROJECTS, page: 1 } } ]; return store.dispatch(loadProjects(1)).then(() => { const actions = store.getActions(); expect(actions).toEqual(expectedActions); }); }); });
-
All tests including the
'should load projects successfully'
should now pass.PASS src/projects/state/__tests__/projectActions-test.js