In my pet project i have few files to test.
My employees.js
controller is
let employees = [
{ id: '1', name: "Edmon D'antes", status: 'worker' },
{ id: '2', name: 'Alluri Sitarama Raju', status: 'hero' },
{ id: '3', name: 'Roman Shukhevych', status: 'hero' },
{ id: '4', name: 'Ptn Pnh', status: 'huylo' },
]
export const getAll = (req, res) => {
res.status(200).json(employees)
}
export const create = (req, res) => {
const newEmployee = {
id: Date.now().toString(),
...req.body,
}
employees.push(newEmployee)
res.status(201).json(newEmployee)
}
export const remove = (req, res) => {
let message = 'Employee has been dismissed.'
employees = employees.filter((e) => {
if (e.id === req.params.id && e.status === 'hero') {
message = 'You must respect heroes!'
return true
}
return e.id !== req.params.id
})
res.json({ message })
}
My employees.test.js
test is
import * as employeesModule from './employees.js'
let mockEmployees = [
{ id: '1', name: "Mocked Edmon D'antes", status: 'worker' },
{ id: '2', name: 'Mocked Alluri Sitarama Raju', status: 'hero' },
{ id: '3', name: 'Mocked Roman Shukhevych', status: 'hero' },
{ id: '4', name: 'Mocked Ptn Pnh', status: 'huylo' },
]
beforeEach(() => {
jest.spyOn(employeesModule, 'getAll').mockImplementation((req, res) => {
return res.status(200).json(mockEmployees)
})
jest.spyOn(employeesModule, 'create').mockImplementation((req, res) => {
const newEmployee = {
id: '5',
...req.body,
}
mockEmployees.push(newEmployee)
return res.status(201).json(newEmployee)
})
jest.spyOn(employeesModule, 'remove').mockImplementation((req, res) => {
let message = 'Employee has been dismissed.'
mockEmployees = mockEmployees.filter((e) => {
if (e.id === req.params.id && e.status === 'hero') {
message = 'You must respect heroes!'
return true
}
return e.id !== req.params.id
})
return res.json({ message })
})
})
describe('employees controller', () => {
it('getAll method should return all employees', () => {
const req = {} // Provide an empty object for req
const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }
employeesModule.getAll(req, res)
expect(res.status).toHaveBeenCalledWith(200)
expect(res.json).toHaveBeenCalledWith(mockEmployees)
})
it('create method should create a new employee', () => {
const req = { body: { name: 'New Employee', status: 'working' } }
const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }
employeesModule.create(req, res)
const newEmployee = mockEmployees.find((e) => e.id === '5')
expect(res.status).toHaveBeenCalledWith(201)
expect(res.json).toHaveBeenCalledWith(newEmployee)
})
it('remove method should remove the employee if not a hero', () => {
const req = { params: { id: '4' } }
const res = { json: jest.fn() }
employeesModule.remove(req, res)
expect(res.json).toHaveBeenCalledWith({
message: 'Employee has been dismissed.',
})
})
it('remove method should not remove the employee if a hero', () => {
const req = { params: { id: '2' } }
const res = { json: jest.fn() }
employeesModule.remove(req, res)
expect(res.json).toHaveBeenCalledWith({
message: 'You must respect heroes!',
})
})
})
As you can see I've covered with tests every controller exported method. And test works, but the issue is that my test verifies its own implementation version, not version provided by controller. To test version provided by controller I need access to employees
collection spying or mocking the one. After that I'd have chance to check collection changes or calls. Is there ideas how to fix the test without changing the controller?
P.S.
I know how to make it working exporting employees
collection from the employees.js
, but you know that's improper change.