diff --git a/src/01-simple-tests/index.test.ts b/src/01-simple-tests/index.test.ts index fbbea85de..62a42cb56 100644 --- a/src/01-simple-tests/index.test.ts +++ b/src/01-simple-tests/index.test.ts @@ -1,32 +1,67 @@ // 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 + expect(simpleCalculator({ a: 2, b: 3, action: Action.Add })).toBe(5); + expect(simpleCalculator({ a: -2, b: -3, action: Action.Add })).toBe(-5); + expect(simpleCalculator({ a: -5, b: 3, action: Action.Add })).toBe(-2); }); test('should subtract two numbers', () => { - // Write your test here + expect(simpleCalculator({ a: 2, b: 3, action: Action.Subtract })).toBe(-1); + expect(simpleCalculator({ a: -2, b: -3, action: Action.Subtract })).toBe(1); + expect(simpleCalculator({ a: 5, b: 3, action: Action.Subtract })).toBe(2); }); test('should multiply two numbers', () => { - // Write your test here + expect(simpleCalculator({ a: 2, b: 3, action: Action.Multiply })).toBe(6); + expect(simpleCalculator({ a: -2, b: -3, action: Action.Multiply })).toBe(6); + expect(simpleCalculator({ a: -2, b: 3, action: Action.Multiply })).toBe(-6); + expect(simpleCalculator({ a: -2, b: 0, action: Action.Multiply })).toBe(-0); }); test('should divide two numbers', () => { - // Write your test here + expect(simpleCalculator({ a: 6, b: 2, action: Action.Divide })).toBe(3); + expect(simpleCalculator({ a: -6, b: 2, action: Action.Divide })).toBe(-3); + expect(simpleCalculator({ a: -6, b: -2, action: Action.Divide })).toBe(3); + expect(simpleCalculator({ a: -6, b: 0, action: Action.Divide })).toBe( + Number.NEGATIVE_INFINITY, + ); + expect(simpleCalculator({ a: 6, b: 4, action: Action.Divide })).toBe(1.5); }); test('should exponentiate two numbers', () => { - // Write your test here + expect(simpleCalculator({ a: 2, b: 2, action: Action.Exponentiate })).toBe( + 4, + ); + expect(simpleCalculator({ a: -2, b: 2, action: Action.Exponentiate })).toBe( + 4, + ); + expect(simpleCalculator({ a: -2, b: 3, action: Action.Exponentiate })).toBe( + -8, + ); + expect(simpleCalculator({ a: 6, b: 0, action: Action.Exponentiate })).toBe( + 1, + ); + expect(simpleCalculator({ a: -6, b: 0, action: Action.Exponentiate })).toBe( + 1, + ); + expect( + simpleCalculator({ a: 9, b: 0.5, action: Action.Exponentiate }), + ).toBe(3); + expect(simpleCalculator({ a: 2, b: -1, action: Action.Exponentiate })).toBe( + 0.5, + ); }); test('should return null for invalid action', () => { - // Write your test here + expect(simpleCalculator({ a: 6, b: 0, action: 'lg' })).toBe(null); + expect(simpleCalculator({ a: 6, b: 0, action: 5 })).toBe(null); }); test('should return null for invalid arguments', () => { - // Write your test here + expect(simpleCalculator({ a: '6', b: 2, action: Action.Add })).toBe(null); + expect(simpleCalculator({ a: 6, b: '2', action: Action.Add })).toBe(null); }); }); diff --git a/src/02-table-tests/index.test.ts b/src/02-table-tests/index.test.ts index 4f36e892e..8ad452ac0 100644 --- a/src/02-table-tests/index.test.ts +++ b/src/02-table-tests/index.test.ts @@ -1,17 +1,21 @@ -// 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: 3, b: 2, action: Action.Subtract, expected: 1 }, + { a: -3, b: -2, action: Action.Subtract, expected: -1 }, + { a: 3, b: 2, action: Action.Multiply, expected: 6 }, + { a: 3, b: 2, action: Action.Divide, expected: 1.5 }, + { a: 3, b: 2, action: Action.Exponentiate, expected: 9 }, +]; 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)( + 'test $action with $a, $b arguments', + ({ a, b, expected, action }) => { + expect(simpleCalculator({ a, b, action })).toBe(expected); + }, + ); }); diff --git a/src/03-error-handling-async/index.test.ts b/src/03-error-handling-async/index.test.ts index 6e106a6d6..5afda6e4c 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('resolved value')).resolves.toBe( + 'resolved value', + ); }); }); describe('throwError', () => { test('should throw error with provided message', () => { - // Write your test here + expect(() => throwError('test message')).toThrowError('test message'); }); 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); }); }); describe('rejectCustomError', () => { test('should reject custom error', async () => { - // Write your test here + expect(rejectCustomError).rejects.toThrowError(MyAwesomeError); }); }); diff --git a/src/04-test-class/index.test.ts b/src/04-test-class/index.test.ts index 937490d82..1809f3da1 100644 --- a/src/04-test-class/index.test.ts +++ b/src/04-test-class/index.test.ts @@ -1,44 +1,91 @@ -// Uncomment the code below and write your tests -// import { getBankAccount } from '.'; +import { + getBankAccount, + InsufficientFundsError, + SynchronizationFailedError, + TransferFailedError, +} from '.'; +import lodash from 'lodash'; describe('BankAccount', () => { + const initialBalance = 1000; + let bankAccount = getBankAccount(initialBalance); + let destinationAccount = getBankAccount(initialBalance); + + beforeAll(() => { + bankAccount = getBankAccount(initialBalance); + destinationAccount = getBankAccount(initialBalance); + }); + test('should create account with initial balance', () => { - // Write your test here + expect(bankAccount.getBalance()).toBe(initialBalance); }); test('should throw InsufficientFundsError error when withdrawing more than balance', () => { - // Write your test here + expect(() => bankAccount.withdraw(initialBalance + 1000)).toThrowError( + InsufficientFundsError, + ); }); test('should throw error when transferring more than balance', () => { - // Write your test here + expect(() => + bankAccount.transfer(initialBalance + 1000, destinationAccount), + ).toThrowError(InsufficientFundsError); }); test('should throw error when transferring to the same account', () => { - // Write your test here + expect(() => + bankAccount.transfer(initialBalance - 500, bankAccount), + ).toThrowError(TransferFailedError); }); test('should deposit money', () => { - // Write your test here + const deposit = 500; + const currentBalance = bankAccount.getBalance(); + expect(bankAccount.deposit(deposit).getBalance()).toBe( + currentBalance + deposit, + ); }); test('should withdraw money', () => { - // Write your test here + const withdraw = 200; + const currentBalance = bankAccount.getBalance(); + expect(bankAccount.withdraw(withdraw).getBalance()).toBe( + currentBalance - withdraw, + ); }); test('should transfer money', () => { - // Write your test here + const transfer = 200; + const currentBalance = bankAccount.getBalance(); + expect( + bankAccount.transfer(transfer, destinationAccount).getBalance(), + ).toBe(currentBalance - transfer); + + expect(destinationAccount.getBalance()).toBe(initialBalance + transfer); }); test('fetchBalance should return number in case if request did not failed', async () => { - // Write your tests here + const mockedValue = 400; + jest.spyOn(lodash, 'random').mockReturnValue(mockedValue); + + const result = await bankAccount.fetchBalance(); + expect(result).toBe(mockedValue); }); test('should set new balance if fetchBalance returned number', async () => { - // Write your tests here + const mockedValue = 400; + jest.spyOn(lodash, 'random').mockReturnValue(mockedValue); + + await bankAccount.synchronizeBalance(); + expect(bankAccount.getBalance()).toBe(mockedValue); }); test('should throw SynchronizationFailedError if fetchBalance returned null', async () => { - // Write your tests here + const mockedValue = 0; + jest.spyOn(lodash, 'random').mockReturnValue(mockedValue); + + expect(bankAccount.synchronizeBalance()).rejects.toThrowError( + SynchronizationFailedError, + ); }); }); diff --git a/src/05-partial-mocking/index.test.ts b/src/05-partial-mocking/index.test.ts index 9d8a66cbd..e0a749577 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 { + __esModule: true, + ...originalModule, + mockOne: jest.fn(), + mockTwo: jest.fn(), + mockThree: jest.fn(), + }; }); describe('partial mocking', () => { @@ -11,10 +18,17 @@ describe('partial mocking', () => { }); test('mockOne, mockTwo, mockThree should not log into console', () => { - // Write your test here + const log = jest.spyOn(console, 'log'); + mockOne(); + mockTwo(); + mockThree(); + + expect(log).not.toBeCalled(); }); test('unmockedFunction should log into console', () => { - // Write your test here + const log = jest.spyOn(console, 'log'); + unmockedFunction(); + expect(log).toHaveBeenCalled(); }); }); diff --git a/src/06-mocking-node-api/index.test.ts b/src/06-mocking-node-api/index.test.ts index 8dc3afd79..c6695bd29 100644 --- a/src/06-mocking-node-api/index.test.ts +++ b/src/06-mocking-node-api/index.test.ts @@ -1,5 +1,11 @@ // Uncomment the code below and write your tests -// import { readFileAsynchronously, doStuffByTimeout, doStuffByInterval } from '.'; +import { doStuffByInterval, doStuffByTimeout, readFileAsynchronously } from '.'; +import path from 'path'; +import fs from 'fs'; +import fsPromises from 'fs/promises'; + +jest.mock('fs'); +jest.mock('fs/promises'); describe('doStuffByTimeout', () => { beforeAll(() => { @@ -11,11 +17,18 @@ describe('doStuffByTimeout', () => { }); test('should set timeout with provided callback and timeout', () => { - // Write your test here + jest.spyOn(global, 'setTimeout'); + const cb = jest.fn(); + doStuffByTimeout(cb, 1000); + expect(setTimeout).toBeCalledWith(cb, 1000); }); test('should call callback only after timeout', () => { - // Write your test here + const cb = jest.fn(); + doStuffByTimeout(cb, 1000); + expect(cb).not.toBeCalled(); + jest.advanceTimersByTime(1000); + expect(cb).toBeCalled(); }); }); @@ -29,24 +42,44 @@ describe('doStuffByInterval', () => { }); test('should set interval with provided callback and timeout', () => { - // Write your test here + jest.spyOn(global, 'setInterval'); + const cb = jest.fn(); + doStuffByInterval(cb, 1000); + expect(setInterval).toBeCalledWith(cb, 1000); }); test('should call callback multiple times after multiple intervals', () => { - // Write your test here + const cb = jest.fn(); + doStuffByInterval(cb, 1000); + expect(cb).not.toBeCalled(); + jest.advanceTimersByTime(1000); + expect(cb).toBeCalledTimes(1); + jest.advanceTimersByTime(2000); + expect(cb).toBeCalledTimes(3); }); }); describe('readFileAsynchronously', () => { test('should call join with pathToFile', async () => { - // Write your test here + const join = jest.spyOn(path, 'join'); + const pathToFile = 'test.txt'; + readFileAsynchronously(pathToFile); + expect(join).toHaveBeenCalledWith(expect.anything(), pathToFile); }); test('should return null if file does not exist', async () => { - // Write your test here + jest.spyOn(fs, 'existsSync').mockReturnValue(false); + const pathToFile = 'fake-path.txt'; + + await expect(readFileAsynchronously(pathToFile)).resolves.toBeNull(); }); test('should return file content if file exists', async () => { - // Write your test here + const fileContent = 'File content'; + jest.spyOn(fs, 'existsSync').mockReturnValue(true); + jest.spyOn(fsPromises, 'readFile').mockResolvedValue(fileContent); + const pathToFile = 'fake-path.txt'; + + await expect(readFileAsynchronously(pathToFile)).resolves.toBe(fileContent); }); }); diff --git a/src/07-mocking-lib-api/index.test.ts b/src/07-mocking-lib-api/index.test.ts index e1dd001ef..290f07929 100644 --- a/src/07-mocking-lib-api/index.test.ts +++ b/src/07-mocking-lib-api/index.test.ts @@ -1,17 +1,52 @@ // 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'); +const mockAxios = axios as jest.Mocked; + +jest.mock('lodash', () => { + const originalModule = jest.requireActual('lodash'); + + //Mock the default export and named export 'foo' + return { + __esModule: true, + ...originalModule, + throttle: jest.fn((cb) => cb), + }; +}); describe('throttledGetDataFromApi', () => { + beforeEach(() => { + mockAxios.create.mockReturnThis(); + }); + test('should create instance with provided base url', async () => { - // Write your test here + const spy = jest.spyOn(mockAxios, 'create'); + const baseURL = 'https://jsonplaceholder.typicode.com'; + try { + await throttledGetDataFromApi('/relative-path'); // to catch axios.get error + } catch (e: any) { + console.log(e.message); + } + expect(spy).toBeCalledWith({ baseURL }); }); test('should perform request to correct provided url', async () => { - // Write your test here + const relativePath = '/relative-path'; + const spy = jest.spyOn(axios.create(), 'get'); + const mockResponse = { data: 'response' }; + mockAxios.get.mockResolvedValue(mockResponse); + await throttledGetDataFromApi(relativePath); + expect(spy).toHaveBeenCalledWith(relativePath); }); test('should return response data', async () => { - // Write your test here + const mockResponse = { data: 'response' }; + mockAxios.get.mockResolvedValue(mockResponse); + + await expect(throttledGetDataFromApi('/posts')).resolves.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..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..97c3a8322 100644 --- a/src/08-snapshot-testing/index.test.ts +++ b/src/08-snapshot-testing/index.test.ts @@ -1,14 +1,25 @@ -// 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 snapshot = { + next: { + next: { + next: null, + value: null, + }, + value: 2, + }, + value: 1, + }; + const list = generateLinkedList([1, 2]); + expect(list).toStrictEqual(snapshot); }); // Check match by comparison with snapshot test('should generate linked list from values 2', () => { - // Write your test here + const list = generateLinkedList([1, 2, 3]); + expect(list).toMatchSnapshot(); }); });