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.jsonby runningnpm installin 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/domand@testing-library/jest-domlibraries, I need to addregenerator-runtime/runtimeand@testing-library/jest-dom/extend-expectto thesetupFilesAfterEnvarray. This extends theexpectfunction to include some useful assertions. clearMocksis 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.testEnvironmentis a string that tells Jest what environment to run the tests in. In this case, we're usingnodebecause we're using Jest in a Node environment.watchPathIgnorePatternsis 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.testPathIgnorePatternsis 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.jsfile 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
determinesWinnerandgenerateCPUResponsefunctions.
- Create a new file:
tests/3.rock_paper_scissors-logic.test.jsfile. - 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 testand 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
});
});
});