From bd126bd9a8d2b7990c5d677cef53c4062731df47 Mon Sep 17 00:00:00 2001 From: Sviatoslav Pokhvalenko Date: Mon, 12 May 2025 10:34:23 +0200 Subject: [PATCH 1/9] Added simple tests --- src/01-simple-tests/index.test.ts | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/01-simple-tests/index.test.ts b/src/01-simple-tests/index.test.ts index fbbea85de..54b3c4b22 100644 --- a/src/01-simple-tests/index.test.ts +++ b/src/01-simple-tests/index.test.ts @@ -1,32 +1,40 @@ // Uncomment the code below and write your tests // import { simpleCalculator, Action } from './index'; +import { Action, simpleCalculator } from '01-simple-tests'; + describe('simpleCalculator tests', () => { test('should add two numbers', () => { - // Write your test here + expect(simpleCalculator({ a: 1, b: 2, action: Action.Add })).toBe(3); }); test('should subtract two numbers', () => { - // Write your test here + expect(simpleCalculator({ a: 2, b: 1, action: Action.Subtract })).toBe(1); }); test('should multiply two numbers', () => { - // Write your test here + expect(simpleCalculator({ a: 2, b: 2, action: Action.Multiply })).toBe(4); }); test('should divide two numbers', () => { - // Write your test here + expect(simpleCalculator({ a: 4, b: 2, action: Action.Divide })).toBe(2); }); test('should exponentiate two numbers', () => { - // Write your test here + expect(simpleCalculator({ a: 5, b: 2, action: Action.Exponentiate })).toBe( + 25, + ); }); test('should return null for invalid action', () => { - // Write your test here + expect( + simpleCalculator({ a: 'a' as unknown, b: 2, action: 'smth' as Action }), + ).toBeNull(); }); test('should return null for invalid arguments', () => { - // Write your test here + expect( + simpleCalculator({ a: 'smth' as unknown, b: 2, action: Action.Add }), + ).toBeNull(); }); }); From 7de43d280a0d7d8237c815966eece7a758c534f3 Mon Sep 17 00:00:00 2001 From: Sviatoslav Pokhvalenko Date: Mon, 12 May 2025 10:36:52 +0200 Subject: [PATCH 2/9] Added table tests --- src/02-table-tests/index.test.ts | 45 +++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/src/02-table-tests/index.test.ts b/src/02-table-tests/index.test.ts index 4f36e892e..12772d0a0 100644 --- a/src/02-table-tests/index.test.ts +++ b/src/02-table-tests/index.test.ts @@ -1,17 +1,42 @@ // 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: 2, b: 2, action: Action.Add, expected: 4 }, + { a: 3, b: 2, action: Action.Add, expected: 5 }, + { a: 6, b: 2, action: Action.Divide, expected: 3 }, + { a: 4, b: 2, action: Action.Divide, expected: 2 }, + { a: 2, b: 2, action: Action.Divide, expected: 1 }, + { a: 3, b: 2, action: Action.Subtract, expected: 1 }, + { a: 4, b: 2, action: Action.Subtract, expected: 2 }, + { a: 5, b: 2, action: Action.Subtract, expected: 3 }, + { a: 3, b: 2, action: Action.Exponentiate, expected: 9 }, + { a: 2, b: 2, action: Action.Exponentiate, expected: 4 }, + { a: 1, b: 2, action: Action.Exponentiate, expected: 1 }, + { a: 3, b: 2, action: Action.Multiply, expected: 6 }, + { a: 4, b: 2, action: Action.Multiply, expected: 8 }, + { a: 5, b: 2, action: Action.Multiply, expected: 10 }, +]; 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); + test.each(testCases)( + `Should return $expected when $a $action $b`, + ({ a, b, action, expected }) => { + expect(simpleCalculator({ a, b, action })).toBe(expected); + }, + ); + + test('should return null for invalid action', () => { + expect(simpleCalculator({ a: 1, b: 2, action: 'smth' })).toBeNull(); + }); + + test('should return null for invalid args', () => { + expect( + simpleCalculator({ a: 'smth', b: 2, action: Action.Add }), + ).toBeNull(); + expect( + simpleCalculator({ a: 1, b: 'smth', action: Action.Add }), + ).toBeNull(); }); - // Consider to use Jest table tests API to test all cases above }); From feaac685b95342d4c6a76ed2a6b46400cb06847e Mon Sep 17 00:00:00 2001 From: Sviatoslav Pokhvalenko Date: Mon, 12 May 2025 10:38:41 +0200 Subject: [PATCH 3/9] Added error handling tests --- src/03-error-handling-async/index.test.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/03-error-handling-async/index.test.ts b/src/03-error-handling-async/index.test.ts index 6e106a6d6..a878e806f 100644 --- a/src/03-error-handling-async/index.test.ts +++ b/src/03-error-handling-async/index.test.ts @@ -1,30 +1,37 @@ // 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(5)).resolves.toBe(5); + await expect(resolveValue('smth')).resolves.toBe('smth'); }); }); describe('throwError', () => { test('should throw error with provided message', () => { - // Write your test here + expect(() => throwError('Error message')).toThrow('Error message'); }); test('should throw error with default message if message is not provided', () => { - // Write your test here + expect(() => throwError()).toThrow('No error message provided.'); }); }); describe('throwCustomError', () => { test('should throw custom error', () => { - // Write your test here + expect(() => throwCustomError()).toThrow(MyAwesomeError); }); }); describe('rejectCustomError', () => { test('should reject custom error', async () => { - // Write your test here + expect(() => rejectCustomError()).rejects.toThrow(MyAwesomeError); }); }); From ca9cf0c62a9d339caacf61134e3841e395d18ba8 Mon Sep 17 00:00:00 2001 From: Sviatoslav Pokhvalenko Date: Mon, 12 May 2025 11:20:53 +0200 Subject: [PATCH 4/9] Solved problem in error handling tests --- src/03-error-handling-async/index.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/03-error-handling-async/index.test.ts b/src/03-error-handling-async/index.test.ts index a878e806f..d17c972ea 100644 --- a/src/03-error-handling-async/index.test.ts +++ b/src/03-error-handling-async/index.test.ts @@ -20,7 +20,7 @@ describe('throwError', () => { }); test('should throw error with default message if message is not provided', () => { - expect(() => throwError()).toThrow('No error message provided.'); + expect(() => throwError()).toThrow('Oops!'); }); }); From 3f87acbdb7a0cb5bdc5aac1ccfa90065c9592f18 Mon Sep 17 00:00:00 2001 From: Sviatoslav Pokhvalenko Date: Mon, 12 May 2025 11:23:28 +0200 Subject: [PATCH 5/9] Added test class tests --- src/04-test-class/index.test.ts | 63 ++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/src/04-test-class/index.test.ts b/src/04-test-class/index.test.ts index 937490d82..19168fed5 100644 --- a/src/04-test-class/index.test.ts +++ b/src/04-test-class/index.test.ts @@ -1,44 +1,83 @@ -// Uncomment the code below and write your tests -// import { getBankAccount } from '.'; +import { + getBankAccount, + InsufficientFundsError, + SynchronizationFailedError, + TransferFailedError, +} from '.'; describe('BankAccount', () => { test('should create account with initial balance', () => { - // Write your test here + const firstBank = getBankAccount(10); + + expect(firstBank.getBalance()).toBe(10); }); test('should throw InsufficientFundsError error when withdrawing more than balance', () => { - // Write your test here + const firstBank = getBankAccount(10); + + expect(() => firstBank.withdraw(20)).toThrow(InsufficientFundsError); }); test('should throw error when transferring more than balance', () => { - // Write your test here + const firstBank = getBankAccount(10); + const secondBank = getBankAccount(0); + + expect(() => firstBank.transfer(20, secondBank)).toThrow( + InsufficientFundsError, + ); }); test('should throw error when transferring to the same account', () => { - // Write your test here + const firstBank = getBankAccount(10); + + expect(() => firstBank.transfer(10, firstBank)).toThrow( + TransferFailedError, + ); }); test('should deposit money', () => { - // Write your test here + const firstBank = getBankAccount(10); + + expect(firstBank.deposit(10).getBalance()).toBe(20); }); test('should withdraw money', () => { - // Write your test here + const firstBank = getBankAccount(10); + + expect(firstBank.withdraw(10).getBalance()).toBe(0); }); test('should transfer money', () => { - // Write your test here + const firstBank = getBankAccount(10); + const secondBank = getBankAccount(0); + + expect(firstBank.transfer(10, secondBank).getBalance()).toBe(0); + expect(secondBank.getBalance()).toBe(10); }); test('fetchBalance should return number in case if request did not failed', async () => { - // Write your tests here + const firstBank = getBankAccount(10); + const result = await firstBank.fetchBalance(); + + result == null + ? expect(result).toBeNull() + : expect(typeof result).toBe('number'); }); test('should set new balance if fetchBalance returned number', async () => { - // Write your tests here + const firstBank = getBankAccount(0); + + firstBank.fetchBalance = async () => 30; + await firstBank.synchronizeBalance(); + expect(firstBank.getBalance()).toBe(30); }); test('should throw SynchronizationFailedError if fetchBalance returned null', async () => { - // Write your tests here + const firstBank = getBankAccount(0); + + firstBank.fetchBalance = async () => null; + await expect(firstBank.synchronizeBalance()).rejects.toThrow( + SynchronizationFailedError, + ); }); }); From 946a02639a08ce8543d93a95e66583b16e414d88 Mon Sep 17 00:00:00 2001 From: Sviatoslav Pokhvalenko Date: Mon, 12 May 2025 11:32:17 +0200 Subject: [PATCH 6/9] Added partial mocking tests --- src/05-partial-mocking/index.test.ts | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/05-partial-mocking/index.test.ts b/src/05-partial-mocking/index.test.ts index 9d8a66cbd..2cbe18606 100644 --- a/src/05-partial-mocking/index.test.ts +++ b/src/05-partial-mocking/index.test.ts @@ -1,8 +1,15 @@ -// 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 { + ...originalModule, + mockOne: jest.fn(), + mockTwo: jest.fn(), + mockThree: jest.fn(), + }; }); describe('partial mocking', () => { @@ -11,10 +18,18 @@ describe('partial mocking', () => { }); test('mockOne, mockTwo, mockThree should not log into console', () => { - // Write your test here + const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); + mockOne(); + mockTwo(); + mockThree(); + expect(consoleSpy).not.toHaveBeenCalled(); + consoleSpy.mockRestore(); }); test('unmockedFunction should log into console', () => { - // Write your test here + const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); + unmockedFunction(); + expect(consoleSpy).toHaveBeenCalledWith('I am not mocked'); + consoleSpy.mockRestore(); }); }); From f2742449be37e6373f2a6b961908fcb15b50460a Mon Sep 17 00:00:00 2001 From: Sviatoslav Pokhvalenko Date: Mon, 12 May 2025 12:28:12 +0200 Subject: [PATCH 7/9] Added mocking node api tests --- src/06-mocking-node-api/index.test.ts | 54 ++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/src/06-mocking-node-api/index.test.ts b/src/06-mocking-node-api/index.test.ts index 8dc3afd79..f6823dc19 100644 --- a/src/06-mocking-node-api/index.test.ts +++ b/src/06-mocking-node-api/index.test.ts @@ -1,5 +1,7 @@ -// Uncomment the code below and write your tests -// import { readFileAsynchronously, doStuffByTimeout, doStuffByInterval } from '.'; +import { readFileAsynchronously, doStuffByTimeout, doStuffByInterval } from '.'; +import path from 'path'; +import fs from 'fs'; +import fsPromises from 'fs/promises'; describe('doStuffByTimeout', () => { beforeAll(() => { @@ -11,11 +13,21 @@ describe('doStuffByTimeout', () => { }); test('should set timeout with provided callback and timeout', () => { - // Write your test here + const spyTimeout = jest.spyOn(global, 'setTimeout'); + const cb = jest.fn(); + const timeout = 1000; + + doStuffByTimeout(cb, timeout); + expect(spyTimeout).toHaveBeenCalledWith(cb, timeout); }); test('should call callback only after timeout', () => { - // Write your test here + const cb = jest.fn(); + + doStuffByTimeout(cb, 1000); + expect(cb).not.toHaveBeenCalled(); + jest.advanceTimersByTime(1000); + expect(cb).toHaveBeenCalled(); }); }); @@ -29,24 +41,48 @@ describe('doStuffByInterval', () => { }); test('should set interval with provided callback and timeout', () => { - // Write your test here + const spyTimeout = jest.spyOn(global, 'setTimeout'); + const cb = jest.fn(); + const timeout = 1000; + + doStuffByTimeout(cb, timeout); + expect(spyTimeout).toHaveBeenCalledWith(cb, timeout); }); test('should call callback multiple times after multiple intervals', () => { - // Write your test here + const cb = jest.fn(); + + doStuffByInterval(cb, 100); + jest.advanceTimersByTime(300); + expect(cb).toHaveBeenCalledTimes(3); }); }); describe('readFileAsynchronously', () => { test('should call join with pathToFile', async () => { - // Write your test here + const joinSpy = jest.spyOn(path, 'join'); + const filePath = 'test'; + + await readFileAsynchronously(filePath); + expect(joinSpy).toHaveBeenCalledWith(__dirname, filePath); }); test('should return null if file does not exist', async () => { - // Write your test here + jest.spyOn(fs, 'existsSync').mockReturnValue(false); + const filePath = 'test'; + const result = await readFileAsynchronously(filePath); + + expect(result).toBeNull(); }); test('should return file content if file exists', async () => { - // Write your test here + jest.spyOn(fs, 'existsSync').mockReturnValue(true); + const filePath = 'test'; + const fileContent = 'content'; + const fileBuffer = Buffer.from(fileContent); + jest.spyOn(fsPromises, 'readFile').mockResolvedValue(fileBuffer); + const result = await readFileAsynchronously(filePath); + + expect(result).toBe(fileContent); }); }); From 02a11c3fd7bc9a24036d418aaf6e562a23c0342c Mon Sep 17 00:00:00 2001 From: Sviatoslav Pokhvalenko Date: Mon, 12 May 2025 23:11:13 +0200 Subject: [PATCH 8/9] Added mocking lib api tests --- src/07-mocking-lib-api/index.test.ts | 39 +++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/07-mocking-lib-api/index.test.ts b/src/07-mocking-lib-api/index.test.ts index e1dd001ef..d905c7cd1 100644 --- a/src/07-mocking-lib-api/index.test.ts +++ b/src/07-mocking-lib-api/index.test.ts @@ -1,17 +1,44 @@ -// Uncomment the code below and write your tests -/* import axios from 'axios'; -import { throttledGetDataFromApi } from './index'; */ +import axios from 'axios'; +import { throttledGetDataFromApi } from './index'; + +jest.mock('axios'); +jest.mock('lodash', () => ({ + throttle: unknown>(fn: T) => fn, +})); describe('throttledGetDataFromApi', () => { + const mockGet = jest.fn(); + const mockCreate = axios.create as jest.Mock; + + beforeEach(() => { + jest.clearAllMocks(); + mockCreate.mockReturnValue({ get: mockGet }); + }); + test('should create instance with provided base url', async () => { - // Write your test here + mockGet.mockResolvedValue({ data: {} }); + + await throttledGetDataFromApi('/posts'); + + expect(mockCreate).toHaveBeenCalledWith({ + baseURL: 'https://jsonplaceholder.typicode.com', + }); }); test('should perform request to correct provided url', async () => { - // Write your test here + mockGet.mockResolvedValue({ data: {} }); + + await throttledGetDataFromApi('/posts'); + + expect(mockGet).toHaveBeenCalledWith('/posts'); }); test('should return response data', async () => { - // Write your test here + const mockData = { id: 1, title: 'Example' }; + mockGet.mockResolvedValue({ data: mockData }); + + const result = await throttledGetDataFromApi('/posts'); + + expect(result).toEqual(mockData); }); }); From 1ae98ed61505240a416a0da144ba8a7f43da872a Mon Sep 17 00:00:00 2001 From: Sviatoslav Pokhvalenko Date: Mon, 12 May 2025 23:16:44 +0200 Subject: [PATCH 9/9] Added snapshot tests --- src/08-snapshot-testing/index.test.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/08-snapshot-testing/index.test.ts b/src/08-snapshot-testing/index.test.ts index 67c345706..e72e79033 100644 --- a/src/08-snapshot-testing/index.test.ts +++ b/src/08-snapshot-testing/index.test.ts @@ -1,14 +1,18 @@ -// 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 + const result = generateLinkedList([1, 2, 3]); + + expect(result).toStrictEqual({ + value: 1, + next: { value: 2, next: { value: 3, next: { value: null, next: null } } }, + }); }); - // Check match by comparison with snapshot test('should generate linked list from values 2', () => { - // Write your test here + const result = generateLinkedList(['a', 'b']); + + expect(result).toMatchSnapshot(); }); });