diff --git a/src/01-simple-tests/index.test.ts b/src/01-simple-tests/index.test.ts index fbbea85de..2b6601da1 100644 --- a/src/01-simple-tests/index.test.ts +++ b/src/01-simple-tests/index.test.ts @@ -1,32 +1,49 @@ -// 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: 3, b: 5, action: Action.Add }; + const result = simpleCalculator(input); + expect(result).toBe(8); }); test('should subtract two numbers', () => { - // Write your test here + const input = { a: 10, b: 4, action: Action.Subtract }; + const result = simpleCalculator(input); + expect(result).toBe(6); }); test('should multiply two numbers', () => { - // Write your test here + const input = { a: 6, b: 7, action: Action.Multiply }; + const result = simpleCalculator(input); + expect(result).toBe(42); }); test('should divide two numbers', () => { - // Write your test here + const input = { a: 20, b: 5, action: Action.Divide }; + const result = simpleCalculator(input); + expect(result).toBe(4); }); test('should exponentiate two numbers', () => { - // Write your test here + const input = { a: 2, b: 3, action: Action.Exponentiate }; + const result = simpleCalculator(input); + expect(result).toBe(8); }); test('should return null for invalid action', () => { - // Write your test here + const input = { a: 5, b: 10, action: 'invalid_action' }; + const result = simpleCalculator(input); + expect(result).toBeNull(); }); test('should return null for invalid arguments', () => { - // Write your test here + const input1 = { a: 'string', b: 10, action: Action.Add }; + const input2 = { a: 5, b: null, action: Action.Subtract }; + const input3 = { a: 5, b: 10, action: 123 }; // invalid action type + + expect(simpleCalculator(input1)).toBeNull(); + expect(simpleCalculator(input2)).toBeNull(); + expect(simpleCalculator(input3)).toBeNull(); }); }); diff --git a/src/02-table-tests/index.test.ts b/src/02-table-tests/index.test.ts index 4f36e892e..f150f95e3 100644 --- a/src/02-table-tests/index.test.ts +++ b/src/02-table-tests/index.test.ts @@ -1,17 +1,35 @@ -// 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: 5, b: 3, action: Action.Subtract, expected: 2 }, + { a: 6, b: 2, action: Action.Subtract, expected: 4 }, + { a: 3, b: 3, action: Action.Multiply, expected: 9 }, + { a: 8, b: 2, action: Action.Multiply, expected: 16 }, + { a: 10, b: 2, action: Action.Divide, expected: 5 }, + { a: 9, b: 3, action: Action.Divide, expected: 3 }, + { a: 2, b: 3, action: Action.Exponentiate, expected: 8 }, + { a: 5, b: 2, action: Action.Exponentiate, expected: 25 }, +]; 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 calculate $a $action $b to be $expected', + ({ a, b, action, expected }) => { + const result = simpleCalculator({ a, b, action }); + expect(result).toBe(expected); + }, + ); + + test('should return null for invalid action', () => { + const result = simpleCalculator({ a: 1, b: 2, action: 'invalid' }); + expect(result).toBeNull(); + }); + + test('should return null for invalid arguments', () => { + const result = simpleCalculator({ a: '1', b: 2, action: Action.Add }); + expect(result).toBeNull(); }); - // Consider to use Jest table tests API to test all cases above -}); +}); \ No newline at end of file diff --git a/src/03-error-handling-async/index.test.ts b/src/03-error-handling-async/index.test.ts index 6e106a6d6..b5a3a55d1 100644 --- a/src/03-error-handling-async/index.test.ts +++ b/src/03-error-handling-async/index.test.ts @@ -1,30 +1,44 @@ -// 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 + const value = 'test'; + const result = await resolveValue(value); + expect(result).toBe(value); }); }); describe('throwError', () => { test('should throw error with provided message', () => { - // Write your test here + const errorMessage = 'Custom error message'; + expect(() => throwError(errorMessage)).toThrowError(errorMessage); }); test('should throw error with default message if message is not provided', () => { - // Write your test here + expect(() => throwError()).toThrowError('Oops!'); }); }); describe('throwCustomError', () => { test('should throw custom error', () => { - // Write your test here + expect(() => throwCustomError()).toThrowError(MyAwesomeError); + expect(() => throwCustomError()).toThrowError( + 'This is my awesome custom error!', + ); }); }); describe('rejectCustomError', () => { test('should reject custom error', async () => { - // Write your test here + await expect(rejectCustomError()).rejects.toThrowError(MyAwesomeError); + await expect(rejectCustomError()).rejects.toThrowError( + '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..c991654a2 100644 --- a/src/04-test-class/index.test.ts +++ b/src/04-test-class/index.test.ts @@ -1,44 +1,84 @@ -// Uncomment the code below and write your tests -// import { getBankAccount } from '.'; +import { + getBankAccount, + InsufficientFundsError, + TransferFailedError, + SynchronizationFailedError, +} from './index'; +import { random } from 'lodash'; + +jest.mock('lodash', () => ({ + random: jest.fn(), +})); describe('BankAccount', () => { test('should create account with initial balance', () => { - // Write your test here + const account = getBankAccount(100); + expect(account.getBalance()).toBe(100); }); test('should throw InsufficientFundsError error when withdrawing more than balance', () => { - // Write your test here + const account = getBankAccount(50); + expect(() => account.withdraw(100)).toThrow(InsufficientFundsError); + expect(() => account.withdraw(100)).toThrow( + 'Insufficient funds: cannot withdraw more than 50', + ); }); test('should throw error when transferring more than balance', () => { - // Write your test here + const account1 = getBankAccount(50); + const account2 = getBankAccount(100); + + expect(() => account1.transfer(100, account2)).toThrow( + InsufficientFundsError, + ); }); test('should throw error when transferring to the same account', () => { - // Write your test here + const account = getBankAccount(50); + expect(() => account.transfer(10, account)).toThrow(TransferFailedError); + expect(() => account.transfer(10, account)).toThrow('Transfer failed'); }); test('should deposit money', () => { - // Write your test here + const account = getBankAccount(50); + account.deposit(50); + expect(account.getBalance()).toBe(100); }); test('should withdraw money', () => { - // Write your test here + const account = getBankAccount(100); + account.withdraw(50); + expect(account.getBalance()).toBe(50); }); test('should transfer money', () => { - // Write your test here + const account1 = getBankAccount(100); + const account2 = getBankAccount(50); + + account1.transfer(50, account2); + expect(account1.getBalance()).toBe(50); + expect(account2.getBalance()).toBe(100); }); - test('fetchBalance should return number in case if request did not failed', async () => { - // Write your tests here + test('fetchBalance should return number in case request did not fail', async () => { + (random as jest.Mock).mockReturnValueOnce(75).mockReturnValueOnce(1); + const account = getBankAccount(100); + const balance = await account.fetchBalance(); + expect(balance).toBe(75); }); test('should set new balance if fetchBalance returned number', async () => { - // Write your tests here + (random as jest.Mock).mockReturnValueOnce(75).mockReturnValueOnce(1); + const account = getBankAccount(100); + await account.synchronizeBalance(); + expect(account.getBalance()).toBe(75); }); test('should throw SynchronizationFailedError if fetchBalance returned null', async () => { - // Write your tests here + (random as jest.Mock).mockReturnValueOnce(50).mockReturnValueOnce(0); + const account = getBankAccount(100); + 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..6fe2aaa12 100644 --- a/src/05-partial-mocking/index.test.ts +++ b/src/05-partial-mocking/index.test.ts @@ -1,8 +1,12 @@ -// 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'); + return { + mockOne: jest.fn(), + mockTwo: jest.fn(), + mockThree: jest.fn(), + unmockedFunction: jest.requireActual('./index').unmockedFunction, + }; }); describe('partial mocking', () => { @@ -11,10 +15,23 @@ describe('partial mocking', () => { }); test('mockOne, mockTwo, mockThree should not log into console', () => { - // Write your test here + const consoleSpy = jest.spyOn(console, 'log'); + + mockOne(); + mockTwo(); + mockThree(); + + expect(consoleSpy).not.toHaveBeenCalledWith('foo'); + expect(consoleSpy).not.toHaveBeenCalledWith('bar'); + expect(consoleSpy).not.toHaveBeenCalledWith('baz'); + + consoleSpy.mockRestore(); }); test('unmockedFunction should log into console', () => { - // Write your test here + const consoleSpy = jest.spyOn(console, 'log'); + unmockedFunction(); + expect(consoleSpy).toHaveBeenCalledWith('I am not mocked'); + consoleSpy.mockRestore(); }); }); diff --git a/src/06-mocking-node-api/index.test.ts b/src/06-mocking-node-api/index.test.ts index 8dc3afd79..f1d43c824 100644 --- a/src/06-mocking-node-api/index.test.ts +++ b/src/06-mocking-node-api/index.test.ts @@ -1,5 +1,19 @@ -// Uncomment the code below and write your tests -// import { readFileAsynchronously, doStuffByTimeout, doStuffByInterval } from '.'; +import { readFileAsynchronously, doStuffByTimeout, doStuffByInterval } from '.'; +import { existsSync } from 'fs'; +import { readFile } from 'fs/promises'; +import { join } from 'path'; + +jest.mock('fs', () => ({ + existsSync: jest.fn(), +})); + +jest.mock('fs/promises', () => ({ + readFile: jest.fn(), +})); + +jest.mock('path', () => ({ + join: jest.fn(), +})); describe('doStuffByTimeout', () => { beforeAll(() => { @@ -11,11 +25,19 @@ describe('doStuffByTimeout', () => { }); test('should set timeout with provided callback and timeout', () => { - // Write your test here + const callback = jest.fn(); + const timeout = 1000; + jest.spyOn(global, 'setTimeout'); + doStuffByTimeout(callback, timeout); + expect(setTimeout).toHaveBeenCalledWith(callback, timeout); }); test('should call callback only after timeout', () => { - // Write your test here + const callback = jest.fn(); + const timeout = 1000; + doStuffByTimeout(callback, timeout); + jest.advanceTimersByTime(timeout); + expect(callback).toHaveBeenCalled(); }); }); @@ -29,24 +51,58 @@ describe('doStuffByInterval', () => { }); test('should set interval with provided callback and timeout', () => { - // Write your test here + const callback = jest.fn(); + const interval = 1000; + jest.spyOn(global, 'setInterval'); + doStuffByInterval(callback, interval); + expect(setInterval).toHaveBeenCalledWith(callback, interval); }); 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 * 3); + expect(callback).toHaveBeenCalledTimes(3); }); }); describe('readFileAsynchronously', () => { + const mockFullPath = './test.txt'; + + beforeEach(() => { + (join as jest.Mock).mockReturnValue(mockFullPath); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + test('should call join with pathToFile', async () => { - // Write your test here + const pathToFile = 'test.txt'; + + await readFileAsynchronously(pathToFile); + + expect(join).toHaveBeenCalledWith(__dirname, pathToFile); }); test('should return null if file does not exist', async () => { - // Write your test here + (existsSync as jest.Mock).mockReturnValue(false); + + const result = await readFileAsynchronously('test.txt'); + + expect(result).toBeNull(); + expect(readFile).not.toHaveBeenCalled(); }); test('should return file content if file exists', async () => { - // Write your test here + (existsSync as jest.Mock).mockReturnValue(true); + (readFile as jest.Mock).mockResolvedValue(Buffer.from('file content')); + + const result = await readFileAsynchronously('test.txt'); + + expect(result).toBe('file content'); + expect(readFile).toHaveBeenCalledWith(mockFullPath); }); }); diff --git a/src/07-mocking-lib-api/index.test.ts b/src/07-mocking-lib-api/index.test.ts index e1dd001ef..78e6a897a 100644 --- a/src/07-mocking-lib-api/index.test.ts +++ b/src/07-mocking-lib-api/index.test.ts @@ -1,17 +1,60 @@ -// 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: jest.fn((fn) => fn), // Mock throttle to bypass throttling behavior for tests +})); describe('throttledGetDataFromApi', () => { - test('should create instance with provided base url', async () => { - // Write your test here + beforeEach(() => { + jest.clearAllMocks(); // Clear any previously stored mocks + }); + + test('should create instance with provided base URL', async () => { + const relativePath = '/posts/1'; + const mockResponse = { data: { id: 1, title: 'Test Post' } }; + + // Mock the axios.create() and axios.get() behavior + const axiosInstance = { get: jest.fn().mockResolvedValue(mockResponse) }; + (axios.create as jest.Mock).mockReturnValue(axiosInstance); + + // Call the function + await throttledGetDataFromApi(relativePath); + + // Check that axios.create was called with the correct base URL + expect(axios.create).toHaveBeenCalledWith({ + baseURL: 'https://jsonplaceholder.typicode.com', + }); }); - test('should perform request to correct provided url', async () => { - // Write your test here + test('should perform request to correct provided URL', async () => { + const relativePath = '/posts/1'; + const mockResponse = { data: { id: 1, title: 'Test Post' } }; + + // Mock the axios.create() and axios.get() behavior + const axiosInstance = { get: jest.fn().mockResolvedValue(mockResponse) }; + (axios.create as jest.Mock).mockReturnValue(axiosInstance); + + // Call the function + await throttledGetDataFromApi(relativePath); + + // Check that axios.get was called with the correct relative URL + expect(axiosInstance.get).toHaveBeenCalledWith(relativePath); }); test('should return response data', async () => { - // Write your test here + const relativePath = '/posts/1'; + const mockResponse = { data: { id: 1, title: 'Test Post' } }; + + // Mock the axios.create() and axios.get() behavior + const axiosInstance = { get: jest.fn().mockResolvedValue(mockResponse) }; + (axios.create as jest.Mock).mockReturnValue(axiosInstance); + + // Call the function and capture the result + const result = await throttledGetDataFromApi(relativePath); + + // Check that the returned data matches the mock response data + expect(result).toEqual(mockResponse.data); }); }); 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..b2b79dc2e --- /dev/null +++ b/src/08-snapshot-testing/__snapshots__/index.test.ts.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generateLinkedList should generate linked list from values 2 1`] = ` +{ + "next": { + "next": { + "next": { + "next": { + "next": null, + "value": null, + }, + "value": 7, + }, + "value": 6, + }, + "value": 5, + }, + "value": 4, +} +`; diff --git a/src/08-snapshot-testing/index.test.ts b/src/08-snapshot-testing/index.test.ts index 67c345706..7029cfcb8 100644 --- a/src/08-snapshot-testing/index.test.ts +++ b/src/08-snapshot-testing/index.test.ts @@ -1,14 +1,31 @@ -// 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 elements = [1, 2, 3]; + + const expectedList = { + value: 1, + next: { + value: 2, + next: { + value: 3, + next: { + value: null, + next: null, + }, + }, + }, + }; + + const result = generateLinkedList(elements); + expect(result).toStrictEqual(expectedList); }); - // Check match by comparison with snapshot test('should generate linked list from values 2', () => { - // Write your test here + const elements = [4, 5, 6, 7]; + + const result = generateLinkedList(elements); + expect(result).toMatchSnapshot(); }); });