# Jest: JavaScript unit test ###### tags: `Test` > **Jest**: JavaScript Testing Framework > **Enzyme**: JavaScript Testing utility for testing your React Components' output > **React Testing Library(RTL)**: React DOM testing utilities <br/> ## Test Overview ![](https://i.imgur.com/2DVHjvG.png) ![](https://i.imgur.com/R1eOWtb.jpg) ![](https://i.imgur.com/ZeZc4p9.png) ![](https://i.imgur.com/DFulCfV.jpg) ![](https://i.imgur.com/v1pjKOU.png) ![](https://i.imgur.com/KIDciU0.png) ![](https://i.imgur.com/jf3gOG7.png) #### Test File Naming Utils ![](https://i.imgur.com/iGQudLj.png) Components ![](https://i.imgur.com/MU0VY81.png) <br/> --- ## Unit Test Concept ### AAA -- Arrange, Act, Assert ![](https://i.imgur.com/ybDP62n.png) `add.js` ```javascript= export function add(numbers) { let sum = 0; for (const number of numbers) { sum += +number; } return sum; } ``` ### Jest Syntax **`it([descritiption string], [ test function])`** **`test([descritiption string], [ test function])`** ```javascript= it("description", ()=>{ // This unit test // 1. Arrange // 2. Act // 3. Assert }) ``` `add.test.js` ```javascript= import { add } from './add'; it("should sum up all number values in the array", () => { // Arrange const inputs = [1, 2, 3]; // Act const result = add(inputs); // Assert const expectedResult = inputs.reduce((prevVal, curVal) => prevVal + curVal , 0); expect(result).toBe(expectedResult); }); ``` <br/> #### Keyword (method) **`it`**/**`test`** : create a unit test **`expect`** : assertion [Jest Official Document: Expect Matcher](https://jestjs.io/docs/expect) <br/> >*What else do we want to test for this function?* <br /> `add.test.js` ```javascript= import { add } from './add'; it("should sum up all number values in the array", () => { const inputs = [1, 2, 3]; const result = add(inputs); const expectedResult = inputs.reduce((prevVal, curVal) => prevVal + curVal , 0); expect(result).toBe(expectedResult); }); it("should yield NaN if at least one invalid number is provided", () => { const inputs = ["invalid", 1]; const result = add(inputs); expect(result).toBeNaN(); }); it("should yield a correct sum if an array of numeric string values are provided", () => { const inputs = ["1", "2"]; const result = add(inputs); const expectedResult = inputs.map((numStr)=> +numStr).reduce((a,b) => a + b, 0); expect(result).toBe(expectedResult); }); it("should yield 0 if an empty array is provided", () => { const inputs = []; const result = add(inputs); expect(result).toBe(0); }); ``` ### Writing Good Test - AAA - Only Test **One** Thing - Focus on the **essence** of a test when arranging - Keep your number of assertioin(`expect`) **low** <br /> ## Other basic Jest method ### `describe` > organize test suites `validation.js` ```javascript= export function validateStringNotEmpty(value) { if (value.trim().length === 0) { throw new Error('Invalid input - must not be empty.'); } } export function validateNumber(number) { if (isNaN(number)) { throw new Error('Invalid number input.'); } } ``` <br/> `validation.test.js` ```javascript= import { it, expect, describe } from "vitest"; import { validateNumber, validateStringNotEmpty } from "./validation"; describe("validateStringNotEmpty()", () => { it("should not throw an error error when non-empty string is provided", () => { const input = " string "; const resultFn = () => validateStringNotEmpty(input); expect(resultFn).not.toThrow(); }); it("should throw an error when empty string is provided", () => { const input1 = " "; const input2 = "" ; const resultFn1 = () => validateStringNotEmpty(input1); const resultFn2 = () => validateStringNotEmpty(input2); expect(resultFn1).toThrow("Invalid input - must not be empty."); expect(resultFn2).toThrow("Invalid input - must not be empty."); }); it('should throw an error if any other value than a string is provided', () => { const inputNum = 1; const inputBool = true; const inputObj = {}; const validationFnNum = () => validateStringNotEmpty(inputNum); const validationFnBool = () => validateStringNotEmpty(inputBool); const validationFnObj = () => validateStringNotEmpty(inputObj); expect(validationFnNum).toThrow(); expect(validationFnBool).toThrow(); expect(validationFnObj).toThrow(); }); }) describe("validateNumber()", () => { it("should throw an error when input is NaN", () => { const input = NaN; const resultFn = () => validateNumber(input); expect(resultFn).toThrow("Invalid number input."); }); it("should not throw an error error when a number is provided", () => { const input = 1; const resultFn = () => validateNumber(input); expect(resultFn).not.toThrow(); }); }) ``` <br /> --- ### Jest hooks :`beforeAll`, `beforeEach`, `afterAll`, `afterEach` > Set up and clean-up among test in the same file `user.js` ```javascript= export class User { constructor(email) { this.email = email; } updateEmail(newEmail) { this.email = newEmail; } clearEmail() { this.email = ''; } } ``` `user.test.js` ```javascript= import { it, expect, beforeEach, beforeAll } from 'vitest'; import { User } from './user'; const testEmail = 'test@test.com'; let user; beforeEach(() => { user = new User(testEmail); }); it('should update the email', () => { const newTestEmail = 'test2@test.com'; user.updateEmail(newTestEmail); expect(user.email).toBe(newTestEmail); }); it('should have an email property', () => { expect(user).toHaveProperty('email'); }); it('should store the provided email value', () => { expect(user.email).toBe(testEmail); }); it('should clear the email', () => { user.clearEmail(); expect(user.email).toBe(''); }); it('should still have an email property after clearing the email', () => { user.clearEmail(); expect(user).toHaveProperty('email'); }); ``` --- ### Concept: Mock and Spy supplement https://medium.com/@rickhanlonii/understanding-jest-mocks-f0046c68e53c https://fork-risk-978.notion.site/Jest-mocks-081bccd7a8fe4e9dacb6b1ed02d1e898