Jest
Jest is a testing lib created by Facebook. Its a wonderful tesitng lib for any situation. Let's give it a try! Create a new package with npm and install jest
npm install jest --save-dev
Notice we used the --save-dev flag this time. We want to save jest in our package.json but as a dev dependency. Because our code does not depend on jest at runtime to execute. When your app gets deployed or installed by another dev, those machines will only NEED to install dependencies and not dev dependency. Saving space and time.
Next add a test script in the package.json:
"scripts": {
"test": "jest"
}
Now we need some code to test.
// myLib.mjs
const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
const users = [{ email: '[email protected]', id: 1, name: 'Goku', verified: false }]
const getNewUser = async id => {
await delay(100)
const user = users.find(u => u.id === id)
if (!user) throw new Error('User does not exist')
return user
}
const mapObjectToArray = (o, cb) => {
const results = []
for (const [k, v] of Object.entries(o)) {
results.push(cb(k, v, o))
}
return results
}
module.exports = { getNewUser, mapObjectToArray }
At this time, the latest version of jest lacks support for ES modules without some setup, we're using commonjs modules. The next version of Jest will support these though. We have some async code and a function with a callback. These would've been tedious to test with just assert alone. Jest makes this easy.
// lib.spec.js
const { mapObjectToArray, getNewUser } = require('./myLib')
describe('getNewUser', () => {
test('user does exist', async () => {
const user = await getNewUser(1)
expect(user).toBeTruthy()
expect(user.verified).toBe(false)
})
test('user does not exist', async () => {
expect.assertions(1)
try {
await getNewUser(3)
} catch (e) {
expect(e.message).toBe('User does not exist')
}
})
})
describe('mapObjectToArray', () => {
test('callback gets called for each value', () => {
const mock = jest.fn()
mapObjectToArray({ a: 1, b: 1, c: 1 }, mock)
expect(mock.mock.calls.length).toBe(3)
})
test('callback gets the right args', () => {
const mockCb = jest.fn()
const o = { a: 1, b: 1, c: 1 }
mapObjectToArray(o, mockCb)
const firstCall = mockCb.mock.calls[0]
expect(firstCall[0]).toBe('a')
expect(firstCall[1]).toBe(1)
expect(firstCall[2]).toBe(o)
})
})
Notice how we didn't have to require or import a jest module but yet we have access to all these new globals like describe and test. That's because this test file will be executed with the jest cli which will supply these values during runtime. If you executed this file with the node runtime, you'll get errors.
Most Node.js testing frameworks follow this format of describing a tes suite, usually a function. From there, we make different calls to test for each assertion we want to claim on that code. Sometimes, you might make many assertions in one test call. There is no one right way.
Now, lets run the test. Jest will look for any file with the .(spec|test).js extension and run it. You can change that if you'd like of course.
npm test
What we get back here is much more pleasant compared to our plain test we made with assert. This is the default reporter, but you can add more reporters like html or json. Or make your own.
Backlinks