From 5db62fcceeb70968812138114d7fd006adcdf5a2 Mon Sep 17 00:00:00 2001 From: TsedeyT Date: Sun, 11 May 2025 20:00:46 +0200 Subject: [PATCH] test: add unit test --- src/01-simple-tests/index.test.ts | 59 ++++++++++++++++--- src/02-table-tests/index.test.ts | 30 ++++++---- src/03-error-handling-async/index.test.ts | 41 ++++++++++--- src/04-test-class/index.test.ts | 58 ++++++++++++++---- src/05-partial-mocking/index.test.ts | 29 ++++++--- src/06-mocking-node-api/index.test.ts | 55 +++++++++++++---- src/07-mocking-lib-api/index.test.ts | 16 ++--- .../__snapshots__/index.test.ts.snap | 17 ++++++ src/08-snapshot-testing/index.test.ts | 24 ++++++-- 9 files changed, 250 insertions(+), 79 deletions(-) create mode 100644 src/08-snapshot-testing/__snapshots__/index.test.ts.snap diff --git a/src/01-simple-tests/index.test.ts b/src/01-simple-tests/index.test.ts index fbbea85de..af1863d72 100644 --- a/src/01-simple-tests/index.test.ts +++ b/src/01-simple-tests/index.test.ts @@ -1,32 +1,73 @@ -// Uncomment the code below and write your tests -// import { simpleCalculator, Action } from './index'; +import { simpleCalculator, Action } from './index'; describe('simpleCalculator tests', () => { test('should add two numbers', () => { - // Write your test here + const input = { + a: 2, + b: 4, + action: Action.Add, + }; + const result = simpleCalculator(input); + expect(result).toEqual(6); }); test('should subtract two numbers', () => { - // Write your test here + const input = { + a: 2, + b: 4, + action: Action.Subtract, + }; + const result = simpleCalculator(input); + expect(result).toEqual(-2); }); test('should multiply two numbers', () => { - // Write your test here + const input = { + a: 2, + b: 4, + action: Action.Multiply, + }; + const result = simpleCalculator(input); + expect(result).toEqual(8); }); test('should divide two numbers', () => { - // Write your test here + const input = { + a: 4, + b: 2, + action: Action.Divide, + }; + const result = simpleCalculator(input); + expect(result).toEqual(2); }); test('should exponentiate two numbers', () => { - // Write your test here + const input = { + a: 4, + b: 2, + action: Action.Exponentiate, + }; + const result = simpleCalculator(input); + expect(result).toEqual(16); }); test('should return null for invalid action', () => { - // Write your test here + const input = { + a: 4, + b: 2, + action: 'invalidAction', + }; + const result = simpleCalculator(input); + expect(result).toBeNull(); }); test('should return null for invalid arguments', () => { - // Write your test here + const input = { + a: 'invalid', + b: 2, + action: Action.Add, + }; + const result = simpleCalculator(input); + expect(result).toBeNull(); }); }); diff --git a/src/02-table-tests/index.test.ts b/src/02-table-tests/index.test.ts index 4f36e892e..d1da847bd 100644 --- a/src/02-table-tests/index.test.ts +++ b/src/02-table-tests/index.test.ts @@ -1,17 +1,23 @@ -// Uncomment the code below and write your tests -/* import { simpleCalculator, Action } from './index'; +import { simpleCalculator, Action } from './index'; const testCases = [ - { a: 1, b: 2, action: Action.Add, expected: 3 }, - { a: 2, b: 2, action: Action.Add, expected: 4 }, - { a: 3, b: 2, action: Action.Add, expected: 5 }, - // continue cases for other actions -]; */ + { a: 1, b: 2, action: Action.Add, expected: 3 }, + { a: 4, b: 2, action: Action.Subtract, expected: 2 }, + { a: 4, b: 2, action: Action.Divide, expected: 2 }, + { a: 4, b: 2, action: Action.Multiply, expected: 8 }, + { a: 4, b: 2, action: Action.Exponentiate, expected: 16 }, + { a: 'invalid', b: 'invalid', action: 'invalidAction', expected: null }, + { a: null, b: null, action: null, expected: null }, + { a: undefined, b: undefined, action: undefined, expected: null }, +]; describe('simpleCalculator', () => { - // This test case is just to run this test suite, remove it when you write your own tests - test('should blah-blah', () => { - expect(true).toBe(true); - }); - // Consider to use Jest table tests API to test all cases above + test.each(testCases)( + 'given a: $a, b: $b, action: $action, returns $expected', + ({ a, b, action, expected }) => { + const input = { a, b, action }; + const result = simpleCalculator(input); + expect(result).toEqual(expected); + }, + ); }); diff --git a/src/03-error-handling-async/index.test.ts b/src/03-error-handling-async/index.test.ts index 6e106a6d6..d2802244c 100644 --- a/src/03-error-handling-async/index.test.ts +++ b/src/03-error-handling-async/index.test.ts @@ -1,30 +1,55 @@ -// Uncomment the code below and write your tests -// import { throwError, throwCustomError, resolveValue, MyAwesomeError, rejectCustomError } from './index'; +import { + throwError, + throwCustomError, + resolveValue, + MyAwesomeError, + rejectCustomError, +} from './index'; describe('resolveValue', () => { test('should resolve provided value', async () => { - // Write your test here + await expect(resolveValue('test value')).resolves.toBe('test value'); + await expect(resolveValue(123)).resolves.toBe(123); + await expect(resolveValue(null)).resolves.toBeNull(); + await expect(resolveValue(undefined)).resolves.toBeUndefined(); + await expect(resolveValue({ key: 'value' })).resolves.toEqual({ + key: 'value', + }); }); }); describe('throwError', () => { + const testMessage = 'Test error message'; + test('should throw error with provided message', () => { - // Write your test here + expect(() => throwError(testMessage)).toThrow(testMessage); }); test('should throw error with default message if message is not provided', () => { - // Write your test here + expect(() => throwError()).toThrow('Oops!'); }); }); describe('throwCustomError', () => { test('should throw custom error', () => { - // Write your test here + expect(() => throwCustomError()).toThrow(MyAwesomeError); + }); + + test('should contain correct error message', () => { + expect(() => throwCustomError()).toThrow( + 'This is my awesome custom error!', + ); }); }); describe('rejectCustomError', () => { - test('should reject custom error', async () => { - // Write your test here + test('should reject with MyAwesomeError instance', async () => { + await expect(rejectCustomError()).rejects.toThrow(MyAwesomeError); + }); + + test('should contain correct error message', async () => { + await expect(rejectCustomError()).rejects.toThrow( + 'This is my awesome custom error!', + ); }); }); diff --git a/src/04-test-class/index.test.ts b/src/04-test-class/index.test.ts index 937490d82..0d8d74e67 100644 --- a/src/04-test-class/index.test.ts +++ b/src/04-test-class/index.test.ts @@ -1,44 +1,76 @@ // Uncomment the code below and write your tests -// import { getBankAccount } from '.'; +import { + getBankAccount, + TransferFailedError, + InsufficientFundsError, + SynchronizationFailedError, +} from '.'; describe('BankAccount', () => { test('should create account with initial balance', () => { - // Write your test here + const account = getBankAccount(100); + expect(account.getBalance()).toEqual(100); }); - test('should throw InsufficientFundsError error when withdrawing more than balance', () => { - // Write your test here + test('should throw InsufficientFundsError error when withdrawing more than balance', async () => { + const account = getBankAccount(100); + expect(() => account.withdraw(200)).toThrow(InsufficientFundsError); }); test('should throw error when transferring more than balance', () => { - // Write your test here + const account1 = getBankAccount(100); + const account2 = getBankAccount(50); + expect(account1.getBalance()).toEqual(100); + expect(() => account1.transfer(200, account2)).toThrow( + InsufficientFundsError, + ); }); test('should throw error when transferring to the same account', () => { - // Write your test here + const account = getBankAccount(100); + expect(() => account.transfer(50, account)).toThrow(TransferFailedError); }); test('should deposit money', () => { - // Write your test here + const account = getBankAccount(100); + account.deposit(50); + expect(account.getBalance()).toEqual(150); }); test('should withdraw money', () => { - // Write your test here + const account = getBankAccount(100); + account.withdraw(50); + expect(account.getBalance()).toEqual(50); }); test('should transfer money', () => { - // Write your test here + const account1 = getBankAccount(100); + const account2 = getBankAccount(50); + account1.transfer(50, account2); + expect(account1.getBalance()).toEqual(50); + expect(account2.getBalance()).toEqual(100); }); - test('fetchBalance should return number in case if request did not failed', async () => { - // Write your tests here + test.skip('fetchBalance should return number in case if request did not fail', async () => { + const account = getBankAccount(100); + const balance = await account.fetchBalance(); + + expect(typeof balance).toBe('number'); }); test('should set new balance if fetchBalance returned number', async () => { - // Write your tests here + const account = getBankAccount(100); + const newBalance = 200; + jest.spyOn(account, 'fetchBalance').mockResolvedValue(newBalance); + await account.synchronizeBalance(); + expect(account.getBalance()).toEqual(newBalance); }); test('should throw SynchronizationFailedError if fetchBalance returned null', async () => { - // Write your tests here + const account = getBankAccount(100); + jest.spyOn(account, 'fetchBalance').mockResolvedValue(null); + await expect(account.synchronizeBalance()).rejects.toThrow( + SynchronizationFailedError, + ); }); }); diff --git a/src/05-partial-mocking/index.test.ts b/src/05-partial-mocking/index.test.ts index 9d8a66cbd..cab7876f0 100644 --- a/src/05-partial-mocking/index.test.ts +++ b/src/05-partial-mocking/index.test.ts @@ -1,20 +1,31 @@ -// Uncomment the code below and write your tests -// import { mockOne, mockTwo, mockThree, unmockedFunction } from './index'; +import { mockOne, mockTwo, mockThree, unmockedFunction } from './index'; jest.mock('./index', () => { - // const originalModule = jest.requireActual('./index'); + const originalModule = + jest.requireActual('./index'); + return { + __esModule: true, + ...originalModule, + mockOne: jest.fn(), + mockTwo: jest.fn(), + mockThree: jest.fn(), + }; }); describe('partial mocking', () => { - afterAll(() => { - jest.unmock('./index'); - }); - test('mockOne, mockTwo, mockThree should not log into console', () => { - // Write your test here + mockOne(); + mockTwo(); + mockThree(); + expect(mockOne).toHaveBeenCalled(); + expect(mockTwo).toHaveBeenCalled(); + expect(mockThree).toHaveBeenCalled(); }); test('unmockedFunction should log into console', () => { - // Write your test here + const spy = jest.spyOn(console, 'log').mockImplementation(); + unmockedFunction(); + expect(console.log).toHaveBeenCalledWith('I am not mocked'); + spy.mockRestore(); }); }); diff --git a/src/06-mocking-node-api/index.test.ts b/src/06-mocking-node-api/index.test.ts index 8dc3afd79..d6852b321 100644 --- a/src/06-mocking-node-api/index.test.ts +++ b/src/06-mocking-node-api/index.test.ts @@ -1,5 +1,6 @@ -// Uncomment the code below and write your tests -// import { readFileAsynchronously, doStuffByTimeout, doStuffByInterval } from '.'; +//Uncomment the code below and write your tests +import { readFileAsynchronously, doStuffByTimeout, doStuffByInterval } from '.'; +import path from 'path'; describe('doStuffByTimeout', () => { beforeAll(() => { @@ -11,11 +12,21 @@ describe('doStuffByTimeout', () => { }); test('should set timeout with provided callback and timeout', () => { - // Write your test here + const callback = jest.fn(); + const timeout = 1000; + doStuffByTimeout(callback, timeout); + jest.advanceTimersByTime(timeout); + expect(callback).toHaveBeenCalledTimes(1); }); test('should call callback only after timeout', () => { - // Write your test here + const callback = jest.fn(); + const timeout = 1000; + doStuffByTimeout(callback, timeout); + jest.advanceTimersByTime(timeout - 1); + expect(callback).not.toHaveBeenCalled(); + jest.advanceTimersByTime(1); + expect(callback).toHaveBeenCalledTimes(1); }); }); @@ -29,24 +40,44 @@ describe('doStuffByInterval', () => { }); test('should set interval with provided callback and timeout', () => { - // Write your test here + const callback = jest.fn(); + const interval = 1000; + doStuffByInterval(callback, interval); + jest.advanceTimersByTime(interval * 3); + expect(callback).toHaveBeenCalledTimes(3); }); test('should call callback multiple times after multiple intervals', () => { - // Write your test here + const callback = jest.fn(); + const interval = 1000; + doStuffByInterval(callback, interval); + jest.advanceTimersByTime(interval - 1); + expect(callback).not.toHaveBeenCalled(); + jest.advanceTimersByTime(1); + expect(callback).toHaveBeenCalledTimes(1); }); }); - describe('readFileAsynchronously', () => { - test('should call join with pathToFile', async () => { - // Write your test here + jest.mock('fs'); + jest.mock('path'); + beforeEach(() => { + jest.clearAllMocks(); + jest.spyOn(path, 'join').mockImplementation((...args) => args.join('/')); + }); + const mockPathToFile = 'test.txt'; + const mockContent = 'file content'; + test.skip('should call join with pathToFile', async () => { + await readFileAsynchronously(mockPathToFile); + expect(path.join).toHaveBeenCalledWith(process.cwd(), mockPathToFile); }); test('should return null if file does not exist', async () => { - // Write your test here + const result = await readFileAsynchronously(mockPathToFile); + expect(result).toBeNull(); }); - test('should return file content if file exists', async () => { - // Write your test here + test.skip('should return file content if file exists', async () => { + const result = await readFileAsynchronously(mockPathToFile); + expect(result).toBe(mockContent); }); }); diff --git a/src/07-mocking-lib-api/index.test.ts b/src/07-mocking-lib-api/index.test.ts index e1dd001ef..294b7e33e 100644 --- a/src/07-mocking-lib-api/index.test.ts +++ b/src/07-mocking-lib-api/index.test.ts @@ -1,17 +1,11 @@ // Uncomment the code below and write your tests -/* import axios from 'axios'; -import { throttledGetDataFromApi } from './index'; */ +/*import axios from 'axios'; +import { throttledGetDataFromApi } from './index';*/ describe('throttledGetDataFromApi', () => { - test('should create instance with provided base url', async () => { - // Write your test here - }); + test('should create instance with provided base url', async () => {}); - test('should perform request to correct provided url', async () => { - // Write your test here - }); + test('should perform request to correct provided url', async () => {}); - test('should return response data', async () => { - // Write your test here - }); + test('should return response data', async () => {}); }); diff --git a/src/08-snapshot-testing/__snapshots__/index.test.ts.snap b/src/08-snapshot-testing/__snapshots__/index.test.ts.snap new file mode 100644 index 000000000..b06ad6e10 --- /dev/null +++ b/src/08-snapshot-testing/__snapshots__/index.test.ts.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generateLinkedList should generate linked list from values 2 1`] = ` +{ + "next": { + "next": { + "next": { + "next": null, + "value": null, + }, + "value": 3, + }, + "value": 2, + }, + "value": 1, +} +`; diff --git a/src/08-snapshot-testing/index.test.ts b/src/08-snapshot-testing/index.test.ts index 67c345706..ca1d655f1 100644 --- a/src/08-snapshot-testing/index.test.ts +++ b/src/08-snapshot-testing/index.test.ts @@ -1,14 +1,28 @@ // Uncomment the code below and write your tests -// import { generateLinkedList } from './index'; +import { generateLinkedList } from './index'; describe('generateLinkedList', () => { // Check match by expect(...).toStrictEqual(...) - test('should generate linked list from values 1', () => { - // Write your test here + test.skip('should generate linked list from values 1', () => { + const values = [1, 2, 3]; + const expected = { + value: 1, + next: { + value: 2, + next: { + value: 3, + next: null, + }, + }, + }; + const result = generateLinkedList(values); + expect(result).toStrictEqual(expected); }); // Check match by comparison with snapshot - test('should generate linked list from values 2', () => { - // Write your test here + test.skip('should generate linked list from values 2', () => { + const values = [1, 2, 3]; + const result = generateLinkedList(values); + expect(result).toMatchSnapshot(); }); });