Part 3: Unit Testing your code using Jest
Installing Jestโ
- Install Jest from npm
npm install --save-dev jest
- This step is already done for you as you install dependencies defined in
package.json
by runningnpm install
in the beginning of the lab.
- This step is already done for you as you install dependencies defined in
Configuringโ
Generally, you wouldn't need a lot of configurations to get started with Jest. But because there are already some unit tests that are already included, and those tests require a bit of configuration, we'll go over some of the configurations that you might need to do.
- Create the following configurations
module.exports = {
setupFilesAfterEnv: [
`regenerator-runtime/runtime`,
`@testing-library/jest-dom/extend-expect`,
],
clearMocks: true,
testEnvironment: `node`,
watchPathIgnorePatterns: [`node_modules`],
testPathIgnorePatterns: [`node_modules`],
};
About those Configurationsโ
- because of how I'm testing the DOM and how I'm using the
@testing-library/dom
and@testing-library/jest-dom
libraries, I need to addregenerator-runtime/runtime
and@testing-library/jest-dom/extend-expect
to thesetupFilesAfterEnv
array. This extends theexpect
function to include some useful assertions. clearMocks
is a boolean that tells Jest to clear the mocks after each test. This is useful if you have a lot of mocks and you want to make sure that you don't have any state that's left over from the previous test.infoIn this lab, I will show you how you can use Mock to mock out the
Math.random()
function.testEnvironment
is a string that tells Jest what environment to run the tests in. In this case, we're usingnode
because we're using Jest in a Node environment.watchPathIgnorePatterns
is an array of strings that tells Jest to ignore any files that match those patterns. This is useful if you have a lot of files and you don't want to run tests on them.testPathIgnorePatterns
is an array of strings that tells Jest to ignore any files that match those patterns. This is useful if you have a lot of files and you don't want to run tests on them.
Some More Project Configurationsโ
- Navigate to
tests/0.folderStructure.test.js
file for example. If you had already installed the VSCode ESLint, you'll see that it's flagging some of the built-in jest functions.
- to fix that, we need to add the Jest env. to the eslint config.
{
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"env": {
"browser": true,
"node": true,
"es2021": true,
"jest": true
},
"rules": {
"array-bracket-spacing": [2, "always"],
"no-const-assign": 2,
"no-var": "error",
"indent": [2, 2],
"quotes": [2, "backtick"],
"eqeqeq": "error"
}
}
Write New Testsโ
We will be testing the Logic of the Rock-Paper-Scissors game, or RockPaperScissors
class.
- We will be testing the
determinesWinner
andgenerateCPUResponse
functions.
- Create a new file:
tests/3.rock_paper_scissors-logic.test.js
file. - on the top, import the Rock Paper Scissors class (now that it's modularized)
const { RockPaperScissors } = require(`../resources/scripts/rock_paper_scissors.js`);
describe(`RockPaperScissors class`, function () {
describe(`determineWinner()`, function () {
test(`win cases`, function () {
const game = new RockPaperScissors();
expect(game.determineWinner(`rock`, `scissors`)).toBe(`win`);
// Complete the test
});
test(`tie cases`, function () {
// Write your test here
});
test(`lost cases`, function () {
// Write your test here
});
});
});
- Try running the tests using
npm test
and make sure your new tests are passing.
Improving the Developer Experience with VSCode Extensionsโ
Before we create more tests, let's try to streamline the process of writing and running tests. 7. Install the VScode Jest Extension.
- This will always run the tests in watch mode and show the result of the test in the side bar as well as next to each test.
Write more tests with Mocksโ
The Math.random()
function is a random number generator. It's a function that returns a number between 0 and 1. and the result of it is .. Well, Random!
It's difficult to test the generateCPUResponse
function because it uses the Math.random
, leading to a different response every time. (it's not exactly a pure function).
What we'll try to do here, is to hijack the Math.random()
function and mock it to return a specific value.
const { RockPaperScissors } = require(`../resources/scripts/rock_paper_scissors.js`);
const mathRandomSpy = jest.spyOn(Math, `random`);
describe(`RockPaperScissors class`, function () {
describe(`determineWinner()`, function () {
test(`win cases`, function () {
const game = new RockPaperScissors();
expect(game.determineWinner(`rock`, `scissors`)).toBe(`win`);
// Complete the test
});
test(`tie cases`, function () {
// Write your test here
});
test(`lost cases`, function () {
// Write your test here
});
});
describe(`generateCPUResponse()`, function () {
it(`Math.Random = 0.1 -> Rock`, function() {
mathRandomSpy.mockImplementation(() => 0.1);
const game = new RockPaperScissors();
expect(game.generateCPUResponse()).toBe(`rock`);
});
it(`Math.Random = 0.5 -> Paper`, function() {
// Write your test here
});
it(`Math.Random = 0.9 -> Paper`, function() {
// Write your test here
});
});
});