diff --git a/hotel-management/package.json b/hotel-management/package.json index 7634a5f..2e05cd6 100644 --- a/hotel-management/package.json +++ b/hotel-management/package.json @@ -8,7 +8,8 @@ "build": "tsc && vite build", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", - "test": "jest --coverage" + "test-ci": "jest --coverage", + "test": "jest --runTestsByPath" }, "coverageReporters": [ "html" diff --git a/hotel-management/src/App.test.tsx b/hotel-management/src/App.test.tsx new file mode 100644 index 0000000..ec995a5 --- /dev/null +++ b/hotel-management/src/App.test.tsx @@ -0,0 +1,69 @@ +import { render, act, RenderResult } from '@testing-library/react'; +import * as userServices from '@service/userServices'; +import * as roomServices from '@service/roomServices'; +import App from './App'; + +jest.mock('@service/userServices'); +jest.mock('@service/roomServices'); + +describe('App', () => { + let wrapper: RenderResult | null = null; + + beforeEach(async () => { + await act(async () => { + wrapper = render(); + }); + }); + + test('should render correctly', () => { + expect(wrapper).toMatchSnapshot(); + }); + + test('Should init room, user data', async () => { + const mockGetUserNotBooked = jest.spyOn(userServices, 'getAllUsers'); + const mockGetRoomAvailable = jest.spyOn(roomServices, 'getAllRooms'); + + mockGetUserNotBooked.mockResolvedValue({ + data: [ + { + id: 1, + name: 'Nezumi', + phone: '0324432321', + isBooked: true, + isDelete: true, + }, + { + id: 1, + name: 'Loi Phan', + phone: '0324432123', + isBooked: true, + isDelete: true, + }, + ], + count: 2, + }); + + mockGetRoomAvailable.mockResolvedValue({ + data: [ + { + id: 1, + name: 'Room 1', + price: 230, + status: true, + isDelete: true, + }, + { + id: 2, + name: 'Room 2', + price: 242, + status: true, + isDelete: true + }, + ], + count: 2 + }); + + expect(mockGetUserNotBooked).toHaveBeenCalled(); + expect(mockGetRoomAvailable).toHaveBeenCalled(); + }); +}); diff --git a/hotel-management/src/__snapshots__/App.test.tsx.snap b/hotel-management/src/__snapshots__/App.test.tsx.snap new file mode 100644 index 0000000..5cbca46 --- /dev/null +++ b/hotel-management/src/__snapshots__/App.test.tsx.snap @@ -0,0 +1,84 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`App should render correctly 1`] = ` +{ + "asFragment": [Function], + "baseElement": +
+
+
+
+
+
+ , + "container":
+
+
+
+
+
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/hotel-management/src/components/AppLayout/AppLayout.test.tsx b/hotel-management/src/components/AppLayout/AppLayout.test.tsx index 471cd48..6717ed4 100644 --- a/hotel-management/src/components/AppLayout/AppLayout.test.tsx +++ b/hotel-management/src/components/AppLayout/AppLayout.test.tsx @@ -3,12 +3,17 @@ import { BrowserRouter } from 'react-router-dom'; // Components import AppLayout from '.'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; describe('AppLayout', () => { + const queryClient = new QueryClient(); + const wrapper = renderer.create( - - - + + + + + ); test('Should render correctly', () => { diff --git a/hotel-management/src/components/AppLayout/__snapshots__/AppLayout.test.tsx.snap b/hotel-management/src/components/AppLayout/__snapshots__/AppLayout.test.tsx.snap index 6d48dfc..dc7ccf8 100644 --- a/hotel-management/src/components/AppLayout/__snapshots__/AppLayout.test.tsx.snap +++ b/hotel-management/src/components/AppLayout/__snapshots__/AppLayout.test.tsx.snap @@ -9,7 +9,6 @@ exports[`AppLayout Should render correctly 1`] = ` >

Hi, - Admin !

+
+
+ , + "container":
+
- Delete - - -
-
+

+ Hello World! +

+
+ + +
+
+ , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} `; diff --git a/hotel-management/src/components/Form/__snapshots__/Form.test.tsx.snap b/hotel-management/src/components/Form/__snapshots__/Form.test.tsx.snap index a4ab15f..b3c34ce 100644 --- a/hotel-management/src/components/Form/__snapshots__/Form.test.tsx.snap +++ b/hotel-management/src/components/Form/__snapshots__/Form.test.tsx.snap @@ -2,56 +2,58 @@ exports[`Form Should render correctly 1`] = `

This is error message

This is error message

+
+ + , + "container":
+
- - - -
+ +
+ , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} `; diff --git a/hotel-management/src/components/Modal/__snapshots__/Modal.test.tsx.snap b/hotel-management/src/components/Modal/__snapshots__/Modal.test.tsx.snap index ca5c47b..3df1188 100644 --- a/hotel-management/src/components/Modal/__snapshots__/Modal.test.tsx.snap +++ b/hotel-management/src/components/Modal/__snapshots__/Modal.test.tsx.snap @@ -2,7 +2,7 @@ exports[`Modal Should render correctly 1`] = `
- - -`; diff --git a/hotel-management/src/components/OrderBy/__snapshots__/OrderBy.test.tsx.snap b/hotel-management/src/components/OrderBy/__snapshots__/OrderBy.test.tsx.snap new file mode 100644 index 0000000..ebb83f0 --- /dev/null +++ b/hotel-management/src/components/OrderBy/__snapshots__/OrderBy.test.tsx.snap @@ -0,0 +1,94 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Order Should render correctly 1`] = ` +{ + "asFragment": [Function], + "baseElement": +
+
+ + +
+
+ , + "container":
+
+ + +
+
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/hotel-management/src/components/Search/Search.test.tsx b/hotel-management/src/components/Search/Search.test.tsx index 5068e51..fd3fb05 100644 --- a/hotel-management/src/components/Search/Search.test.tsx +++ b/hotel-management/src/components/Search/Search.test.tsx @@ -1,18 +1,67 @@ -import renderer from 'react-test-renderer'; import { BrowserRouter } from 'react-router-dom'; +import { useState } from 'react'; // Components import Search from '.'; +import { + RenderResult, + fireEvent, + render, + act, +} from '@testing-library/react'; + +let mockSearchParam = ''; + +jest.useFakeTimers(); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useSearchParams: () => { + const [params, setParams] = useState(new URLSearchParams(mockSearchParam)); + return [ + params, + (newParams: string) => { + mockSearchParam = newParams; + setParams(new URLSearchParams(newParams)); + }, + ]; + }, +})); describe('Search', () => { - const placeHolder = 'Search placeholder...'; - const wrapper = renderer.create( - - - - ); + // const placeHolder = 'Search placeholder...'; + // let wrapper: RenderResult | null = null; - test('Should render correctly', () => { - expect(wrapper).toMatchSnapshot(); + // beforeEach(() => { + // wrapper = render( + // + // + // + // ); + // }); + + // test('Should render correctly', () => { + // expect(wrapper).toMatchSnapshot(); + // }); + + test('Should add query to url after 1 second', async () => { + let wrapper: RenderResult | null = null; + act(() => { + wrapper = render( + + + + ); + }); + + const searchField = await wrapper!.findByPlaceholderText( + 'Search placeholder...' + ); + + act(() => { + fireEvent.change(searchField, { target: { value: 'abc' } }); + }); + + // jest.advanceTimersByTime(1000); }); }); + \ No newline at end of file diff --git a/hotel-management/src/components/Search/__snapshots__/Search.test.tsx.snap b/hotel-management/src/components/Search/__snapshots__/Search.test.tsx.snap deleted file mode 100644 index a0f238e..0000000 --- a/hotel-management/src/components/Search/__snapshots__/Search.test.tsx.snap +++ /dev/null @@ -1,9 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Search Should render correctly 1`] = ` - -`; diff --git a/hotel-management/src/components/Select/__snapshots__/Select.test.tsx.snap b/hotel-management/src/components/Select/__snapshots__/Select.test.tsx.snap index bf1a8d0..0ab245e 100644 --- a/hotel-management/src/components/Select/__snapshots__/Select.test.tsx.snap +++ b/hotel-management/src/components/Select/__snapshots__/Select.test.tsx.snap @@ -3,16 +3,19 @@ exports[`Select Should render correctly 1`] = ` - - - +{ + "asFragment": [Function], + "baseElement": +
+ +
+ , + "container":
+ +
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} `; diff --git a/hotel-management/src/constants/commons.ts b/hotel-management/src/constants/commons.ts index e790987..9d91cc7 100644 --- a/hotel-management/src/constants/commons.ts +++ b/hotel-management/src/constants/commons.ts @@ -53,7 +53,7 @@ const FORM = { }; const REGEX = { - PHONE: /(84|0[3|5|7|8|9])+([0-9]{8})\b/g, + PHONE: /(0[3|5|7|8|9])+([0-9]{8})\b/g, NAME: /^[a-zA-Z]{2,}(?: [a-zA-Z]+){0,2}$/gm, NUMBER: /^[0-9]*$/, PASSWORD: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$@!%&*?])[A-Za-z\d#$@!%&*?]{8,16}$/ diff --git a/hotel-management/src/contexts/__tests__/userRoomAvailableContext.test.tsx b/hotel-management/src/contexts/__tests__/userRoomAvailableContext.test.tsx new file mode 100644 index 0000000..672476c --- /dev/null +++ b/hotel-management/src/contexts/__tests__/userRoomAvailableContext.test.tsx @@ -0,0 +1,129 @@ +import { reducer } from '@context/UserRoomAvailableContext'; +import { IDataState } from '@type/common'; + +jest.mock('@service/userServices'); +jest.mock('@service/roomServices'); + +describe('userRoomAvailableContext', () => { + let initialState: { + roomsAvailable: IDataState[]; + usersAvailable: IDataState[]; + }; + + const sampleRooms = [ + { + id: 2, + name: 'Room 2', + }, + { + id: 3, + name: 'Room 3', + }, + ]; + + const sampleUsers = [ + { + id: 2, + name: 'Loi Phan', + }, + { + id: 3, + name: 'Van A', + }, + ]; + + beforeEach(() => { + initialState = { + roomsAvailable: [ + { + id: 1, + name: 'Room 1', + }, + ], + usersAvailable: [ + { + id: 1, + name: 'Nezumi', + }, + ], + }; + }); + + test('Should init user correctly', async () => { + const state = reducer(initialState, { + type: 'initUser', + payload: sampleUsers, + }); + + expect(state.usersAvailable.length).toEqual(2); + }); + + test('Should add user correctly', async () => { + const state = reducer(initialState, { + type: 'addUser', + payload: [{ id: 2, name: 'Test Name' }], + }); + + expect(state.usersAvailable.length).toEqual(2); + }); + + test('Should remove user correctly', async () => { + const state = reducer(initialState, { + type: 'removeUser', + payload: [{ id: 1 }], + }); + + expect(state.usersAvailable.length).toEqual(0); + }); + + test('Should update user correctly', async () => { + const state = reducer(initialState, { + type: 'updateUserName', + payload: [{ id: 1, name: 'Update name' }], + }); + + expect(state.usersAvailable[0]).toEqual({ + id: 1, + name: 'Update name' + }); + }); + + test('Should init room correctly', async () => { + const state = reducer(initialState, { + type: 'initRoom', + payload: sampleRooms, + }); + + expect(state.roomsAvailable.length).toEqual(2); + }); + + test('Should add room correctly', async () => { + const state = reducer(initialState, { + type: 'addRoom', + payload: [{ id: 2, name: 'Test Room' }], + }); + + expect(state.roomsAvailable.length).toEqual(2); + }); + + test('Should remove room correctly', async () => { + const state = reducer(initialState, { + type: 'removeRoom', + payload: [{ id: 1 }], + }); + + expect(state.roomsAvailable.length).toEqual(0); + }); + + test('Should update room correctly', async () => { + const state = reducer(initialState, { + type: 'updateRoomName', + payload: [{ id: 1, name: 'Update name' }], + }); + + expect(state.roomsAvailable[0]).toEqual({ + id: 1, + name: 'Update name' + }); + }); +}); diff --git a/hotel-management/src/helpers/__tests__/helpers.test.ts b/hotel-management/src/helpers/__tests__/helpers.test.ts new file mode 100644 index 0000000..8e71b7f --- /dev/null +++ b/hotel-management/src/helpers/__tests__/helpers.test.ts @@ -0,0 +1,10 @@ +// Helpers +import { formatCurrency } from '@helper/helper'; + +describe('formatCurrency', () => { + test('Should format correctly', () => { + const result = formatCurrency(5000); + + expect(result).toEqual('$5,000.00'); + }); +}); diff --git a/hotel-management/src/helpers/__tests__/validators.test.ts b/hotel-management/src/helpers/__tests__/validators.test.ts new file mode 100644 index 0000000..61d6b94 --- /dev/null +++ b/hotel-management/src/helpers/__tests__/validators.test.ts @@ -0,0 +1,90 @@ +// Constants +import { REGEX } from '@constant/commons'; + +// Helpers +import { + isValidDiscount, + isValidRegex, + isValidString, +} from '@helper/validators'; + +describe('isValidPhone', () => { + const isValidPhone = (phone: string) => + isValidRegex(new RegExp(REGEX.PHONE), phone); + + test('Should is valid phone', () => { + const case_1 = isValidPhone('0321123212'); + const case_2 = isValidPhone('0533245422'); + const case_3 = isValidPhone('0723342321'); + const case_4 = isValidPhone('0823654321'); + const case_5 = isValidPhone('0943212343'); + + expect(case_1).toBeTruthy(); + expect(case_2).toBeTruthy(); + expect(case_3).toBeTruthy(); + expect(case_4).toBeTruthy(); + expect(case_5).toBeTruthy(); + }); + + test('Should is not valid phone', () => { + const case_1 = isValidPhone('0327212321Abc'); + const case_2 = isValidPhone('0021432123'); + const case_3 = isValidPhone('@325542321'); + const case_4 = isValidPhone('A321443232'); + const case_5 = isValidPhone('ValidPhone'); + const case_6 = isValidPhone('000'); + + expect(case_1).toBeFalsy(); + expect(case_2).toBeFalsy(); + expect(case_3).toBeFalsy(); + expect(case_4).toBeFalsy(); + expect(case_5).toBeFalsy(); + expect(case_6).toBeFalsy(); + }); +}); + +describe('isValidDiscount', () => { + test('Should is valid discount', () => { + const case_1 = isValidDiscount(99.99); + const case_2 = isValidDiscount(50); + const case_3 = isValidDiscount(0); + const case_4 = isValidDiscount(100); + + expect(case_1).toBeTruthy(); + expect(case_2).toBeTruthy(); + expect(case_3).toBeTruthy(); + expect(case_4).toBeTruthy(); + }); + + test('Should is not valid discount', () => { + const case_1 = isValidDiscount(-1); + const case_2 = isValidDiscount(-0.99); + const case_3 = isValidDiscount(101); + + expect(case_1).toBeFalsy(); + expect(case_2).toBeFalsy(); + expect(case_3).toBeFalsy(); + }); +}); + +describe('Should is valid string', () => { + test('Is valid string', () => { + const case_1 = isValidString('Phan Huu Loi'); + const case_2 = isValidString('Nezumi'); + + expect(case_1).toBeTruthy(); + expect(case_2).toBeTruthy(); + }); + + test('Should is not valid string', () => { + const case_1 = isValidString('Le'); + const case_2 = isValidString('1tét'); + const case_3 = isValidString('@!'); + const case_4 = isValidString(' '); + + expect(case_1).toBeFalsy(); + expect(case_2).toBeFalsy(); + expect(case_3).toBeFalsy(); + expect(case_4).toBeFalsy(); + }); +}); diff --git a/hotel-management/src/hooks/__tests__/rooms.test.tsx b/hotel-management/src/hooks/__tests__/rooms.test.tsx new file mode 100644 index 0000000..8587cef --- /dev/null +++ b/hotel-management/src/hooks/__tests__/rooms.test.tsx @@ -0,0 +1,132 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { act, renderHook, waitFor } from '@testing-library/react'; +import { MemoryRouter } from 'react-router-dom'; +import { ReactNode } from 'react'; + +// Hooks +import { useRooms } from '@hook/rooms/useRooms'; +import { useCreateRoom } from '@hook/rooms/useCreateRoom'; +import { useUpdateRoom } from '@hook/rooms/useUpdateRoom'; +import { useSetIsDeleteRoom } from '@hook/rooms/useSetIsDeleteRoom'; + +// Types +import { IRoom } from '@type/room'; + +const mockUseRooms = jest.fn(useRooms); +const mockUseCreateRoom = jest.fn(useCreateRoom); +const mockUseUpdateRoom = jest.fn(useUpdateRoom); +const mockUseDeleteRoom = jest.fn(useSetIsDeleteRoom); +interface IWrapper { + children: ReactNode; +} + +const sampleData: IRoom = { + id: 999, + name: 'Room name test', + price: 9999, + status: true, + isDelete: true, +}; +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + }, + }, +}); +const wrapper = ({ children }: IWrapper) => { + return ( + + {children} + + ); +}; + +describe('Room hooks', () => { + test('Should fetch data correctly', async () => { + mockUseRooms.mockImplementation(() => ({ + rooms: [ + { + id: 1, + name: 'Nezumi', + price: 2500, + status: true, + isDelete: true, + }, + { + id: 2, + name: 'Loi Phan', + price: 8500, + status: false, + isDelete: true, + }, + ], + isLoading: false, + count: 2 + })); + const { result } = renderHook(() => mockUseRooms(), { wrapper }); + + await waitFor(() => + expect(result.current.rooms?.length).toBeGreaterThan(0) + ); + }); + + test('Should create room correctly', async () => { + mockUseCreateRoom.mockImplementation(() => ({ + createRoom: () => { + sampleData; + }, + isCreating: false, + isSuccess: true, + })); + const { result } = renderHook(() => mockUseCreateRoom(), { wrapper }); + + act(() => { + result.current.createRoom(sampleData); + }); + + await waitFor(() => result.current.isSuccess); + + expect(result.current.isSuccess).toBeTruthy(); + }); + + test('Should edit room correctly', async () => { + mockUseUpdateRoom.mockImplementation(() => ({ + updateRoom: () => { + sampleData; + }, + isUpdating: false, + isSuccess: true, + })); + const { result } = renderHook(() => mockUseUpdateRoom(), { wrapper }); + + act(() => { + const testMethod = async () => { + result.current.updateRoom(sampleData); + await waitFor(() => expect(result.current.isSuccess).toBeTruthy()); + }; + + testMethod(); + }); + }); + + test('Should delete room correctly', async () => { + mockUseDeleteRoom.mockImplementation(() => ({ + setIsDeleteRoom: () => { + sampleData + }, + isDeleting: false, + isSuccess: true, + })); + const { result } = renderHook(() => mockUseDeleteRoom(), { wrapper }); + + act(() => { + const testMethod = async () => { + result.current.setIsDeleteRoom(sampleData.id); + await waitFor(() => expect(result.current.isSuccess).toBeTruthy()); + }; + + testMethod(); + }); + }); +}); diff --git a/hotel-management/src/hooks/__tests__/useDebounce.test.tsx b/hotel-management/src/hooks/__tests__/useDebounce.test.tsx new file mode 100644 index 0000000..4eca0c2 --- /dev/null +++ b/hotel-management/src/hooks/__tests__/useDebounce.test.tsx @@ -0,0 +1,47 @@ +import { fireEvent, render } from '@testing-library/react'; +import { useState } from 'react'; +import { act } from 'react-test-renderer'; + +// Hooks +import { useDebounce } from '@hook/useDebounce'; + +jest.useFakeTimers(); + +const TestComponent = ({ initialValue = 0 }: { initialValue?: number }) => { + const [value, setValue] = useState(initialValue); + const debouncedValue = useDebounce(value, 1000); + + return ( +
+ + {debouncedValue} + {value} +
+ ); +}; + +describe('useDebouncedValue', function () { + test('Debounce value should not change before 1 second', () => { + const { getByTestId, getByText } = render(); + const incrementButton = getByText('Increment'); + const debouncedValue = getByTestId('debouncedValue'); + const value = getByTestId('value'); + + const clickAndWaitTime = (passedTime: number) => { + act(() => { + fireEvent.click(incrementButton); + jest.advanceTimersByTime(passedTime); + }); + }; + + clickAndWaitTime(100); + + expect(debouncedValue.textContent).toBe('0'); + expect(value.textContent).toBe('1'); + + clickAndWaitTime(1000); + + expect(debouncedValue.textContent).toBe('1'); + expect(value.textContent).toBe('2'); + }); +}); diff --git a/hotel-management/src/hooks/__tests__/useOutsideClick.test.tsx b/hotel-management/src/hooks/__tests__/useOutsideClick.test.tsx new file mode 100644 index 0000000..0178a71 --- /dev/null +++ b/hotel-management/src/hooks/__tests__/useOutsideClick.test.tsx @@ -0,0 +1,33 @@ +import { fireEvent, render, renderHook, screen } from '@testing-library/react'; + +// Hooks +import { useOutsideClick } from '@hook/useOutsideClick'; + +describe('useOutsideClick', () => { + test('Call handler when click outside element', () => { + // Arrange + const handler = jest.fn(); + const ref = renderHook(() => useOutsideClick(handler)) + .result.current; + render(
); + + fireEvent.click(document); + + // Assert + expect(handler).toHaveBeenCalledTimes(1); + }); + + test('Not call handler when click outside element', () => { + // Arrange + const handler = jest.fn(); + const ref = renderHook(() => useOutsideClick(handler)) + .result.current; + render(
); + + // Act + fireEvent.click(screen.getByTestId('test-element')); + + // Assert + expect(handler).not.toHaveBeenCalled(); + }); +}); diff --git a/hotel-management/src/hooks/__tests__/users.test.tsx b/hotel-management/src/hooks/__tests__/users.test.tsx new file mode 100644 index 0000000..a6fe479 --- /dev/null +++ b/hotel-management/src/hooks/__tests__/users.test.tsx @@ -0,0 +1,111 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { renderHook, waitFor } from '@testing-library/react'; +import { ReactNode } from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { act } from 'react-test-renderer'; + +// Hooks +import { useCreateUser } from '@hook/users/useCreateUser'; +import { useUpdateUser } from '@hook/users/useUpdateUser'; +import { useUsers } from '@hook/users/useUsers'; + +// Types +import { IUser } from '@type/user'; + +const mockUseUsers = jest.fn(useUsers); +const mockUseCreateUser = jest.fn(useCreateUser); +const mockUseUpdateUser = jest.fn(useUpdateUser); + +interface IWrapper { + children: ReactNode; +} + +const sampleData: IUser = { + id: 999, + name: 'User name test', + phone: '123456789', + isBooked: true, + isDelete: true, +}; +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + }, + }, +}); +const wrapper = ({ children }: IWrapper) => { + return ( + + {children} + + ); +}; + +describe('Users hook', () => { + test('Should fetch user data correctly', async () => { + mockUseUsers.mockImplementation(() => ({ + users: [ + { + id: 1, + name: 'Nezumi', + phone: '0123456678', + isBooked: true, + isDelete: true, + }, + { + id: 2, + name: 'Loi Phan', + phone: '0123456678', + isBooked: false, + isDelete: true, + }, + ], + isLoading: false, + count: 2, + })); + const { result } = renderHook(() => mockUseUsers(), { wrapper }); + + await waitFor(() => expect(result.current.users?.length).toEqual(2)); + }); + + test('Should create user correctly', async () => { + mockUseCreateUser.mockImplementation(() => ({ + createUser: () => { + sampleData; + }, + isCreating: false, + isSuccess: true, + })); + const { result } = renderHook(() => mockUseCreateUser(), { wrapper }); + + act(() => { + const testMethod = async () => { + result.current.createUser(sampleData); + await waitFor(() => expect(result.current.isSuccess).toBeTruthy()); + }; + + testMethod(); + }); + }); + + test('Should update user correctly', async () => { + mockUseUpdateUser.mockImplementation(() => ({ + updateUser: () => { + sampleData; + }, + isUpdating: false, + isSuccess: true, + })); + const { result } = renderHook(() => mockUseUpdateUser(), { wrapper }); + + act(() => { + const testMethod = async () => { + result.current.updateUser(sampleData); + await waitFor(() => expect(result.current.isSuccess).toBeTruthy()); + }; + + testMethod(); + }); + }); +}); diff --git a/hotel-management/src/pages/Room/__tests__/RoomForm.test.tsx b/hotel-management/src/pages/Room/__tests__/RoomForm.test.tsx deleted file mode 100644 index c63a486..0000000 --- a/hotel-management/src/pages/Room/__tests__/RoomForm.test.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { BrowserRouter } from 'react-router-dom'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import renderer from 'react-test-renderer'; - -// Components -import RoomForm from '../RoomForm'; - -describe('RoomForm', () => { - const queryClient = new QueryClient(); - - const wrapper = renderer.create( - - - - - - ); - - test('Should render correctly', () => { - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/hotel-management/src/pages/Room/__tests__/RoomRow.test.tsx b/hotel-management/src/pages/Room/__tests__/RoomRow.test.tsx deleted file mode 100644 index 4f179f6..0000000 --- a/hotel-management/src/pages/Room/__tests__/RoomRow.test.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import renderer from 'react-test-renderer'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; - -// Types -import { IRoom } from '@type/room'; - -// Components -import RoomRow from '../RoomRow'; - -describe('RoomRow', () => { - const tempRoom: IRoom = { - id: 1, - name: 'Temp Room', - price: 250, - status: true, - isDelete: true, - }; - const queryClient = new QueryClient(); - - const wrapper = renderer.create( - - - - ); - - test('Should render correctly', () => { - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/hotel-management/src/pages/Room/__tests__/RoomTable.test.tsx b/hotel-management/src/pages/Room/__tests__/RoomTable.test.tsx deleted file mode 100644 index 13a76c1..0000000 --- a/hotel-management/src/pages/Room/__tests__/RoomTable.test.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import renderer from 'react-test-renderer'; -import { BrowserRouter } from 'react-router-dom'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; - -// Components -import RoomTable from '../RoomTable'; - -describe('RoomTable', () => { - const queryClient = new QueryClient(); - - const wrapper = renderer.create( - - - - - - ); - - test('Should render correctly', () => { - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/hotel-management/src/pages/Room/__tests__/__snapshots__/RoomForm.test.tsx.snap b/hotel-management/src/pages/Room/__tests__/__snapshots__/RoomForm.test.tsx.snap deleted file mode 100644 index 9cc4c07..0000000 --- a/hotel-management/src/pages/Room/__tests__/__snapshots__/RoomForm.test.tsx.snap +++ /dev/null @@ -1,67 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RoomForm Should render correctly 1`] = ` - -
- -
- -
-
-
- -
- -
-
-
- - -
- -`; diff --git a/hotel-management/src/pages/Room/__tests__/__snapshots__/RoomRow.test.tsx.snap b/hotel-management/src/pages/Room/__tests__/__snapshots__/RoomRow.test.tsx.snap deleted file mode 100644 index 228a2f7..0000000 --- a/hotel-management/src/pages/Room/__tests__/__snapshots__/RoomRow.test.tsx.snap +++ /dev/null @@ -1,53 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RoomRow Should render correctly 1`] = ` -
-
- 1 -
-
- Temp Room -
-
- $250.00 -
-
- Unavailable -
-
-
- -
-
-
-`; diff --git a/hotel-management/src/pages/Room/__tests__/__snapshots__/RoomTable.test.tsx.snap b/hotel-management/src/pages/Room/__tests__/__snapshots__/RoomTable.test.tsx.snap deleted file mode 100644 index 86243e4..0000000 --- a/hotel-management/src/pages/Room/__tests__/__snapshots__/RoomTable.test.tsx.snap +++ /dev/null @@ -1,63 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RoomTable Should render correctly 1`] = ` -
-
-
- - -
- - -
-
-
-`; diff --git a/hotel-management/src/pages/Room/__tests__/__snapshots__/index.test.tsx.snap b/hotel-management/src/pages/Room/__tests__/__snapshots__/index.test.tsx.snap deleted file mode 100644 index 6fb4c8d..0000000 --- a/hotel-management/src/pages/Room/__tests__/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,84 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Room Should render correctly 1`] = ` -
-
-

- List Room -

- -
-
-
-
- - -
- - -
-
-
-
-`; diff --git a/hotel-management/src/pages/Room/__tests__/index.test.tsx b/hotel-management/src/pages/Room/__tests__/index.test.tsx deleted file mode 100644 index 64fba84..0000000 --- a/hotel-management/src/pages/Room/__tests__/index.test.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import Room from '..'; -import { BrowserRouter } from 'react-router-dom'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; - -// Components -import renderer from 'react-test-renderer'; - -describe('Room', () => { - const queryClient = new QueryClient(); - - const wrapper = renderer.create( - - - - - - ); - - test('Should render correctly', () => { - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/hotel-management/src/pages/User/__tests__/UserForm.test.tsx b/hotel-management/src/pages/User/__tests__/UserForm.test.tsx index 0313107..fa30246 100644 --- a/hotel-management/src/pages/User/__tests__/UserForm.test.tsx +++ b/hotel-management/src/pages/User/__tests__/UserForm.test.tsx @@ -1,22 +1,73 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { BrowserRouter } from 'react-router-dom'; -import renderer from 'react-test-renderer'; - // Components import UserForm from '../UserForm'; +import { + RenderResult, + fireEvent, + render, + waitFor, +} from '@testing-library/react'; + +const createUser = jest.fn(); + +jest.mock('@hook/users/useCreateUser.ts', () => ({ + ...jest.requireActual('@hook/users/useCreateUser.ts'), + useCreateUser: jest.fn(() => ({ + isCreating: false, + createUser, + })), +})); + +jest.mock('@hook/users/useUpdateUser', () => ({ + ...jest.requireActual('@hook/users/useUpdateUser'), + useUpdateUser: () => ({ + isUpdating: false, + updateUser: jest.fn(), + }), +})); describe('UserForm', () => { const queryClient = new QueryClient(); - const wrapper = renderer.create( - - - - - - ); + let wrapper: RenderResult | null = null; + + beforeEach(() => { + wrapper = render( + + + + + + ); + }); test('Should render correctly', () => { expect(wrapper).toMatchSnapshot(); }); + + test('Should submit correctly', async () => { + const nameField = wrapper!.container.querySelector('#name'); + const phoneField = wrapper!.container.querySelector('#phone'); + const submitBtn = wrapper!.getByText('Add').closest('button'); + let result: { + name: string; + phone: string; + }; + + createUser.mockImplementationOnce((newUser, { onSuccess }) => { + result = newUser; + onSuccess(); + }); + + fireEvent.input(nameField!, { target: { value: 'Nezumi' } }); + fireEvent.input(phoneField!, { target: { value: '0327764321' } }); + + fireEvent.submit(submitBtn!); + + await waitFor(() => { + expect(createUser).toHaveBeenCalled(); + expect(result).toEqual({ name: 'Nezumi', phone: '0327764321' }); + }); + }); }); diff --git a/hotel-management/src/pages/User/__tests__/__snapshots__/UserForm.test.tsx.snap b/hotel-management/src/pages/User/__tests__/__snapshots__/UserForm.test.tsx.snap index edcd103..1b92e15 100644 --- a/hotel-management/src/pages/User/__tests__/__snapshots__/UserForm.test.tsx.snap +++ b/hotel-management/src/pages/User/__tests__/__snapshots__/UserForm.test.tsx.snap @@ -1,67 +1,184 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`UserForm Should render correctly 1`] = ` -
-
- +{ + "asFragment": [Function], + "baseElement":
- + +
+ +
+ +
+
+
+ +
+ +
+
+
+ + +
+
-
-
-
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} `; diff --git a/hotel-management/src/pages/User/__tests__/__snapshots__/UserRow.test.tsx.snap b/hotel-management/src/pages/User/__tests__/__snapshots__/UserRow.test.tsx.snap index c6b759a..357c1d0 100644 --- a/hotel-management/src/pages/User/__tests__/__snapshots__/UserRow.test.tsx.snap +++ b/hotel-management/src/pages/User/__tests__/__snapshots__/UserRow.test.tsx.snap @@ -18,11 +18,11 @@ exports[`UserRow Should render correctly 1`] = `
`; diff --git a/hotel-management/src/pages/User/__tests__/__snapshots__/index.test.tsx.snap b/hotel-management/src/pages/User/__tests__/__snapshots__/index.test.tsx.snap index 1f7ea38..99a82fa 100644 --- a/hotel-management/src/pages/User/__tests__/__snapshots__/index.test.tsx.snap +++ b/hotel-management/src/pages/User/__tests__/__snapshots__/index.test.tsx.snap @@ -2,19 +2,19 @@ exports[`User Should render correctly 1`] = `

List User

diff --git a/hotel-management/src/services/__tests__/roomService.test.ts b/hotel-management/src/services/__tests__/roomService.test.ts new file mode 100644 index 0000000..56202ca --- /dev/null +++ b/hotel-management/src/services/__tests__/roomService.test.ts @@ -0,0 +1,86 @@ +import { waitFor } from '@testing-library/react'; + +// Services +import { + createRoom, + setIsDeleteRoom, + getAllRooms, + updateRoom, +} from '@service/roomServices'; + +// Types +import { IRoom } from '@type/room'; + +jest.mock('@service/supabaseService'); +const mockGetAllRooms = jest.fn(getAllRooms); +const mockUpdateRoom = jest.fn(updateRoom); +const mockCreateRoom = jest.fn(createRoom); +const mockIsDeleteRoom = jest.fn(setIsDeleteRoom); + +const sampleData: IRoom = { + id: 999, + name: 'Room name test', + price: 9999, + status: true, + isDelete: true, +}; + +describe('Rooms service', () => { + test('Should fetch room correctly', async () => { + mockGetAllRooms.mockResolvedValue({ + data: [ + { + id: 1, + name: 'Nezumi', + price: 2500, + status: true, + isDelete: true, + }, + { + id: 2, + name: 'Loi Phan', + price: 8500, + status: false, + isDelete: true, + }, + ], + count: 2, + }); + const result = await mockGetAllRooms({ + sortBy: 'name', + orderBy: 'asc', + roomSearch: '', + page: 1, + }); + + await waitFor(() => expect(result.data.length).toEqual(2)); + }); + + test('Should create room correctly', async () => { + mockCreateRoom.mockResolvedValue(sampleData); + + const result = await mockCreateRoom(sampleData); + + await waitFor(() => expect(result).toBeTruthy()); + }); + + test('Should update room correctly', async () => { + mockUpdateRoom.mockResolvedValue({ + id: 1, + name: 'Nezumi', + price: 2500, + status: true, + isDelete: true, + }); + const result = await mockUpdateRoom(sampleData); + + await waitFor(() => expect(result).toBeTruthy()); + }); + + test('Should delete room correctly', async () => { + mockIsDeleteRoom.mockResolvedValue(sampleData); + const result = await mockIsDeleteRoom(1); + + await waitFor(() => expect(result).toBeTruthy()); + }); +}); diff --git a/hotel-management/src/services/__tests__/userService.test.ts b/hotel-management/src/services/__tests__/userService.test.ts new file mode 100644 index 0000000..af30ea7 --- /dev/null +++ b/hotel-management/src/services/__tests__/userService.test.ts @@ -0,0 +1,64 @@ +import { waitFor } from '@testing-library/react'; + +// Services +import { createUser, getAllUsers, updateUser } from '@service/userServices'; + +// Types +import { IUser } from '@type/user'; + +const mockGetAllUsers = jest.fn(getAllUsers); +const mockCreateUser = jest.fn(createUser); +const mockUpdateUser = jest.fn(updateUser); + +const sampleData: IUser = { + id: 999, + name: 'User name test', + phone: '123456789', + isBooked: true, + isDelete: true, +}; + +describe('User services', () => { + test('Should fetch user data correctly', async () => { + mockGetAllUsers.mockResolvedValue({ + data: [ + { + id: 1, + name: 'Nezumi', + phone: '0324422123', + isBooked: true, + isDelete: true, + }, + { + id: 2, + name: 'Loi Phan', + phone: '0324422145', + isBooked: false, + isDelete: true, + }, + ], count: 2 + }); + const result = await mockGetAllUsers(({ + sortBy: 'name', + orderBy: 'asc', + phoneSearch: '', + page: 1, + })); + + await waitFor(() => expect(result.data.length).toEqual(2)); + }); + + test('Should create user correctly', async () => { + mockCreateUser.mockResolvedValue(sampleData); + const result = await mockCreateUser(sampleData); + + await waitFor(() => expect(result).toBeTruthy()); + }); + + test('Should update user correctly', async () => { + mockUpdateUser.mockResolvedValue(sampleData); + const result = await mockUpdateUser(sampleData); + + await waitFor(() => expect(result).toBeTruthy()); + }); +});