Merge pull request #49 from Nez27/feat/unit-test

Add unit test case and fix comments
This commit is contained in:
Loi Phan
2023-12-03 22:25:53 +07:00
committed by GitHub
138 changed files with 9131 additions and 1535 deletions
-2
View File
@@ -19,14 +19,12 @@
"@supabase/supabase-js": "^2.38.4", "@supabase/supabase-js": "^2.38.4",
"@tanstack/react-query": "^5.8.4", "@tanstack/react-query": "^5.8.4",
"@tanstack/react-query-devtools": "^5.8.4", "@tanstack/react-query-devtools": "^5.8.4",
"@types/react-test-renderer": "^18.0.6",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-hook-form": "^7.47.0", "react-hook-form": "^7.47.0",
"react-hot-toast": "^2.4.1", "react-hot-toast": "^2.4.1",
"react-icons": "^4.11.0", "react-icons": "^4.11.0",
"react-router-dom": "^6.17.0", "react-router-dom": "^6.17.0",
"react-test-renderer": "^18.2.0",
"styled-components": "^6.1.0" "styled-components": "^6.1.0"
}, },
"devDependencies": { "devDependencies": {
+4 -38
View File
@@ -17,9 +17,6 @@ dependencies:
'@tanstack/react-query-devtools': '@tanstack/react-query-devtools':
specifier: ^5.8.4 specifier: ^5.8.4
version: 5.8.4(@tanstack/react-query@5.8.4)(react-dom@18.2.0)(react@18.2.0) version: 5.8.4(@tanstack/react-query@5.8.4)(react-dom@18.2.0)(react@18.2.0)
'@types/react-test-renderer':
specifier: ^18.0.6
version: 18.0.6
react: react:
specifier: ^18.2.0 specifier: ^18.2.0
version: 18.2.0 version: 18.2.0
@@ -38,9 +35,6 @@ dependencies:
react-router-dom: react-router-dom:
specifier: ^6.17.0 specifier: ^6.17.0
version: 6.17.0(react-dom@18.2.0)(react@18.2.0) version: 6.17.0(react-dom@18.2.0)(react@18.2.0)
react-test-renderer:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
styled-components: styled-components:
specifier: ^6.1.0 specifier: ^6.1.0
version: 6.1.0(react-dom@18.2.0)(react@18.2.0) version: 6.1.0(react-dom@18.2.0)(react@18.2.0)
@@ -1342,6 +1336,7 @@ packages:
/@types/prop-types@15.7.9: /@types/prop-types@15.7.9:
resolution: {integrity: sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==} resolution: {integrity: sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==}
dev: true
/@types/react-dom@18.2.14: /@types/react-dom@18.2.14:
resolution: {integrity: sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==} resolution: {integrity: sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==}
@@ -1349,21 +1344,17 @@ packages:
'@types/react': 18.2.29 '@types/react': 18.2.29
dev: true dev: true
/@types/react-test-renderer@18.0.6:
resolution: {integrity: sha512-O2JT1J3/v/NaYHYmPf2DXBSqUGmp6iwhFPicES6Pc1Y90B9Qgu99mmaBGqfZFpVuXLzF/pNJB4K9ySL3iqFeXA==}
dependencies:
'@types/react': 18.2.29
dev: false
/@types/react@18.2.29: /@types/react@18.2.29:
resolution: {integrity: sha512-Z+ZrIRocWtdD70j45izShRwDuiB4JZqDegqMFW/I8aG5DxxLKOzVNoq62UIO82v9bdgi+DO1jvsb9sTEZUSm+Q==} resolution: {integrity: sha512-Z+ZrIRocWtdD70j45izShRwDuiB4JZqDegqMFW/I8aG5DxxLKOzVNoq62UIO82v9bdgi+DO1jvsb9sTEZUSm+Q==}
dependencies: dependencies:
'@types/prop-types': 15.7.9 '@types/prop-types': 15.7.9
'@types/scheduler': 0.16.5 '@types/scheduler': 0.16.5
csstype: 3.1.2 csstype: 3.1.2
dev: true
/@types/scheduler@0.16.5: /@types/scheduler@0.16.5:
resolution: {integrity: sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==} resolution: {integrity: sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==}
dev: true
/@types/semver@7.5.3: /@types/semver@7.5.3:
resolution: {integrity: sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==} resolution: {integrity: sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==}
@@ -3738,11 +3729,6 @@ packages:
resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==}
dev: true dev: true
/object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
dev: false
/object-inspect@1.13.1: /object-inspect@1.13.1:
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
dev: true dev: true
@@ -4005,6 +3991,7 @@ packages:
/react-is@18.2.0: /react-is@18.2.0:
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
dev: true
/react-refresh@0.14.0: /react-refresh@0.14.0:
resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==}
@@ -4034,27 +4021,6 @@ packages:
react: 18.2.0 react: 18.2.0
dev: false dev: false
/react-shallow-renderer@16.15.0(react@18.2.0):
resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==}
peerDependencies:
react: ^16.0.0 || ^17.0.0 || ^18.0.0
dependencies:
object-assign: 4.1.1
react: 18.2.0
react-is: 18.2.0
dev: false
/react-test-renderer@18.2.0(react@18.2.0):
resolution: {integrity: sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==}
peerDependencies:
react: ^18.2.0
dependencies:
react: 18.2.0
react-is: 18.2.0
react-shallow-renderer: 16.15.0(react@18.2.0)
scheduler: 0.23.0
dev: false
/react@18.2.0: /react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
+4
View File
@@ -1,6 +1,10 @@
import { render, act, RenderResult } from '@testing-library/react'; import { render, act, RenderResult } from '@testing-library/react';
// Services
import * as userServices from '@service/userServices'; import * as userServices from '@service/userServices';
import * as roomServices from '@service/roomServices'; import * as roomServices from '@service/roomServices';
// Components
import App from './App'; import App from './App';
jest.mock('@service/userServices'); jest.mock('@service/userServices');
+1 -1
View File
@@ -14,7 +14,7 @@ import RootLayout from '@component/RootLayout';
import User from './pages/User'; import User from './pages/User';
import Booking from './pages/Booking'; import Booking from './pages/Booking';
import Room from './pages/Room'; import Room from './pages/Room';
import NotFound from './pages/NotFound/NotFound'; import NotFound from './pages/NotFound';
import Login from '@page/Login'; import Login from '@page/Login';
import Account from '@page/Account'; import Account from '@page/Account';
@@ -9,7 +9,7 @@ exports[`App should render correctly 1`] = `
class="sc-jrsKJM iDdaat" class="sc-jrsKJM iDdaat"
> >
<div <div
class="sc-pNWRh lfNGxm" class="sc-pNWRh eTXcLU"
/> />
</div> </div>
<div <div
@@ -22,7 +22,7 @@ exports[`App should render correctly 1`] = `
class="sc-jrsKJM iDdaat" class="sc-jrsKJM iDdaat"
> >
<div <div
class="sc-pNWRh lfNGxm" class="sc-pNWRh eTXcLU"
/> />
</div> </div>
<div <div
+5 -1
View File
@@ -3,7 +3,11 @@ import styled, { css } from 'styled-components';
// Styled // Styled
import CommonInput from './CommonInput'; import CommonInput from './CommonInput';
type TInput = 'text' | 'checkbox' | 'hidden' | 'date' | 'password'; type TInput = 'text'
| 'checkbox'
| 'hidden'
| 'date'
| 'password';
interface IInputTyped { interface IInputTyped {
type?: TInput; type?: TInput;
@@ -12,9 +12,8 @@ const Spinner = styled.div`
width: 80px; width: 80px;
aspect-ratio: 1; aspect-ratio: 1;
border-radius: 50%; border-radius: 50%;
background: background: radial-gradient(farthest-side, var(--primary-color) 94%, #0000)
radial-gradient(farthest-side, var(--primary-color) 94%, #0000) top/10px top/10px 10px no-repeat,
10px no-repeat,
conic-gradient(#0000 30%, var(--primary-color)); conic-gradient(#0000 30%, var(--primary-color));
-webkit-mask: radial-gradient(farthest-side, #0000 calc(100% - 10px), #000 0); -webkit-mask: radial-gradient(farthest-side, #0000 calc(100% - 10px), #000 0);
mask: none; mask: none;
@@ -1,14 +1,14 @@
import renderer from 'react-test-renderer';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import { render } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
// Components // Components
import AppLayout from '.'; import AppLayout from '.';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
describe('AppLayout', () => { describe('AppLayout', () => {
const queryClient = new QueryClient(); const queryClient = new QueryClient();
const wrapper = renderer.create( const wrapper = render(
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<BrowserRouter> <BrowserRouter>
<AppLayout /> <AppLayout />
@@ -1,206 +1,360 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`AppLayout Should render correctly 1`] = ` exports[`AppLayout Should render correctly 1`] = `
<div {
className="sc-iCoHzw jFLeHb" "asFragment": [Function],
> "baseElement": <body>
<header <div>
className="sc-dlniIP cClxoS" <div
> class="sc-iCoHzw kcSkNP"
<p> >
Hi, <header
! class="sc-dlniIP eqIruu"
</p>
<ul
className="sc-gtsqUy gOWXQs"
>
<li>
<button
className="sc-bdnyFh bxHnoO"
iconStyle={
{
"size": "23px",
}
}
isHaveChildren={false}
onClick={[Function]}
style={
{
"backgroundColor": undefined,
"color": undefined,
"fontSize": undefined,
}
}
> >
<svg <p>
fill="currentColor" Hi,
height="1em" !
stroke="currentColor" </p>
strokeWidth="0" <ul
style={ class="sc-gtsqUy gOWXQs"
{
"color": undefined,
}
}
viewBox="0 0 512 512"
width="1em"
xmlns="http://www.w3.org/2000/svg"
> >
<path <li>
d="M258.9 48C141.92 46.42 46.42 141.92 48 258.9c1.56 112.19 92.91 203.54 205.1 205.1 117 1.6 212.48-93.9 210.88-210.88C462.44 140.91 371.09 49.56 258.9 48zm126.42 327.25a4 4 0 01-6.14-.32 124.27 124.27 0 00-32.35-29.59C321.37 329 289.11 320 256 320s-65.37 9-90.83 25.34a124.24 124.24 0 00-32.35 29.58 4 4 0 01-6.14.32A175.32 175.32 0 0180 259c-1.63-97.31 78.22-178.76 175.57-179S432 158.81 432 256a175.32 175.32 0 01-46.68 119.25z" <button
/> aria-label="Profile"
<path class="sc-bdnyFh bxHnoO"
d="M256 144c-19.72 0-37.55 7.39-50.22 20.82s-19 32-17.57 51.93C191.11 256 221.52 288 256 288s64.83-32 67.79-71.24c1.48-19.74-4.8-38.14-17.68-51.82C293.39 151.44 275.59 144 256 144z" iconstyle="[object Object]"
/> >
</svg> <svg
fill="currentColor"
<span /> height="1em"
</button> stroke="currentColor"
</li> stroke-width="0"
<li> viewBox="0 0 512 512"
<button width="1em"
className="sc-bdnyFh bxHnoO" xmlns="http://www.w3.org/2000/svg"
disabled={false} >
iconStyle={ <path
{ d="M258.9 48C141.92 46.42 46.42 141.92 48 258.9c1.56 112.19 92.91 203.54 205.1 205.1 117 1.6 212.48-93.9 210.88-210.88C462.44 140.91 371.09 49.56 258.9 48zm126.42 327.25a4 4 0 01-6.14-.32 124.27 124.27 0 00-32.35-29.59C321.37 329 289.11 320 256 320s-65.37 9-90.83 25.34a124.24 124.24 0 00-32.35 29.58 4 4 0 01-6.14.32A175.32 175.32 0 0180 259c-1.63-97.31 78.22-178.76 175.57-179S432 158.81 432 256a175.32 175.32 0 01-46.68 119.25z"
"size": "23px", />
} <path
} d="M256 144c-19.72 0-37.55 7.39-50.22 20.82s-19 32-17.57 51.93C191.11 256 221.52 288 256 288s64.83-32 67.79-71.24c1.48-19.74-4.8-38.14-17.68-51.82C293.39 151.44 275.59 144 256 144z"
isHaveChildren={false} />
onClick={[Function]} </svg>
style={
{ <span />
"backgroundColor": undefined, </button>
"color": undefined, </li>
"fontSize": undefined, <li>
} <button
} aria-label="Logout"
class="sc-bdnyFh bxHnoO"
iconstyle="[object Object]"
>
<svg
aria-hidden="true"
fill="none"
height="1em"
stroke="currentColor"
stroke-width="2"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<span />
</button>
</li>
</ul>
</header>
<aside
class="sc-jSFipO ejTmsl"
> >
<svg <h1
aria-hidden="true" class="sc-gKAaef kdwrvt"
fill="none"
height="1em"
stroke="currentColor"
strokeWidth="2"
style={
{
"color": undefined,
}
}
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
> >
<path Hotel Management
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" </h1>
strokeLinecap="round" <nav
strokeLinejoin="round" class="sc-hKFymg eIMPQI"
/> >
</svg> <a
class="sc-eCAqax hQZHUY"
<span /> href="/booking"
</button> >
</li> <svg
</ul> fill="currentColor"
</header> height="1em"
<aside stroke="currentColor"
className="sc-jSFipO ejTmsl" stroke-width="0"
> viewBox="0 0 24 24"
<h1 width="1em"
className="sc-gKAaef kdwrvt" xmlns="http://www.w3.org/2000/svg"
onClick={[Function]} >
<path
d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM5 7h14v2H5V7z"
/>
</svg>
<span>
Booking
</span>
</a>
<a
class="sc-eCAqax hQZHUY"
href="/user"
>
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.5 6.375a4.125 4.125 0 118.25 0 4.125 4.125 0 01-8.25 0zM14.25 8.625a3.375 3.375 0 116.75 0 3.375 3.375 0 01-6.75 0zM1.5 19.125a7.125 7.125 0 0114.25 0v.003l-.001.119a.75.75 0 01-.363.63 13.067 13.067 0 01-6.761 1.873c-2.472 0-4.786-.684-6.76-1.873a.75.75 0 01-.364-.63l-.001-.122zM17.25 19.128l-.001.144a2.25 2.25 0 01-.233.96 10.088 10.088 0 005.06-1.01.75.75 0 00.42-.643 4.875 4.875 0 00-6.957-4.611 8.586 8.586 0 011.71 5.157v.003z"
/>
</svg>
<span>
User
</span>
</a>
<a
class="sc-eCAqax hQZHUY"
href="/room"
>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 16 16"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z"
/>
</svg>
<span>
Room
</span>
</a>
</nav>
</aside>
<main
class="sc-fujznN cdRedX"
/>
</div>
</div>
</body>,
"container": <div>
<div
class="sc-iCoHzw kcSkNP"
> >
Hotel Management <header
</h1> class="sc-dlniIP eqIruu"
<nav
className="sc-hKFymg eIMPQI"
>
<a
className="sc-eCAqax hQZHUY"
href="/booking"
onClick={[Function]}
> >
<svg <p>
fill="currentColor" Hi,
height="1em" !
stroke="currentColor" </p>
strokeWidth="0" <ul
style={ class="sc-gtsqUy gOWXQs"
{
"color": undefined,
}
}
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
> >
<path <li>
d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM5 7h14v2H5V7z" <button
/> aria-label="Profile"
</svg> class="sc-bdnyFh bxHnoO"
<span> iconstyle="[object Object]"
Booking >
</span> <svg
</a> fill="currentColor"
<a height="1em"
className="sc-eCAqax hQZHUY" stroke="currentColor"
href="/user" stroke-width="0"
onClick={[Function]} viewBox="0 0 512 512"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M258.9 48C141.92 46.42 46.42 141.92 48 258.9c1.56 112.19 92.91 203.54 205.1 205.1 117 1.6 212.48-93.9 210.88-210.88C462.44 140.91 371.09 49.56 258.9 48zm126.42 327.25a4 4 0 01-6.14-.32 124.27 124.27 0 00-32.35-29.59C321.37 329 289.11 320 256 320s-65.37 9-90.83 25.34a124.24 124.24 0 00-32.35 29.58 4 4 0 01-6.14.32A175.32 175.32 0 0180 259c-1.63-97.31 78.22-178.76 175.57-179S432 158.81 432 256a175.32 175.32 0 01-46.68 119.25z"
/>
<path
d="M256 144c-19.72 0-37.55 7.39-50.22 20.82s-19 32-17.57 51.93C191.11 256 221.52 288 256 288s64.83-32 67.79-71.24c1.48-19.74-4.8-38.14-17.68-51.82C293.39 151.44 275.59 144 256 144z"
/>
</svg>
<span />
</button>
</li>
<li>
<button
aria-label="Logout"
class="sc-bdnyFh bxHnoO"
iconstyle="[object Object]"
>
<svg
aria-hidden="true"
fill="none"
height="1em"
stroke="currentColor"
stroke-width="2"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<span />
</button>
</li>
</ul>
</header>
<aside
class="sc-jSFipO ejTmsl"
> >
<svg <h1
aria-hidden="true" class="sc-gKAaef kdwrvt"
fill="currentColor"
height="1em"
stroke="currentColor"
strokeWidth="0"
style={
{
"color": undefined,
}
}
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
> >
<path Hotel Management
d="M4.5 6.375a4.125 4.125 0 118.25 0 4.125 4.125 0 01-8.25 0zM14.25 8.625a3.375 3.375 0 116.75 0 3.375 3.375 0 01-6.75 0zM1.5 19.125a7.125 7.125 0 0114.25 0v.003l-.001.119a.75.75 0 01-.363.63 13.067 13.067 0 01-6.761 1.873c-2.472 0-4.786-.684-6.76-1.873a.75.75 0 01-.364-.63l-.001-.122zM17.25 19.128l-.001.144a2.25 2.25 0 01-.233.96 10.088 10.088 0 005.06-1.01.75.75 0 00.42-.643 4.875 4.875 0 00-6.957-4.611 8.586 8.586 0 011.71 5.157v.003z" </h1>
/> <nav
</svg> class="sc-hKFymg eIMPQI"
<span>
User
</span>
</a>
<a
className="sc-eCAqax hQZHUY"
href="/room"
onClick={[Function]}
>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
strokeWidth="0"
style={
{
"color": undefined,
}
}
viewBox="0 0 16 16"
width="1em"
xmlns="http://www.w3.org/2000/svg"
> >
<path <a
d="M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z" class="sc-eCAqax hQZHUY"
/> href="/booking"
</svg> >
<span> <svg
Room fill="currentColor"
</span> height="1em"
</a> stroke="currentColor"
</nav> stroke-width="0"
</aside> viewBox="0 0 24 24"
<main width="1em"
className="sc-fujznN cdRedX" xmlns="http://www.w3.org/2000/svg"
/> >
</div> <path
d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM5 7h14v2H5V7z"
/>
</svg>
<span>
Booking
</span>
</a>
<a
class="sc-eCAqax hQZHUY"
href="/user"
>
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.5 6.375a4.125 4.125 0 118.25 0 4.125 4.125 0 01-8.25 0zM14.25 8.625a3.375 3.375 0 116.75 0 3.375 3.375 0 01-6.75 0zM1.5 19.125a7.125 7.125 0 0114.25 0v.003l-.001.119a.75.75 0 01-.363.63 13.067 13.067 0 01-6.761 1.873c-2.472 0-4.786-.684-6.76-1.873a.75.75 0 01-.364-.63l-.001-.122zM17.25 19.128l-.001.144a2.25 2.25 0 01-.233.96 10.088 10.088 0 005.06-1.01.75.75 0 00.42-.643 4.875 4.875 0 00-6.957-4.611 8.586 8.586 0 011.71 5.157v.003z"
/>
</svg>
<span>
User
</span>
</a>
<a
class="sc-eCAqax hQZHUY"
href="/room"
>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 16 16"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z"
/>
</svg>
<span>
Room
</span>
</a>
</nav>
</aside>
<main
class="sc-fujznN cdRedX"
/>
</div>
</div>,
"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],
}
`; `;
@@ -4,7 +4,7 @@ const StyledAppLayout = styled.div`
display: grid; display: grid;
grid-template-columns: 300px 1fr; grid-template-columns: 300px 1fr;
grid-template-rows: auto 1fr; grid-template-rows: auto 1fr;
height: 100vh; height: 100vh;
`; `;
@@ -1,11 +1,11 @@
import renderer from 'react-test-renderer';
// Components
import ButtonIcon from '.';
import { HiOutlineLogout } from 'react-icons/hi'; import { HiOutlineLogout } from 'react-icons/hi';
// Components
import { render } from '@testing-library/react';
import ButtonIcon from '.';
describe('ButtonIcon', () => { describe('ButtonIcon', () => {
const wrapper = renderer.create( const wrapper = render(
<ButtonIcon <ButtonIcon
aria-label="Logout" aria-label="Logout"
icon={<HiOutlineLogout />} icon={<HiOutlineLogout />}
@@ -1,44 +1,110 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ButtonIcon Should render correctly 1`] = ` exports[`ButtonIcon Should render correctly 1`] = `
<button {
className="sc-bdnyFh bxHnoO" "asFragment": [Function],
iconStyle={ "baseElement": <body>
{ <div>
"size": "23px", <button
} class="sc-bdnyFh bxHnoO"
} iconstyle="[object Object]"
isHaveChildren={false} >
style={ <svg
{ aria-hidden="true"
"backgroundColor": undefined, fill="none"
"color": undefined, height="1em"
"fontSize": undefined, stroke="currentColor"
} stroke-width="2"
} viewBox="0 0 24 24"
> width="1em"
<svg xmlns="http://www.w3.org/2000/svg"
aria-hidden="true" >
fill="none" <path
height="1em" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
stroke="currentColor" stroke-linecap="round"
strokeWidth="2" stroke-linejoin="round"
style={ />
{ </svg>
"color": undefined,
} <span />
} </button>
viewBox="0 0 24 24" </div>
width="1em" </body>,
xmlns="http://www.w3.org/2000/svg" "container": <div>
> <button
<path class="sc-bdnyFh bxHnoO"
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" iconstyle="[object Object]"
strokeLinecap="round" >
strokeLinejoin="round" <svg
/> aria-hidden="true"
</svg> fill="none"
height="1em"
<span /> stroke="currentColor"
</button> stroke-width="2"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<span />
</button>
</div>,
"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],
}
`; `;
@@ -1,6 +1,7 @@
import { RenderResult, fireEvent, render } from '@testing-library/react';
// Components // Components
import ConfirmMessage from '.'; import ConfirmMessage from '.';
import { RenderResult, fireEvent, render } from '@testing-library/react';
describe('ConfirmMessage testing snapshot', () => { describe('ConfirmMessage testing snapshot', () => {
const message = 'Hello World!'; const message = 'Hello World!';
@@ -1,7 +1,9 @@
import renderer from 'react-test-renderer'; import { render } from '@testing-library/react';
// Components // Components
import Form from '.'; import Form from '.';
// Styled
import Input from '@commonStyle/Input'; import Input from '@commonStyle/Input';
describe('Form ', () => { describe('Form ', () => {
@@ -10,7 +12,7 @@ describe('Form ', () => {
const handleOnSubmit = jest.fn(); const handleOnSubmit = jest.fn();
const handleOnClick = jest.fn(); const handleOnClick = jest.fn();
const wrapper = renderer.create( const wrapper = render(
<Form onSubmit={handleOnSubmit}> <Form onSubmit={handleOnSubmit}>
<Form.Row label="Name" error={errorMessage}> <Form.Row label="Name" error={errorMessage}>
<Input type="text" id="name" /> <Input type="text" id="name" />
@@ -24,7 +26,11 @@ describe('Form ', () => {
<Form.Button type="submit" name="submit" disabled={isDisable}> <Form.Button type="submit" name="submit" disabled={isDisable}>
Confirm Confirm
</Form.Button> </Form.Button>
<Form.Button type="button" variations="secondary" onClick={handleOnClick}> <Form.Button
type="button"
variations="secondary"
onClick={handleOnClick}
>
Close Close
</Form.Button> </Form.Button>
</Form.Action> </Form.Action>
@@ -1,74 +1,200 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Form Should render correctly 1`] = ` exports[`Form Should render correctly 1`] = `
<form {
className="sc-gtsqUy jMGskL" "asFragment": [Function],
onSubmit={[MockFunction]} "baseElement": <body>
>
<div
className="sc-hKFymg ivIEWo"
direction="horizontal"
>
<label
className="sc-eCAqax dnXnhF"
>
Name
</label>
<div> <div>
<input <form
className="sc-iCoHzw csWeiH" class="sc-gtsqUy jMGskL"
id="name"
type="text"
/>
<p
className="sc-jSFipO iOcxfq"
> >
This is error message <div
</p> class="sc-hKFymg ivIEWo"
direction="horizontal"
>
<label
class="sc-eCAqax dnXnhF"
>
Name
</label>
<div>
<input
class="sc-iCoHzw csWeiH"
id="name"
type="text"
/>
<p
class="sc-jSFipO iOcxfq"
>
This is error message
</p>
</div>
</div>
<div
class="sc-hKFymg ivIEWo"
direction="horizontal"
>
<label
class="sc-eCAqax dnXnhF"
>
Price
</label>
<div>
<input
class="sc-iCoHzw csWeiH"
id="price"
type="text"
/>
<p
class="sc-jSFipO iOcxfq"
>
This is error message
</p>
</div>
</div>
<div
class="sc-dlniIP hBqqvG"
>
<button
class="sc-bdnyFh sc-gKAaef bEtbaY fRlVwz"
disabled=""
name="submit"
type="submit"
variations="primary"
>
Confirm
</button>
<button
class="sc-bdnyFh sc-gKAaef buXbPz fRlVwz"
type="button"
variations="secondary"
>
Close
</button>
</div>
</form>
</div> </div>
</div> </body>,
<div "container": <div>
className="sc-hKFymg ivIEWo" <form
direction="horizontal" class="sc-gtsqUy jMGskL"
>
<label
className="sc-eCAqax dnXnhF"
> >
Price <div
</label> class="sc-hKFymg ivIEWo"
<div> direction="horizontal"
<input
className="sc-iCoHzw csWeiH"
id="price"
type="text"
/>
<p
className="sc-jSFipO iOcxfq"
> >
This is error message <label
</p> class="sc-eCAqax dnXnhF"
</div> >
</div> Name
<div </label>
className="sc-dlniIP hBqqvG" <div>
> <input
<button class="sc-iCoHzw csWeiH"
className="sc-bdnyFh sc-gKAaef bEtbaY fRlVwz" id="name"
disabled={true} type="text"
name="submit" />
type="submit" <p
variations="primary" class="sc-jSFipO iOcxfq"
> >
Confirm This is error message
</button> </p>
<button </div>
className="sc-bdnyFh sc-gKAaef buXbPz fRlVwz" </div>
onClick={[MockFunction]} <div
type="button" class="sc-hKFymg ivIEWo"
variations="secondary" direction="horizontal"
> >
Close <label
</button> class="sc-eCAqax dnXnhF"
</div> >
</form> Price
</label>
<div>
<input
class="sc-iCoHzw csWeiH"
id="price"
type="text"
/>
<p
class="sc-jSFipO iOcxfq"
>
This is error message
</p>
</div>
</div>
<div
class="sc-dlniIP hBqqvG"
>
<button
class="sc-bdnyFh sc-gKAaef bEtbaY fRlVwz"
disabled=""
name="submit"
type="submit"
variations="primary"
>
Confirm
</button>
<button
class="sc-bdnyFh sc-gKAaef buXbPz fRlVwz"
type="button"
variations="secondary"
>
Close
</button>
</div>
</form>
</div>,
"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],
}
`; `;
@@ -1,14 +1,14 @@
import renderer from 'react-test-renderer'; import { render } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
// Components // Components
import Header from '.'; import Header from '.';
import { BrowserRouter } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
describe('Header', () => { describe('Header', () => {
const queryClient = new QueryClient(); const queryClient = new QueryClient();
const wrapper = renderer.create( const wrapper = render(
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<BrowserRouter> <BrowserRouter>
<Header accountName="Nezumi" /> <Header accountName="Nezumi" />
@@ -1,104 +1,194 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Header Should render correctly 1`] = ` exports[`Header Should render correctly 1`] = `
<header {
className="sc-dlniIP cClxoS" "asFragment": [Function],
> "baseElement": <body>
<p> <div>
Hi, <header
Nezumi class="sc-dlniIP eqIruu"
!
</p>
<ul
className="sc-gtsqUy gOWXQs"
>
<li>
<button
className="sc-bdnyFh bxHnoO"
iconStyle={
{
"size": "23px",
}
}
isHaveChildren={false}
onClick={[Function]}
style={
{
"backgroundColor": undefined,
"color": undefined,
"fontSize": undefined,
}
}
> >
<svg <p>
fill="currentColor" Hi,
height="1em" Nezumi
stroke="currentColor" !
strokeWidth="0" </p>
style={ <ul
{ class="sc-gtsqUy gOWXQs"
"color": undefined,
}
}
viewBox="0 0 512 512"
width="1em"
xmlns="http://www.w3.org/2000/svg"
> >
<path <li>
d="M258.9 48C141.92 46.42 46.42 141.92 48 258.9c1.56 112.19 92.91 203.54 205.1 205.1 117 1.6 212.48-93.9 210.88-210.88C462.44 140.91 371.09 49.56 258.9 48zm126.42 327.25a4 4 0 01-6.14-.32 124.27 124.27 0 00-32.35-29.59C321.37 329 289.11 320 256 320s-65.37 9-90.83 25.34a124.24 124.24 0 00-32.35 29.58 4 4 0 01-6.14.32A175.32 175.32 0 0180 259c-1.63-97.31 78.22-178.76 175.57-179S432 158.81 432 256a175.32 175.32 0 01-46.68 119.25z" <button
/> aria-label="Profile"
<path class="sc-bdnyFh bxHnoO"
d="M256 144c-19.72 0-37.55 7.39-50.22 20.82s-19 32-17.57 51.93C191.11 256 221.52 288 256 288s64.83-32 67.79-71.24c1.48-19.74-4.8-38.14-17.68-51.82C293.39 151.44 275.59 144 256 144z" iconstyle="[object Object]"
/> >
</svg> <svg
fill="currentColor"
<span /> height="1em"
</button> stroke="currentColor"
</li> stroke-width="0"
<li> viewBox="0 0 512 512"
<button width="1em"
className="sc-bdnyFh bxHnoO" xmlns="http://www.w3.org/2000/svg"
disabled={false} >
iconStyle={ <path
{ d="M258.9 48C141.92 46.42 46.42 141.92 48 258.9c1.56 112.19 92.91 203.54 205.1 205.1 117 1.6 212.48-93.9 210.88-210.88C462.44 140.91 371.09 49.56 258.9 48zm126.42 327.25a4 4 0 01-6.14-.32 124.27 124.27 0 00-32.35-29.59C321.37 329 289.11 320 256 320s-65.37 9-90.83 25.34a124.24 124.24 0 00-32.35 29.58 4 4 0 01-6.14.32A175.32 175.32 0 0180 259c-1.63-97.31 78.22-178.76 175.57-179S432 158.81 432 256a175.32 175.32 0 01-46.68 119.25z"
"size": "23px", />
} <path
} d="M256 144c-19.72 0-37.55 7.39-50.22 20.82s-19 32-17.57 51.93C191.11 256 221.52 288 256 288s64.83-32 67.79-71.24c1.48-19.74-4.8-38.14-17.68-51.82C293.39 151.44 275.59 144 256 144z"
isHaveChildren={false} />
onClick={[Function]} </svg>
style={
{ <span />
"backgroundColor": undefined, </button>
"color": undefined, </li>
"fontSize": undefined, <li>
} <button
} aria-label="Logout"
class="sc-bdnyFh bxHnoO"
iconstyle="[object Object]"
>
<svg
aria-hidden="true"
fill="none"
height="1em"
stroke="currentColor"
stroke-width="2"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<span />
</button>
</li>
</ul>
</header>
</div>
</body>,
"container": <div>
<header
class="sc-dlniIP eqIruu"
>
<p>
Hi,
Nezumi
!
</p>
<ul
class="sc-gtsqUy gOWXQs"
> >
<svg <li>
aria-hidden="true" <button
fill="none" aria-label="Profile"
height="1em" class="sc-bdnyFh bxHnoO"
stroke="currentColor" iconstyle="[object Object]"
strokeWidth="2" >
style={ <svg
{ fill="currentColor"
"color": undefined, height="1em"
} stroke="currentColor"
} stroke-width="0"
viewBox="0 0 24 24" viewBox="0 0 512 512"
width="1em" width="1em"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
> >
<path <path
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" d="M258.9 48C141.92 46.42 46.42 141.92 48 258.9c1.56 112.19 92.91 203.54 205.1 205.1 117 1.6 212.48-93.9 210.88-210.88C462.44 140.91 371.09 49.56 258.9 48zm126.42 327.25a4 4 0 01-6.14-.32 124.27 124.27 0 00-32.35-29.59C321.37 329 289.11 320 256 320s-65.37 9-90.83 25.34a124.24 124.24 0 00-32.35 29.58 4 4 0 01-6.14.32A175.32 175.32 0 0180 259c-1.63-97.31 78.22-178.76 175.57-179S432 158.81 432 256a175.32 175.32 0 01-46.68 119.25z"
strokeLinecap="round" />
strokeLinejoin="round" <path
/> d="M256 144c-19.72 0-37.55 7.39-50.22 20.82s-19 32-17.57 51.93C191.11 256 221.52 288 256 288s64.83-32 67.79-71.24c1.48-19.74-4.8-38.14-17.68-51.82C293.39 151.44 275.59 144 256 144z"
</svg> />
</svg>
<span />
</button> <span />
</li> </button>
</ul> </li>
</header> <li>
<button
aria-label="Logout"
class="sc-bdnyFh bxHnoO"
iconstyle="[object Object]"
>
<svg
aria-hidden="true"
fill="none"
height="1em"
stroke="currentColor"
stroke-width="2"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<span />
</button>
</li>
</ul>
</header>
</div>,
"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],
}
`; `;
@@ -2,7 +2,7 @@ import styled from 'styled-components';
const StyledHeader = styled.header` const StyledHeader = styled.header`
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
padding: 20px 40px; padding: 20px 40px;
display: flex; display: flex;
@@ -1,14 +1,14 @@
import renderer from 'react-test-renderer'; import { BrowserRouter } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { render } from '@testing-library/react';
// Components // Components
import HeaderMenu from '.'; import HeaderMenu from '.';
import { BrowserRouter } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
describe('HeaderMenu', () => { describe('HeaderMenu', () => {
const queryClient = new QueryClient(); const queryClient = new QueryClient();
const wrapper = renderer.create( const wrapper = render(
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<BrowserRouter> <BrowserRouter>
<HeaderMenu /> <HeaderMenu />
@@ -1,95 +1,176 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`HeaderMenu Should render correctly 1`] = ` exports[`HeaderMenu Should render correctly 1`] = `
<ul {
className="sc-gtsqUy gOWXQs" "asFragment": [Function],
> "baseElement": <body>
<li> <div>
<button <ul
className="sc-bdnyFh bxHnoO" class="sc-gtsqUy gOWXQs"
iconStyle={
{
"size": "23px",
}
}
isHaveChildren={false}
onClick={[Function]}
style={
{
"backgroundColor": undefined,
"color": undefined,
"fontSize": undefined,
}
}
>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
strokeWidth="0"
style={
{
"color": undefined,
}
}
viewBox="0 0 512 512"
width="1em"
xmlns="http://www.w3.org/2000/svg"
> >
<path <li>
d="M258.9 48C141.92 46.42 46.42 141.92 48 258.9c1.56 112.19 92.91 203.54 205.1 205.1 117 1.6 212.48-93.9 210.88-210.88C462.44 140.91 371.09 49.56 258.9 48zm126.42 327.25a4 4 0 01-6.14-.32 124.27 124.27 0 00-32.35-29.59C321.37 329 289.11 320 256 320s-65.37 9-90.83 25.34a124.24 124.24 0 00-32.35 29.58 4 4 0 01-6.14.32A175.32 175.32 0 0180 259c-1.63-97.31 78.22-178.76 175.57-179S432 158.81 432 256a175.32 175.32 0 01-46.68 119.25z" <button
/> aria-label="Profile"
<path class="sc-bdnyFh bxHnoO"
d="M256 144c-19.72 0-37.55 7.39-50.22 20.82s-19 32-17.57 51.93C191.11 256 221.52 288 256 288s64.83-32 67.79-71.24c1.48-19.74-4.8-38.14-17.68-51.82C293.39 151.44 275.59 144 256 144z" iconstyle="[object Object]"
/> >
</svg> <svg
fill="currentColor"
<span /> height="1em"
</button> stroke="currentColor"
</li> stroke-width="0"
<li> viewBox="0 0 512 512"
<button width="1em"
className="sc-bdnyFh bxHnoO" xmlns="http://www.w3.org/2000/svg"
disabled={false} >
iconStyle={ <path
{ d="M258.9 48C141.92 46.42 46.42 141.92 48 258.9c1.56 112.19 92.91 203.54 205.1 205.1 117 1.6 212.48-93.9 210.88-210.88C462.44 140.91 371.09 49.56 258.9 48zm126.42 327.25a4 4 0 01-6.14-.32 124.27 124.27 0 00-32.35-29.59C321.37 329 289.11 320 256 320s-65.37 9-90.83 25.34a124.24 124.24 0 00-32.35 29.58 4 4 0 01-6.14.32A175.32 175.32 0 0180 259c-1.63-97.31 78.22-178.76 175.57-179S432 158.81 432 256a175.32 175.32 0 01-46.68 119.25z"
"size": "23px", />
} <path
} d="M256 144c-19.72 0-37.55 7.39-50.22 20.82s-19 32-17.57 51.93C191.11 256 221.52 288 256 288s64.83-32 67.79-71.24c1.48-19.74-4.8-38.14-17.68-51.82C293.39 151.44 275.59 144 256 144z"
isHaveChildren={false} />
onClick={[Function]} </svg>
style={
{ <span />
"backgroundColor": undefined, </button>
"color": undefined, </li>
"fontSize": undefined, <li>
} <button
} aria-label="Logout"
class="sc-bdnyFh bxHnoO"
iconstyle="[object Object]"
>
<svg
aria-hidden="true"
fill="none"
height="1em"
stroke="currentColor"
stroke-width="2"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<span />
</button>
</li>
</ul>
</div>
</body>,
"container": <div>
<ul
class="sc-gtsqUy gOWXQs"
> >
<svg <li>
aria-hidden="true" <button
fill="none" aria-label="Profile"
height="1em" class="sc-bdnyFh bxHnoO"
stroke="currentColor" iconstyle="[object Object]"
strokeWidth="2" >
style={ <svg
{ fill="currentColor"
"color": undefined, height="1em"
} stroke="currentColor"
} stroke-width="0"
viewBox="0 0 24 24" viewBox="0 0 512 512"
width="1em" width="1em"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
> >
<path <path
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" d="M258.9 48C141.92 46.42 46.42 141.92 48 258.9c1.56 112.19 92.91 203.54 205.1 205.1 117 1.6 212.48-93.9 210.88-210.88C462.44 140.91 371.09 49.56 258.9 48zm126.42 327.25a4 4 0 01-6.14-.32 124.27 124.27 0 00-32.35-29.59C321.37 329 289.11 320 256 320s-65.37 9-90.83 25.34a124.24 124.24 0 00-32.35 29.58 4 4 0 01-6.14.32A175.32 175.32 0 0180 259c-1.63-97.31 78.22-178.76 175.57-179S432 158.81 432 256a175.32 175.32 0 01-46.68 119.25z"
strokeLinecap="round" />
strokeLinejoin="round" <path
/> d="M256 144c-19.72 0-37.55 7.39-50.22 20.82s-19 32-17.57 51.93C191.11 256 221.52 288 256 288s64.83-32 67.79-71.24c1.48-19.74-4.8-38.14-17.68-51.82C293.39 151.44 275.59 144 256 144z"
</svg> />
</svg>
<span />
</button> <span />
</li> </button>
</ul> </li>
<li>
<button
aria-label="Logout"
class="sc-bdnyFh bxHnoO"
iconstyle="[object Object]"
>
<svg
aria-hidden="true"
fill="none"
height="1em"
stroke="currentColor"
stroke-width="2"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<span />
</button>
</li>
</ul>
</div>,
"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],
}
`; `;
@@ -1,8 +1,9 @@
// Components
import Menus from '.';
import { RiEditBoxFill, RiDeleteBin2Line } from 'react-icons/ri'; import { RiEditBoxFill, RiDeleteBin2Line } from 'react-icons/ri';
import { RenderResult, fireEvent, render } from '@testing-library/react'; import { RenderResult, fireEvent, render } from '@testing-library/react';
// Components
import Menus from '.';
describe('Menus', () => { describe('Menus', () => {
const id = '123'; const id = '123';
const handleOnClick = jest.fn(); const handleOnClick = jest.fn();
@@ -2,13 +2,17 @@ import { MouseEvent, ReactNode, useContext, useState } from 'react';
// Components // Components
import { HiEllipsisVertical } from 'react-icons/hi2'; import { HiEllipsisVertical } from 'react-icons/hi2';
import ButtonIcon from '@component/ButtonIcon';
// Hooks // Hooks
import { useOutsideClick } from '@hook/useOutsideClick'; import { useOutsideClick } from '@hook/useOutsideClick';
import ButtonIcon from '@component/ButtonIcon';
// Styled // Styled
import { StyledMenu, StyledList, StyledToggle } from './styled'; import {
StyledMenu,
StyledList,
StyledToggle
} from './styled';
// Contexts // Contexts
import MenusContext from '@context/MenuContext'; import MenusContext from '@context/MenuContext';
@@ -1,10 +1,10 @@
import renderer from 'react-test-renderer'; import { render } from '@testing-library/react';
// Components // Components
import Message from '.'; import Message from '.';
describe('Message', () => { describe('Message', () => {
const wrapper = renderer.create(<Message>This is a message!</Message>); const wrapper = render(<Message>This is a message!</Message>);
test('Should render correctly', () => { test('Should render correctly', () => {
expect(wrapper).toMatchSnapshot(); expect(wrapper).toMatchSnapshot();
@@ -1,9 +1,74 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Message Should render correctly 1`] = ` exports[`Message Should render correctly 1`] = `
<p {
className="sc-bdnyFh fIKUZt" "asFragment": [Function],
> "baseElement": <body>
This is a message! <div>
</p> <p
class="sc-bdnyFh fIKUZt"
>
This is a message!
</p>
</div>
</body>,
"container": <div>
<p
class="sc-bdnyFh fIKUZt"
>
This is a message!
</p>
</div>,
"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],
}
`; `;
@@ -1,11 +1,11 @@
import renderer from 'react-test-renderer'; import { render } from '@testing-library/react';
// Components // Components
import Modal from '.'; import Modal from '.';
import Button from '@commonStyle/Button'; import Button from '@commonStyle/Button';
describe('Modal', () => { describe('Modal', () => {
const wrapper = renderer.create( const wrapper = render(
<Modal> <Modal>
<Modal.Open <Modal.Open
modalName="room-form" modalName="room-form"
@@ -1,11 +1,76 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Modal Should render correctly 1`] = ` exports[`Modal Should render correctly 1`] = `
<button {
className="sc-eCAqax iNUTro" "asFragment": [Function],
onClick={[Function]} "baseElement": <body>
variations="primary" <div>
> <button
Add room class="sc-eCAqax iNUTro"
</button> variations="primary"
>
Add room
</button>
</div>
</body>,
"container": <div>
<button
class="sc-eCAqax iNUTro"
variations="primary"
>
Add room
</button>
</div>,
"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],
}
`; `;
@@ -1,11 +1,12 @@
import renderer from 'react-test-renderer';
import { render } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
// Components // Components
import Nav from '.'; import Nav from '.';
describe('Nav', () => { describe('Nav', () => {
const wrapper = renderer.create( const wrapper = render(
<BrowserRouter> <BrowserRouter>
<Nav /> <Nav />
</BrowserRouter> </BrowserRouter>
@@ -1,90 +1,200 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Nav Should render correctly 1`] = ` exports[`Nav Should render correctly 1`] = `
<nav {
className="sc-bdnyFh gGCifp" "asFragment": [Function],
> "baseElement": <body>
<a <div>
className="sc-gtsqUy gbSQWi" <nav
href="/booking" class="sc-bdnyFh gGCifp"
onClick={[Function]} >
> <a
<svg class="sc-gtsqUy gbSQWi"
fill="currentColor" href="/booking"
height="1em" >
stroke="currentColor" <svg
strokeWidth="0" fill="currentColor"
style={ height="1em"
{ stroke="currentColor"
"color": undefined, stroke-width="0"
} viewBox="0 0 24 24"
} width="1em"
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"
width="1em" >
xmlns="http://www.w3.org/2000/svg" <path
d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM5 7h14v2H5V7z"
/>
</svg>
<span>
Booking
</span>
</a>
<a
class="sc-gtsqUy gbSQWi"
href="/user"
>
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.5 6.375a4.125 4.125 0 118.25 0 4.125 4.125 0 01-8.25 0zM14.25 8.625a3.375 3.375 0 116.75 0 3.375 3.375 0 01-6.75 0zM1.5 19.125a7.125 7.125 0 0114.25 0v.003l-.001.119a.75.75 0 01-.363.63 13.067 13.067 0 01-6.761 1.873c-2.472 0-4.786-.684-6.76-1.873a.75.75 0 01-.364-.63l-.001-.122zM17.25 19.128l-.001.144a2.25 2.25 0 01-.233.96 10.088 10.088 0 005.06-1.01.75.75 0 00.42-.643 4.875 4.875 0 00-6.957-4.611 8.586 8.586 0 011.71 5.157v.003z"
/>
</svg>
<span>
User
</span>
</a>
<a
class="sc-gtsqUy gbSQWi"
href="/room"
>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 16 16"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z"
/>
</svg>
<span>
Room
</span>
</a>
</nav>
</div>
</body>,
"container": <div>
<nav
class="sc-bdnyFh gGCifp"
> >
<path <a
d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM5 7h14v2H5V7z" class="sc-gtsqUy gbSQWi"
/> href="/booking"
</svg> >
<span> <svg
Booking fill="currentColor"
</span> height="1em"
</a> stroke="currentColor"
<a stroke-width="0"
className="sc-gtsqUy gbSQWi" viewBox="0 0 24 24"
href="/user" width="1em"
onClick={[Function]} xmlns="http://www.w3.org/2000/svg"
> >
<svg <path
aria-hidden="true" d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM5 7h14v2H5V7z"
fill="currentColor" />
height="1em" </svg>
stroke="currentColor" <span>
strokeWidth="0" Booking
style={ </span>
{ </a>
"color": undefined, <a
} class="sc-gtsqUy gbSQWi"
} href="/user"
viewBox="0 0 24 24" >
width="1em" <svg
xmlns="http://www.w3.org/2000/svg" aria-hidden="true"
> fill="currentColor"
<path height="1em"
d="M4.5 6.375a4.125 4.125 0 118.25 0 4.125 4.125 0 01-8.25 0zM14.25 8.625a3.375 3.375 0 116.75 0 3.375 3.375 0 01-6.75 0zM1.5 19.125a7.125 7.125 0 0114.25 0v.003l-.001.119a.75.75 0 01-.363.63 13.067 13.067 0 01-6.761 1.873c-2.472 0-4.786-.684-6.76-1.873a.75.75 0 01-.364-.63l-.001-.122zM17.25 19.128l-.001.144a2.25 2.25 0 01-.233.96 10.088 10.088 0 005.06-1.01.75.75 0 00.42-.643 4.875 4.875 0 00-6.957-4.611 8.586 8.586 0 011.71 5.157v.003z" stroke="currentColor"
/> stroke-width="0"
</svg> viewBox="0 0 24 24"
<span> width="1em"
User xmlns="http://www.w3.org/2000/svg"
</span> >
</a> <path
<a d="M4.5 6.375a4.125 4.125 0 118.25 0 4.125 4.125 0 01-8.25 0zM14.25 8.625a3.375 3.375 0 116.75 0 3.375 3.375 0 01-6.75 0zM1.5 19.125a7.125 7.125 0 0114.25 0v.003l-.001.119a.75.75 0 01-.363.63 13.067 13.067 0 01-6.761 1.873c-2.472 0-4.786-.684-6.76-1.873a.75.75 0 01-.364-.63l-.001-.122zM17.25 19.128l-.001.144a2.25 2.25 0 01-.233.96 10.088 10.088 0 005.06-1.01.75.75 0 00.42-.643 4.875 4.875 0 00-6.957-4.611 8.586 8.586 0 011.71 5.157v.003z"
className="sc-gtsqUy gbSQWi" />
href="/room" </svg>
onClick={[Function]} <span>
> User
<svg </span>
fill="currentColor" </a>
height="1em" <a
stroke="currentColor" class="sc-gtsqUy gbSQWi"
strokeWidth="0" href="/room"
style={ >
{ <svg
"color": undefined, fill="currentColor"
} height="1em"
} stroke="currentColor"
viewBox="0 0 16 16" stroke-width="0"
width="1em" viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg" width="1em"
> xmlns="http://www.w3.org/2000/svg"
<path >
d="M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z" <path
/> d="M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z"
</svg> />
<span> </svg>
Room <span>
</span> Room
</a> </span>
</nav> </a>
</nav>
</div>,
"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],
}
`; `;
@@ -0,0 +1,202 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Pagination Should render correctly 1`] = `
{
"asFragment": [Function],
"baseElement": <body>
<div>
<div
class="sc-bdnyFh kjuCvI"
>
<p>
Showing
1
to
5
of
<span>
10
</span>
results
</p>
<div
class="sc-gtsqUy gUbTlC"
>
<button
class="sc-dlniIP kLAzMx"
disabled=""
>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0 0h24v24H0V0z"
fill="none"
/>
<path
d="M15.41 16.59L10.83 12l4.58-4.59L14 6l-6 6 6 6 1.41-1.41z"
/>
</svg>
<span>
Previous
</span>
</button>
<button
class="sc-dlniIP kLAzMx"
>
<span>
Next
</span>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0 0h24v24H0V0z"
fill="none"
/>
<path
d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"
/>
</svg>
</button>
</div>
</div>
</div>
</body>,
"container": <div>
<div
class="sc-bdnyFh kjuCvI"
>
<p>
Showing
1
to
5
of
<span>
10
</span>
results
</p>
<div
class="sc-gtsqUy gUbTlC"
>
<button
class="sc-dlniIP kLAzMx"
disabled=""
>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0 0h24v24H0V0z"
fill="none"
/>
<path
d="M15.41 16.59L10.83 12l4.58-4.59L14 6l-6 6 6 6 1.41-1.41z"
/>
</svg>
<span>
Previous
</span>
</button>
<button
class="sc-dlniIP kLAzMx"
>
<span>
Next
</span>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0 0h24v24H0V0z"
fill="none"
/>
<path
d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"
/>
</svg>
</button>
</div>
</div>
</div>,
"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],
}
`;
@@ -0,0 +1,44 @@
import { render, fireEvent, RenderResult } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
// Components
import Pagination from '.';
describe('Pagination', () => {
const count = 10;
let wrapper: RenderResult | null = null;
beforeEach(() => {
wrapper = render(
<BrowserRouter>
<Pagination count={count} />
</BrowserRouter>
);
});
test('Should render correctly', () => {
expect(wrapper).toMatchSnapshot();
});
test('Next button should be disable when in the last page', () => {
fireEvent.click(wrapper!.getByText('Next'));
expect(wrapper!.getByText('Next').closest('button')).toBeDisabled();
});
test('Previous button should not be disable when move to second page', () => {
fireEvent.click(wrapper!.getByText('Next'));
expect(wrapper!.getByText('Previous').closest('button')).not.toBeDisabled();
});
test('Previous button should be disabled when go back to the first page', () => {
// Navigate to the second page
fireEvent.click(wrapper!.getByText('Next'));
// Back to the first page
fireEvent.click(wrapper!.getByText('Previous'));
expect(wrapper!.getByText('Previous').closest('button')).toBeDisabled();
});
});
@@ -22,14 +22,18 @@ const Pagination = ({ count }: IPagination) => {
const totalPage = Math.ceil(count / DEFAULT_PAGE_SIZE); const totalPage = Math.ceil(count / DEFAULT_PAGE_SIZE);
const nextPage = () => { const nextPage = () => {
const next = currentPage === totalPage ? currentPage : currentPage + 1; const next = currentPage === totalPage
? currentPage
: currentPage + 1;
searchParams.set('page', next.toString()); searchParams.set('page', next.toString());
setSearchParams(searchParams); setSearchParams(searchParams);
}; };
const previousPage = () => { const previousPage = () => {
const previous = currentPage === 1 ? currentPage : currentPage - 1; const previous = currentPage === 1
? currentPage
: currentPage - 1;
searchParams.set('page', previous.toString()); searchParams.set('page', previous.toString());
setSearchParams(searchParams); setSearchParams(searchParams);
@@ -38,7 +42,9 @@ const Pagination = ({ count }: IPagination) => {
const fromIndex = (currentPage - 1) * DEFAULT_PAGE_SIZE + 1; const fromIndex = (currentPage - 1) * DEFAULT_PAGE_SIZE + 1;
const toIndex = const toIndex =
currentPage === totalPage ? count : currentPage * DEFAULT_PAGE_SIZE; currentPage === totalPage
? count
: currentPage * DEFAULT_PAGE_SIZE;
return ( return (
totalPage > 1 && ( totalPage > 1 && (
@@ -0,0 +1,78 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`RootLayout Should render correctly 1`] = `
{
"asFragment": [Function],
"baseElement": <body>
<div>
<div
class="sc-gtsqUy brPTv"
>
<div
class="sc-bdnyFh gtsksw"
/>
</div>
</div>
</body>,
"container": <div>
<div
class="sc-gtsqUy brPTv"
>
<div
class="sc-bdnyFh gtsksw"
/>
</div>
</div>,
"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],
}
`;
@@ -0,0 +1,19 @@
import { render } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
// Components
import RootLayout from '..';
describe('RootLayout', () => {
test('Should render correctly', () => {
const queryClient = new QueryClient();
const wrapper = render(
<QueryClientProvider client={queryClient}>
<RootLayout />
</QueryClientProvider>
);
expect(wrapper).toMatchSnapshot();
});
});
@@ -0,0 +1,62 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`RouteProtected Should render correctly 1`] = `
{
"asFragment": [Function],
"baseElement": <body>
<div />
</body>,
"container": <div />,
"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],
}
`;
@@ -0,0 +1,23 @@
import { render } from '@testing-library/react';
import RouteProtected from '..';
import AppLayout from '@component/AppLayout';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BrowserRouter } from 'react-router-dom';
describe('RouteProtected', () => {
test('Should render correctly', () => {
const queryClient = new QueryClient();
const wrapper = render(
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<RouteProtected>
<AppLayout />
</RouteProtected>
</BrowserRouter>
</QueryClientProvider>
);
expect(wrapper).toMatchSnapshot();
});
});
@@ -1,67 +1,42 @@
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter, useSearchParams } from 'react-router-dom';
import { useState } from 'react'; import { RenderResult, fireEvent, render } from '@testing-library/react';
// Components // Components
import Search from '.'; import Search from '.';
import {
RenderResult,
fireEvent,
render,
act,
} from '@testing-library/react';
let mockSearchParam = '';
jest.useFakeTimers();
jest.mock('react-router-dom', () => ({ jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'), ...jest.requireActual('react-router-dom'),
useSearchParams: () => { useSearchParams: jest.fn(),
const [params, setParams] = useState(new URLSearchParams(mockSearchParam)); }));
return [
params, jest.mock('@hook/useDebounce', () => ({
(newParams: string) => { useDebounce: jest.fn((value) => value),
mockSearchParam = newParams;
setParams(new URLSearchParams(newParams));
},
];
},
})); }));
describe('Search', () => { describe('Search', () => {
// const placeHolder = 'Search placeholder...'; const mockSearchParams = new URLSearchParams();
// let wrapper: RenderResult | null = null; (useSearchParams as jest.Mock).mockReturnValue([mockSearchParams, jest.fn()]);
let wrapper: RenderResult | null = null;
// beforeEach(() => { beforeEach(() => {
// wrapper = render( wrapper = render(
// <BrowserRouter> <BrowserRouter>
// <Search setPlaceHolder={placeHolder} /> <Search setPlaceHolder="Search" />
// </BrowserRouter> </BrowserRouter>
// );
// });
// 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(
<BrowserRouter>
<Search setPlaceHolder={'Search placeholder...'} />
</BrowserRouter>
);
});
const searchField = await wrapper!.findByPlaceholderText(
'Search placeholder...'
); );
});
act(() => { test('Should render correctly', () => {
fireEvent.change(searchField, { target: { value: 'abc' } }); expect(wrapper).toMatchSnapshot();
}); })
// jest.advanceTimersByTime(1000); test('updates searchParams on input change', () => {
const searchInput = wrapper!.getByPlaceholderText('Search');
// Type into the search input
fireEvent.change(searchInput, { target: { value: 'Search value' } });
// Expect searchParams to be updated
expect(mockSearchParams.get('search')).toBe('Search value');
}); });
}); });
@@ -0,0 +1,72 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Search Should render correctly 1`] = `
{
"asFragment": [Function],
"baseElement": <body>
<div>
<input
class="sc-bdnyFh fkeDFp"
placeholder="Search"
/>
</div>
</body>,
"container": <div>
<input
class="sc-bdnyFh fkeDFp"
placeholder="Search"
/>
</div>,
"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],
}
`;
@@ -1,4 +1,4 @@
import renderer from 'react-test-renderer'; import { render } from '@testing-library/react';
// Components // Components
import Select from '.'; import Select from '.';
@@ -11,13 +11,13 @@ describe('Select', () => {
}, },
{ {
label: 'Option 2', label: 'Option 2',
value: 'Value 2' value: 'Value 2',
} },
]; ];
const value = 'Temp value'; const value = 'Temp value';
const handleOnChange = jest.fn(); const handleOnChange = jest.fn();
const wrapper = renderer.create( const wrapper = render(
<Select <Select
options={options} options={options}
value={value} value={value}
@@ -1,24 +1,94 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Select Should render correctly 1`] = ` exports[`Select Should render correctly 1`] = `
<select {
aria-label="Sort" "asFragment": [Function],
className="sc-bdnyFh hPOEsG" "baseElement": <body>
disabled={false} <div>
onChange={[MockFunction]} <select
value="Temp value" aria-label="Sort"
> class="sc-bdnyFh hPOEsG"
<option >
data-testid="select-option" <option
value="Value 1" value="Value 1"
> >
Option 1 Option 1
</option> </option>
<option <option
data-testid="select-option" value="Value 2"
value="Value 2" >
> Option 2
Option 2 </option>
</option> </select>
</select> </div>
</body>,
"container": <div>
<select
aria-label="Sort"
class="sc-bdnyFh hPOEsG"
>
<option
value="Value 1"
>
Option 1
</option>
<option
value="Value 2"
>
Option 2
</option>
</select>
</div>,
"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],
}
`; `;
@@ -1,8 +1,4 @@
import { import { FieldValues, RegisterOptions, useFormContext } from 'react-hook-form';
FieldValues,
RegisterOptions,
useFormContext,
} from 'react-hook-form';
import { ChangeEventHandler } from 'react'; import { ChangeEventHandler } from 'react';
// Styled // Styled
@@ -46,7 +42,7 @@ const Select = ({
: { onChange: onChange })} : { onChange: onChange })}
> >
{options.map((option) => ( {options.map((option) => (
<option value={option.value} key={option.value} data-testid='select-option'> <option value={option.value} key={option.value}>
{option.label} {option.label}
</option> </option>
))} ))}
@@ -1,11 +1,17 @@
import renderer from 'react-test-renderer'; import { BrowserRouter, useNavigate } from 'react-router-dom';
import { BrowserRouter } from 'react-router-dom'; import { fireEvent, render } from '@testing-library/react';
// Components // Components
import Sidebar from '.'; import Sidebar from '.';
// Mock useNavigate hook
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: jest.fn(),
}));
describe('Sidebar', () => { describe('Sidebar', () => {
const wrapper = renderer.create( const wrapper = render(
<BrowserRouter> <BrowserRouter>
<Sidebar heading="Hotel Management" /> <Sidebar heading="Hotel Management" />
</BrowserRouter> </BrowserRouter>
@@ -14,4 +20,20 @@ describe('Sidebar', () => {
test('Should render correctly', () => { test('Should render correctly', () => {
expect(wrapper).toMatchSnapshot(); expect(wrapper).toMatchSnapshot();
}); });
test('On click to heading should be navigate', () => {
const mockNavigate = jest.fn();
(useNavigate as jest.Mock).mockReturnValue(mockNavigate);
const wrapper = render(
<BrowserRouter>
<Sidebar heading="Hotel Management" />
</BrowserRouter>
);
const headingElement = wrapper.getByText('Hotel Management');
fireEvent.click(headingElement);
expect(mockNavigate).toHaveBeenCalledWith('/');
});
}); });
@@ -1,100 +1,218 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Sidebar Should render correctly 1`] = ` exports[`Sidebar Should render correctly 1`] = `
<aside {
className="sc-dlniIP dfcuiS" "asFragment": [Function],
> "baseElement": <body>
<h1 <div>
className="sc-hKFymg OpLao" <aside
onClick={[Function]} class="sc-dlniIP dfcuiS"
>
Hotel Management
</h1>
<nav
className="sc-bdnyFh gGCifp"
>
<a
className="sc-gtsqUy gbSQWi"
href="/booking"
onClick={[Function]}
>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
strokeWidth="0"
style={
{
"color": undefined,
}
}
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
> >
<path <h1
d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM5 7h14v2H5V7z" class="sc-hKFymg OpLao"
/> >
</svg> Hotel Management
<span> </h1>
Booking <nav
</span> class="sc-bdnyFh gGCifp"
</a> >
<a <a
className="sc-gtsqUy gbSQWi" class="sc-gtsqUy gbSQWi"
href="/user" href="/booking"
onClick={[Function]} >
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM5 7h14v2H5V7z"
/>
</svg>
<span>
Booking
</span>
</a>
<a
class="sc-gtsqUy gbSQWi"
href="/user"
>
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.5 6.375a4.125 4.125 0 118.25 0 4.125 4.125 0 01-8.25 0zM14.25 8.625a3.375 3.375 0 116.75 0 3.375 3.375 0 01-6.75 0zM1.5 19.125a7.125 7.125 0 0114.25 0v.003l-.001.119a.75.75 0 01-.363.63 13.067 13.067 0 01-6.761 1.873c-2.472 0-4.786-.684-6.76-1.873a.75.75 0 01-.364-.63l-.001-.122zM17.25 19.128l-.001.144a2.25 2.25 0 01-.233.96 10.088 10.088 0 005.06-1.01.75.75 0 00.42-.643 4.875 4.875 0 00-6.957-4.611 8.586 8.586 0 011.71 5.157v.003z"
/>
</svg>
<span>
User
</span>
</a>
<a
class="sc-gtsqUy gbSQWi"
href="/room"
>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 16 16"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z"
/>
</svg>
<span>
Room
</span>
</a>
</nav>
</aside>
</div>
</body>,
"container": <div>
<aside
class="sc-dlniIP dfcuiS"
> >
<svg <h1
aria-hidden="true" class="sc-hKFymg OpLao"
fill="currentColor"
height="1em"
stroke="currentColor"
strokeWidth="0"
style={
{
"color": undefined,
}
}
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
> >
<path Hotel Management
d="M4.5 6.375a4.125 4.125 0 118.25 0 4.125 4.125 0 01-8.25 0zM14.25 8.625a3.375 3.375 0 116.75 0 3.375 3.375 0 01-6.75 0zM1.5 19.125a7.125 7.125 0 0114.25 0v.003l-.001.119a.75.75 0 01-.363.63 13.067 13.067 0 01-6.761 1.873c-2.472 0-4.786-.684-6.76-1.873a.75.75 0 01-.364-.63l-.001-.122zM17.25 19.128l-.001.144a2.25 2.25 0 01-.233.96 10.088 10.088 0 005.06-1.01.75.75 0 00.42-.643 4.875 4.875 0 00-6.957-4.611 8.586 8.586 0 011.71 5.157v.003z" </h1>
/> <nav
</svg> class="sc-bdnyFh gGCifp"
<span>
User
</span>
</a>
<a
className="sc-gtsqUy gbSQWi"
href="/room"
onClick={[Function]}
>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
strokeWidth="0"
style={
{
"color": undefined,
}
}
viewBox="0 0 16 16"
width="1em"
xmlns="http://www.w3.org/2000/svg"
> >
<path <a
d="M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z" class="sc-gtsqUy gbSQWi"
/> href="/booking"
</svg> >
<span> <svg
Room fill="currentColor"
</span> height="1em"
</a> stroke="currentColor"
</nav> stroke-width="0"
</aside> viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM5 7h14v2H5V7z"
/>
</svg>
<span>
Booking
</span>
</a>
<a
class="sc-gtsqUy gbSQWi"
href="/user"
>
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.5 6.375a4.125 4.125 0 118.25 0 4.125 4.125 0 01-8.25 0zM14.25 8.625a3.375 3.375 0 116.75 0 3.375 3.375 0 01-6.75 0zM1.5 19.125a7.125 7.125 0 0114.25 0v.003l-.001.119a.75.75 0 01-.363.63 13.067 13.067 0 01-6.761 1.873c-2.472 0-4.786-.684-6.76-1.873a.75.75 0 01-.364-.63l-.001-.122zM17.25 19.128l-.001.144a2.25 2.25 0 01-.233.96 10.088 10.088 0 005.06-1.01.75.75 0 00.42-.643 4.875 4.875 0 00-6.957-4.611 8.586 8.586 0 011.71 5.157v.003z"
/>
</svg>
<span>
User
</span>
</a>
<a
class="sc-gtsqUy gbSQWi"
href="/room"
>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 16 16"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z"
/>
</svg>
<span>
Room
</span>
</a>
</nav>
</aside>
</div>,
"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],
}
`; `;
@@ -1,6 +1,7 @@
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import { useState } from 'react'; import { useState } from 'react';
import { render, fireEvent, RenderResult } from '@testing-library/react'; import { render, fireEvent, RenderResult } from '@testing-library/react';
// Components // Components
import SortBy from '.'; import SortBy from '.';
@@ -10,13 +10,11 @@ exports[`SortBy Should render correctly 1`] = `
class="sc-bdnyFh hPOEsG" class="sc-bdnyFh hPOEsG"
> >
<option <option
data-testid="select-option"
value="Value1" value="Value1"
> >
Option 1 Option 1
</option> </option>
<option <option
data-testid="select-option"
value="Value2" value="Value2"
> >
Option 2 Option 2
@@ -30,13 +28,11 @@ exports[`SortBy Should render correctly 1`] = `
class="sc-bdnyFh hPOEsG" class="sc-bdnyFh hPOEsG"
> >
<option <option
data-testid="select-option"
value="Value1" value="Value1"
> >
Option 1 Option 1
</option> </option>
<option <option
data-testid="select-option"
value="Value2" value="Value2"
> >
Option 2 Option 2
@@ -1,4 +1,4 @@
import renderer from 'react-test-renderer'; import { render } from '@testing-library/react';
// Components // Components
import Table from '.'; import Table from '.';
@@ -29,7 +29,12 @@ describe('Table', () => {
}, },
]; ];
const TableRow = ({ user }: ITableRow) => { const TableRow = ({ user }: ITableRow) => {
const { id, name, phone, isBooked } = user; const {
id,
name,
phone,
isBooked
} = user;
return ( return (
<Table.Row> <Table.Row>
@@ -42,7 +47,7 @@ describe('Table', () => {
}; };
const renderRow = (user: IUser) => <TableRow user={user} key={user.id} />; const renderRow = (user: IUser) => <TableRow user={user} key={user.id} />;
const wrapper = renderer.create( const wrapper = render(
<Table columns="10% 35% 30% 15% 10%"> <Table columns="10% 35% 30% 15% 10%">
<Table.Header headerColumn={columnName} /> <Table.Header headerColumn={columnName} />
<Table.Body<IUser> data={tempUser} render={renderRow} /> <Table.Body<IUser> data={tempUser} render={renderRow} />
@@ -1,53 +1,162 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Table Should render correctly 1`] = ` exports[`Table Should render correctly 1`] = `
<div {
className="sc-bdnyFh eEibLN" "asFragment": [Function],
> "baseElement": <body>
<div
className="sc-gtsqUy sc-eCAqax eucOOU hcIWQg"
columns="10% 35% 30% 15% 10%"
>
<div> <div>
Column 1 <div
class="sc-bdnyFh eEibLN"
>
<div
class="sc-gtsqUy sc-eCAqax eucOOU hcIWQg"
columns="10% 35% 30% 15% 10%"
>
<div>
Column 1
</div>
<div>
Column 2
</div>
</div>
<div
class="sc-dlniIP EYkDq"
>
<div
class="sc-gtsqUy sc-hKFymg eucOOU jwwTFT"
columns="10% 35% 30% 15% 10%"
>
<div>
1
</div>
<div>
Nezumi
</div>
<div>
123
</div>
<div />
</div>
<div
class="sc-gtsqUy sc-hKFymg eucOOU jwwTFT"
columns="10% 35% 30% 15% 10%"
>
<div>
2
</div>
<div>
Loi Phan
</div>
<div>
453
</div>
<div />
</div>
</div>
</div>
</div> </div>
<div> </body>,
Column 2 "container": <div>
</div>
</div>
<div
className="sc-dlniIP EYkDq"
>
<div <div
className="sc-gtsqUy sc-hKFymg eucOOU jwwTFT" class="sc-bdnyFh eEibLN"
columns="10% 35% 30% 15% 10%"
> >
<div> <div
1 class="sc-gtsqUy sc-eCAqax eucOOU hcIWQg"
columns="10% 35% 30% 15% 10%"
>
<div>
Column 1
</div>
<div>
Column 2
</div>
</div> </div>
<div> <div
Nezumi class="sc-dlniIP EYkDq"
>
<div
class="sc-gtsqUy sc-hKFymg eucOOU jwwTFT"
columns="10% 35% 30% 15% 10%"
>
<div>
1
</div>
<div>
Nezumi
</div>
<div>
123
</div>
<div />
</div>
<div
class="sc-gtsqUy sc-hKFymg eucOOU jwwTFT"
columns="10% 35% 30% 15% 10%"
>
<div>
2
</div>
<div>
Loi Phan
</div>
<div>
453
</div>
<div />
</div>
</div> </div>
<div>
123
</div>
<div />
</div> </div>
<div </div>,
className="sc-gtsqUy sc-hKFymg eucOOU jwwTFT" "debug": [Function],
columns="10% 35% 30% 15% 10%" "findAllByAltText": [Function],
> "findAllByDisplayValue": [Function],
<div> "findAllByLabelText": [Function],
2 "findAllByPlaceholderText": [Function],
</div> "findAllByRole": [Function],
<div> "findAllByTestId": [Function],
Loi Phan "findAllByText": [Function],
</div> "findAllByTitle": [Function],
<div> "findByAltText": [Function],
453 "findByDisplayValue": [Function],
</div> "findByLabelText": [Function],
<div /> "findByPlaceholderText": [Function],
</div> "findByRole": [Function],
</div> "findByTestId": [Function],
</div> "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],
}
`; `;
@@ -1,10 +1,10 @@
import renderer from 'react-test-renderer'; import { render } from '@testing-library/react';
// Components // Components
import Toast from '.'; import Toast from '.';
describe('Toast', () => { describe('Toast', () => {
const wrapper = renderer.create(<Toast />); const wrapper = render(<Toast />);
test('Should render correctly', () => { test('Should render correctly', () => {
expect(wrapper).toMatchSnapshot(); expect(wrapper).toMatchSnapshot();
@@ -1,20 +1,70 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Toast Should render correctly 1`] = ` exports[`Toast Should render correctly 1`] = `
<div {
onMouseEnter={[Function]} "asFragment": [Function],
onMouseLeave={[Function]} "baseElement": <body>
style={ <div>
{ <div
"bottom": 16, style="position: fixed; z-index: 2000; top: 16px; left: 16px; right: 16px; bottom: 16px; pointer-events: none; margin: 8px;"
"left": 16, />
"margin": "8px", </div>
"pointerEvents": "none", </body>,
"position": "fixed", "container": <div>
"right": 16, <div
"top": 16, style="position: fixed; z-index: 2000; top: 16px; left: 16px; right: 16px; bottom: 16px; pointer-events: none; margin: 8px;"
"zIndex": 2000, />
} </div>,
} "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],
}
`; `;
+7 -1
View File
@@ -59,4 +59,10 @@ const REGEX = {
PASSWORD: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$@!%&*?])[A-Za-z\d#$@!%&*?]{8,16}$/ PASSWORD: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$@!%&*?])[A-Za-z\d#$@!%&*?]{8,16}$/
}; };
export { USER_PAGE, ROOM_PAGE, FORM, REGEX, ORDERBY_OPTIONS }; export {
USER_PAGE,
ROOM_PAGE,
FORM,
REGEX,
ORDERBY_OPTIONS
};
@@ -6,7 +6,7 @@ const PASSWORD_CONDITION =
'Your password must have 1 uppercase, 1 lowercase, 1 special character, min 1 number and the length between from 8 to 16!'; 'Your password must have 1 uppercase, 1 lowercase, 1 special character, min 1 number and the length between from 8 to 16!';
const INVALID_PASSWORD = 'Invalid password'; const INVALID_PASSWORD = 'Invalid password';
const PASSWORD_NOT_MATCH = 'Password not match!'; const PASSWORD_NOT_MATCH = 'Password not match!';
const PASSWORD_NOT_MATCH_REQUIREMENT = 'Password not match the requirement!' const PASSWORD_NOT_MATCH_REQUIREMENT = 'Password not match the requirement!';
export { export {
REQUIRED_FIELD_ERROR, REQUIRED_FIELD_ERROR,
@@ -16,5 +16,5 @@ export {
PASSWORD_CONDITION, PASSWORD_CONDITION,
INVALID_PASSWORD, INVALID_PASSWORD,
PASSWORD_NOT_MATCH, PASSWORD_NOT_MATCH,
PASSWORD_NOT_MATCH_REQUIREMENT PASSWORD_NOT_MATCH_REQUIREMENT,
}; };
+15 -8
View File
@@ -1,8 +1,15 @@
export const BOOKING = '/booking'; const BOOKING = '/booking';
export const USER = '/user'; const USER = '/user';
export const ROOM = '/room'; const ROOM = '/room';
export const ACCOUNT = '/account'; const ACCOUNT = '/account';
export const OTHER_PATH = '*'; const OTHER_PATH = '*';
export const USER_PATH = 'users'; const LOGIN = 'login';
export const ROOM_PATH = 'rooms';
export const LOGIN = 'login'; export {
BOOKING,
USER,
ROOM,
ACCOUNT,
OTHER_PATH,
LOGIN,
}
@@ -40,18 +40,20 @@ const initialState: IUserRoomState = {
const reducer = (state: IUserRoomState, action: IAction) => { const reducer = (state: IUserRoomState, action: IAction) => {
switch (action.type) { switch (action.type) {
case 'initRoom': // Init data for the first load
return {
...state,
roomsAvailable: action.payload,
};
case 'initUser': case 'initUser':
return { return {
...state, ...state,
usersAvailable: action.payload, usersAvailable: action.payload,
}; };
case 'initRoom':
return {
...state,
roomsAvailable: action.payload,
};
// Add data to state
case 'addUser': { case 'addUser': {
const tempArr = state.usersAvailable; const tempArr = state.usersAvailable;
const itemExist = state.usersAvailable.find( const itemExist = state.usersAvailable.find(
@@ -68,6 +70,23 @@ const reducer = (state: IUserRoomState, action: IAction) => {
}; };
} }
case 'addRoom': {
const tempArr = state.roomsAvailable;
const itemExist = state.roomsAvailable.find(
(item) => item.id === action.payload[0].id
);
if (!itemExist) {
tempArr.push(action.payload[0]);
}
return {
...state,
roomsAvailable: tempArr,
};
}
// Update state
case 'updateUserName': { case 'updateUserName': {
const tempArr = state.usersAvailable; const tempArr = state.usersAvailable;
@@ -85,41 +104,6 @@ const reducer = (state: IUserRoomState, action: IAction) => {
}; };
} }
case 'updateStatusUser': {
const tempArr = state.usersAvailable;
const indexItemUpdate = tempArr.findIndex(
(item) => item.id === action.payload[0].id
);
tempArr[indexItemUpdate].isBooked = action.payload[0].isBooked;
return {
...state,
usersAvailable: tempArr,
};
}
case 'removeUser':
return {
...state,
usersAvailable: state.usersAvailable.filter((user) => user.id !== action.payload[0].id)
}
case 'addRoom': {
const tempArr = state.roomsAvailable;
const itemExist = state.roomsAvailable.find(
(item) => item.id === action.payload[0].id
);
if (!itemExist) {
tempArr.push(action.payload[0]);
}
return {
...state,
roomsAvailable: tempArr,
};
}
case 'updateRoomName': { case 'updateRoomName': {
const tempArr = state.roomsAvailable; const tempArr = state.roomsAvailable;
@@ -137,6 +121,19 @@ const reducer = (state: IUserRoomState, action: IAction) => {
}; };
} }
case 'updateStatusUser': {
const tempArr = state.usersAvailable;
const indexItemUpdate = tempArr.findIndex(
(item) => item.id === action.payload[0].id
);
tempArr[indexItemUpdate].isBooked = action.payload[0].isBooked;
return {
...state,
usersAvailable: tempArr,
};
}
case 'updateStatusRoom': { case 'updateStatusRoom': {
const tempArr = state.roomsAvailable; const tempArr = state.roomsAvailable;
const indexItemUpdate = tempArr.findIndex( const indexItemUpdate = tempArr.findIndex(
@@ -150,11 +147,22 @@ const reducer = (state: IUserRoomState, action: IAction) => {
}; };
} }
case 'removeRoom': // Remove state
case 'removeUser':
return { return {
...state, ...state,
roomsAvailable: state.roomsAvailable.filter((room) => room.id !== action.payload[0].id) usersAvailable: state.usersAvailable.filter(
} (user) => user.id !== action.payload[0].id
),
};
case 'removeRoom':
return {
...state,
roomsAvailable: state.roomsAvailable.filter(
(room) => room.id !== action.payload[0].id
),
};
default: default:
throw new Error('Action unknown'); throw new Error('Action unknown');
@@ -1,4 +1,7 @@
// Contexts
import { reducer } from '@context/UserRoomAvailableContext'; import { reducer } from '@context/UserRoomAvailableContext';
// Types
import { IDataState } from '@type/common'; import { IDataState } from '@type/common';
jest.mock('@service/userServices'); jest.mock('@service/userServices');
@@ -38,12 +41,14 @@ describe('userRoomAvailableContext', () => {
{ {
id: 1, id: 1,
name: 'Room 1', name: 'Room 1',
status: true,
}, },
], ],
usersAvailable: [ usersAvailable: [
{ {
id: 1, id: 1,
name: 'Nezumi', name: 'Nezumi',
isBooked: true,
}, },
], ],
}; };
@@ -84,7 +89,8 @@ describe('userRoomAvailableContext', () => {
expect(state.usersAvailable[0]).toEqual({ expect(state.usersAvailable[0]).toEqual({
id: 1, id: 1,
name: 'Update name' name: 'Update name',
isBooked: true,
}); });
}); });
@@ -123,7 +129,34 @@ describe('userRoomAvailableContext', () => {
expect(state.roomsAvailable[0]).toEqual({ expect(state.roomsAvailable[0]).toEqual({
id: 1, id: 1,
name: 'Update name' name: 'Update name',
status: true,
});
});
test('Should update room status correctly', async () => {
const state = reducer(initialState, {
type: 'updateStatusRoom',
payload: [{ id: 1, status: false }],
});
expect(state.roomsAvailable[0]).toEqual({
id: 1,
name: 'Room 1',
status: false,
});
});
test('Should update user status correctly', async () => {
const state = reducer(initialState, {
type: 'updateStatusUser',
payload: [{ id: 1, isBooked: false }],
});
expect(state.usersAvailable[0]).toEqual({
id: 1,
name: 'Nezumi',
isBooked: false,
}); });
}); });
}); });
@@ -1,5 +1,5 @@
// Helpers // Helpers
import { formatCurrency } from '@helper/helper'; import { formatCurrency, getDayDiff } from '@helper/helper';
describe('formatCurrency', () => { describe('formatCurrency', () => {
test('Should format correctly', () => { test('Should format correctly', () => {
@@ -8,3 +8,21 @@ describe('formatCurrency', () => {
expect(result).toEqual('$5,000.00'); expect(result).toEqual('$5,000.00');
}); });
}); });
describe('getDayDiff', () => {
test('Should calculate correctly', () => {
const case_1 = getDayDiff(new Date('2023/11/30'), new Date('2023/12/01'));
const case_2 = getDayDiff(new Date('2023/12/15'), new Date('2023/12/20'));
const case_3 = getDayDiff(new Date('2023/12/31'), new Date('2024/01/01'));
expect(case_1).toEqual(1);
expect(case_2).toEqual(5);
expect(case_3).toEqual(1);
});
test('Should return 0 if startDate larger than endDate', () => {
const result = getDayDiff(new Date('2023/11/30'), new Date('2023/11/20'));
expect(result).toEqual(0);
});
});
@@ -3,6 +3,7 @@ import { REGEX } from '@constant/commons';
// Helpers // Helpers
import { import {
compareTwoDates,
isValidDiscount, isValidDiscount,
isValidRegex, isValidRegex,
isValidString, isValidString,
@@ -88,3 +89,23 @@ describe('Should is valid string', () => {
expect(case_4).toBeFalsy(); expect(case_4).toBeFalsy();
}); });
}); });
describe('Should compare two dates correctly', () => {
test('The start date should greater than end date', () => {
const result = compareTwoDates(
new Date('2023/12/05'),
new Date('2023/12/01')
);
expect(result).toBe(true);
});
test('The start date should fewer than end date', () => {
const result = compareTwoDates(
new Date('2023/12/01'),
new Date('2023/12/05')
);
expect(result).toBe(false);
});
});
+6 -12
View File
@@ -20,22 +20,16 @@ const formatCurrency = (value: number): string => {
const getDayDiff = (startDate: Date, endDate: Date): number => { const getDayDiff = (startDate: Date, endDate: Date): number => {
const msInDay = 24 * 60 * 60 * 1000; const msInDay = 24 * 60 * 60 * 1000;
return Math.round( if(endDate > startDate) {
Math.abs(Number(endDate) - Number(startDate)) / msInDay return Math.round(
); Math.abs(Number(endDate) - Number(startDate)) / msInDay
} );
}
/** return 0;
* Convert from currency string to the number
* @param currency The currency string
* @returns The number
*/
const convertCurrencyToNumber = (currency: string) => {
return Number(currency.replace(/[^0-9.-]+/g,""))
} }
export { export {
formatCurrency, formatCurrency,
getDayDiff, getDayDiff,
convertCurrencyToNumber
}; };
@@ -12,10 +12,11 @@ import { useSetIsDeleteRoom } from '@hook/rooms/useSetIsDeleteRoom';
// Types // Types
import { IRoom } from '@type/room'; import { IRoom } from '@type/room';
const mockUseRooms = jest.fn(useRooms); jest.mock('@hook/rooms/useRooms');
const mockUseCreateRoom = jest.fn(useCreateRoom); jest.mock('@hook/rooms/useCreateRoom');
const mockUseUpdateRoom = jest.fn(useUpdateRoom); jest.mock('@hook/rooms/useUpdateRoom');
const mockUseDeleteRoom = jest.fn(useSetIsDeleteRoom); jest.mock('@hook/rooms/useSetIsDeleteRoom');
interface IWrapper { interface IWrapper {
children: ReactNode; children: ReactNode;
} }
@@ -27,24 +28,26 @@ const sampleData: IRoom = {
status: true, status: true,
isDelete: true, isDelete: true,
}; };
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
const wrapper = ({ children }: IWrapper) => {
return (
<QueryClientProvider client={queryClient}>
<MemoryRouter>{children}</MemoryRouter>
</QueryClientProvider>
);
};
describe('Room hooks', () => { describe('Room hooks', () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
const wrapper = ({ children }: IWrapper) => {
return (
<QueryClientProvider client={queryClient}>
<MemoryRouter>{children}</MemoryRouter>
</QueryClientProvider>
);
};
test('Should fetch data correctly', async () => { test('Should fetch data correctly', async () => {
mockUseRooms.mockImplementation(() => ({ (useRooms as jest.Mock).mockImplementation(() => ({
rooms: [ rooms: [
{ {
id: 1, id: 1,
@@ -64,7 +67,7 @@ describe('Room hooks', () => {
isLoading: false, isLoading: false,
count: 2 count: 2
})); }));
const { result } = renderHook(() => mockUseRooms(), { wrapper }); const { result } = renderHook(() => useRooms(), { wrapper });
await waitFor(() => await waitFor(() =>
expect(result.current.rooms?.length).toBeGreaterThan(0) expect(result.current.rooms?.length).toBeGreaterThan(0)
@@ -72,14 +75,14 @@ describe('Room hooks', () => {
}); });
test('Should create room correctly', async () => { test('Should create room correctly', async () => {
mockUseCreateRoom.mockImplementation(() => ({ (useCreateRoom as jest.Mock).mockImplementation(() => ({
createRoom: () => { createRoom: () => {
sampleData; sampleData;
}, },
isCreating: false, isCreating: false,
isSuccess: true, isSuccess: true,
})); }));
const { result } = renderHook(() => mockUseCreateRoom(), { wrapper }); const { result } = renderHook(() => useCreateRoom(), { wrapper });
act(() => { act(() => {
result.current.createRoom(sampleData); result.current.createRoom(sampleData);
@@ -91,14 +94,14 @@ describe('Room hooks', () => {
}); });
test('Should edit room correctly', async () => { test('Should edit room correctly', async () => {
mockUseUpdateRoom.mockImplementation(() => ({ (useUpdateRoom as jest.Mock).mockImplementation(() => ({
updateRoom: () => { updateRoom: () => {
sampleData; sampleData;
}, },
isUpdating: false, isUpdating: false,
isSuccess: true, isSuccess: true,
})); }));
const { result } = renderHook(() => mockUseUpdateRoom(), { wrapper }); const { result } = renderHook(() => useUpdateRoom(), { wrapper });
act(() => { act(() => {
const testMethod = async () => { const testMethod = async () => {
@@ -111,14 +114,14 @@ describe('Room hooks', () => {
}); });
test('Should delete room correctly', async () => { test('Should delete room correctly', async () => {
mockUseDeleteRoom.mockImplementation(() => ({ (useSetIsDeleteRoom as jest.Mock).mockImplementation(() => ({
setIsDeleteRoom: () => { setIsDeleteRoom: () => {
sampleData sampleData
}, },
isDeleting: false, isDeleting: false,
isSuccess: true, isSuccess: true,
})); }));
const { result } = renderHook(() => mockUseDeleteRoom(), { wrapper }); const { result } = renderHook(() => useSetIsDeleteRoom(), { wrapper });
act(() => { act(() => {
const testMethod = async () => { const testMethod = async () => {
@@ -1,6 +1,5 @@
import { fireEvent, render } from '@testing-library/react'; import { act, fireEvent, render } from '@testing-library/react';
import { useState } from 'react'; import { useState } from 'react';
import { act } from 'react-test-renderer';
// Hooks // Hooks
import { useDebounce } from '@hook/useDebounce'; import { useDebounce } from '@hook/useDebounce';
@@ -5,7 +5,6 @@ import { useOutsideClick } from '@hook/useOutsideClick';
describe('useOutsideClick', () => { describe('useOutsideClick', () => {
test('Call handler when click outside element', () => { test('Call handler when click outside element', () => {
// Arrange
const handler = jest.fn(); const handler = jest.fn();
const ref = renderHook(() => useOutsideClick<HTMLDivElement>(handler)) const ref = renderHook(() => useOutsideClick<HTMLDivElement>(handler))
.result.current; .result.current;
@@ -13,21 +12,17 @@ describe('useOutsideClick', () => {
fireEvent.click(document); fireEvent.click(document);
// Assert
expect(handler).toHaveBeenCalledTimes(1); expect(handler).toHaveBeenCalledTimes(1);
}); });
test('Not call handler when click outside element', () => { test('Not call handler when click outside element', () => {
// Arrange
const handler = jest.fn(); const handler = jest.fn();
const ref = renderHook(() => useOutsideClick<HTMLDivElement>(handler)) const ref = renderHook(() => useOutsideClick<HTMLDivElement>(handler))
.result.current; .result.current;
render(<div ref={ref} data-testid="test-element"></div>); render(<div ref={ref} data-testid="test-element"></div>);
// Act
fireEvent.click(screen.getByTestId('test-element')); fireEvent.click(screen.getByTestId('test-element'));
// Assert
expect(handler).not.toHaveBeenCalled(); expect(handler).not.toHaveBeenCalled();
}); });
}); });
@@ -1,8 +1,7 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { renderHook, waitFor } from '@testing-library/react'; import { act, renderHook, waitFor } from '@testing-library/react';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { act } from 'react-test-renderer';
// Hooks // Hooks
import { useCreateUser } from '@hook/users/useCreateUser'; import { useCreateUser } from '@hook/users/useCreateUser';
@@ -12,9 +11,9 @@ import { useUsers } from '@hook/users/useUsers';
// Types // Types
import { IUser } from '@type/user'; import { IUser } from '@type/user';
const mockUseUsers = jest.fn(useUsers); jest.mock('@hook/users/useUsers');
const mockUseCreateUser = jest.fn(useCreateUser); jest.mock('@hook/users/useCreateUser');
const mockUseUpdateUser = jest.fn(useUpdateUser); jest.mock('@hook/users/useUpdateUser');
interface IWrapper { interface IWrapper {
children: ReactNode; children: ReactNode;
@@ -44,7 +43,7 @@ const wrapper = ({ children }: IWrapper) => {
describe('Users hook', () => { describe('Users hook', () => {
test('Should fetch user data correctly', async () => { test('Should fetch user data correctly', async () => {
mockUseUsers.mockImplementation(() => ({ (useUsers as jest.Mock).mockImplementation(() => ({
users: [ users: [
{ {
id: 1, id: 1,
@@ -64,20 +63,20 @@ describe('Users hook', () => {
isLoading: false, isLoading: false,
count: 2, count: 2,
})); }));
const { result } = renderHook(() => mockUseUsers(), { wrapper }); const { result } = renderHook(() => useUsers(), { wrapper });
await waitFor(() => expect(result.current.users?.length).toEqual(2)); await waitFor(() => expect(result.current.users?.length).toEqual(2));
}); });
test('Should create user correctly', async () => { test('Should create user correctly', async () => {
mockUseCreateUser.mockImplementation(() => ({ (useCreateUser as jest.Mock).mockImplementation(() => ({
createUser: () => { createUser: () => {
sampleData; sampleData;
}, },
isCreating: false, isCreating: false,
isSuccess: true, isSuccess: true,
})); }));
const { result } = renderHook(() => mockUseCreateUser(), { wrapper }); const { result } = renderHook(() => useCreateUser(), { wrapper });
act(() => { act(() => {
const testMethod = async () => { const testMethod = async () => {
@@ -90,14 +89,14 @@ describe('Users hook', () => {
}); });
test('Should update user correctly', async () => { test('Should update user correctly', async () => {
mockUseUpdateUser.mockImplementation(() => ({ (useUpdateUser as jest.Mock).mockImplementation(() => ({
updateUser: () => { updateUser: () => {
sampleData; sampleData;
}, },
isUpdating: false, isUpdating: false,
isSuccess: true, isSuccess: true,
})); }));
const { result } = renderHook(() => mockUseUpdateUser(), { wrapper }); const { result } = renderHook(() => useUpdateUser(), { wrapper });
act(() => { act(() => {
const testMethod = async () => { const testMethod = async () => {
@@ -0,0 +1,39 @@
import { useQuery } from '@tanstack/react-query';
import { renderHook } from '@testing-library/react';
import { User } from '@supabase/supabase-js';
// Services
import * as authenticationService from '@service/authenticationService';
// Hooks
import { useAccount } from '../useAccount';
jest.mock('@tanstack/react-query');
describe('useAccount', () => {
test('Should return the value correctly', async () => {
const mockAccount: User = {
role: 'authenticated',
app_metadata: jest.fn(),
id: '1',
user_metadata: jest.fn(),
aud: '',
created_at: '',
};
(useQuery as jest.Mock).mockReturnValue({
data: mockAccount,
isPending: false,
});
jest
.spyOn(authenticationService, 'getCurrentAccount')
.mockResolvedValue(mockAccount);
const { result } = renderHook(() => useAccount());
expect(result.current.isPending).toBe(false);
expect(result.current.account).toBe(mockAccount);
expect(result.current.isAuthenticated).toBe(true);
});
});
@@ -0,0 +1,73 @@
import {
QueryClient,
QueryClientProvider,
useMutation,
} from '@tanstack/react-query';
import { renderHook } from '@testing-library/react';
import { MemoryRouter, useNavigate } from 'react-router-dom';
import { ReactNode } from 'react';
// Hooks
import { useLogin } from '../useLogin';
interface IWrapper {
children: ReactNode;
}
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useMutation: jest.fn(),
}));
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: jest.fn(),
}));
describe('useLogin', () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
const env = ({ children }: IWrapper) => {
return (
<QueryClientProvider client={queryClient}>
<MemoryRouter>{children}</MemoryRouter>
</QueryClientProvider>
);
};
test('OnSuccess should call correctly', async () => {
(useMutation as jest.Mock).mockImplementation(({ onSuccess }) => {
const result = { mutate: jest.fn(), isPending: false };
onSuccess({ user: 'tempUser' });
return result;
});
const navigateMock = jest.fn();
(useNavigate as jest.Mock).mockReturnValue(navigateMock);
renderHook(() => useLogin(), { wrapper: env });
expect(navigateMock).toHaveBeenCalledWith('/');
});
test('OnError should call correctly', async () => {
(useMutation as jest.Mock).mockImplementation(({ onError }) => {
const result = { mutate: jest.fn(), isPending: false };
onError(new Error('This is error'));
return result;
});
renderHook(() => useLogin(), { wrapper: env });
expect(useMutation).toHaveBeenCalled();
});
});
@@ -0,0 +1,65 @@
import {
QueryClient,
QueryClientProvider,
useMutation,
} from '@tanstack/react-query';
import { act, renderHook } from '@testing-library/react';
import { ReactNode } from 'react';
import { MemoryRouter, useNavigate } from 'react-router-dom';
// Hooks
import { useLogout } from '../useLogout';
interface IWrapper {
children: ReactNode;
}
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useMutation: jest.fn(),
}));
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: jest.fn(),
}));
describe('useLogout', () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
const env = ({ children }: IWrapper) => {
return (
<QueryClientProvider client={queryClient}>
<MemoryRouter>{children}</MemoryRouter>
</QueryClientProvider>
);
};
test('Should logout successful', async () => {
(useMutation as jest.Mock).mockImplementation(({ onSuccess }) => {
const result = { mutate: jest.fn(), isPending: false };
onSuccess(); // Simulate a successful logout
return result;
});
const navigateMock = jest.fn();
(useNavigate as jest.Mock).mockReturnValue(navigateMock);
const { result } = renderHook(() => useLogout(), { wrapper: env });
// Call the logout function
await act(async () => {
result.current.logout();
});
// Assert that navigate has been called with the correct arguments
expect(navigateMock).toHaveBeenCalledWith('/login', { replace: true });
});
});
@@ -0,0 +1,69 @@
import {
QueryClient,
QueryClientProvider,
useMutation,
} from '@tanstack/react-query';
import { renderHook } from '@testing-library/react';
import { MemoryRouter, useNavigate } from 'react-router-dom';
import { ReactNode } from 'react';
// Hooks
import { useUpdateAccount } from '../useUpdateAccount';
interface IWrapper {
children: ReactNode;
}
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useMutation: jest.fn(),
}));
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: jest.fn(),
}));
describe('useUpdateAccount', () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
const env = ({ children }: IWrapper) => {
return (
<QueryClientProvider client={queryClient}>
<MemoryRouter>{children}</MemoryRouter>
</QueryClientProvider>
);
};
test('OnSuccess should call correctly', async () => {
(useMutation as jest.Mock).mockImplementation(({ onSuccess }) => {
const action = { mutate: jest.fn(), isUpdating: false };
onSuccess({ user: 'tempUser' });
return action;
});
const navigateMock = jest.fn();
(useNavigate as jest.Mock).mockReturnValue(navigateMock);
renderHook(() => useUpdateAccount(), { wrapper: env });
});
test('OnError should call correctly', async () => {
(useMutation as jest.Mock).mockImplementation(({ onError }) => {
const action = { mutate: jest.fn(), isUpdating: false };
onError(new Error('This is error'));
return action;
});
renderHook(() => useUpdateAccount(), { wrapper: env });
});
});
@@ -1,13 +1,10 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useNavigate, useSearchParams } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import toast from 'react-hot-toast'; import toast from 'react-hot-toast';
// Services // Services
import { login as loginFn } from '@service/authenticationService'; import { login as loginFn } from '@service/authenticationService';
// Types
import { ILogin } from '@type/common';
/** /**
* Login web * Login web
* @returns The login function and isPending boolean * @returns The login function and isPending boolean
@@ -15,16 +12,13 @@ import { ILogin } from '@type/common';
const useLogin = () => { const useLogin = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const navigate = useNavigate(); const navigate = useNavigate();
const [searchParams] = useSearchParams();
const redirectTo = searchParams.get('redirectTo') || null;
const { mutate: login, isPending } = useMutation({ const { mutate: login, isPending } = useMutation({
mutationFn: ({ email, password }: ILogin) => loginFn({ email, password }), mutationFn: loginFn,
onSuccess: (account) => { onSuccess: (account) => {
queryClient.setQueryData(['account'], account.user); queryClient.setQueryData(['account'], account.user);
redirectTo
? navigate(redirectTo) navigate('/');
: navigate('/');
}, },
onError: (err) => { onError: (err) => {
console.error(err.message); console.error(err.message);
@@ -0,0 +1,148 @@
import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/react-query';
import { useSearchParams } from 'react-router-dom';
import { renderHook } from '@testing-library/react';
import { URLSearchParams } from 'url';
// Hooks
import { useBookings } from '../useBookings';
// Services
import { getAllBookings } from '@service/bookingServices';
jest.mock('react-router-dom', () => ({
useSearchParams: jest.fn(),
}));
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useQuery: jest.fn(),
}));
jest.mock('@service/bookingServices', () => ({
getAllBookings: jest.fn(),
}));
describe('useBookings hook', () => {
const queryClient = new QueryClient();
beforeEach(() => {
jest.clearAllMocks();
});
test('Should fetch data successful', async () => {
const sampleDate = { data: [{ id: 1, name: 'Booking 1' }], count: 3 };
(useSearchParams as jest.Mock).mockReturnValue([
new URLSearchParams('page=1'),
new URLSearchParams('search=test'),
]);
(useQuery as jest.Mock).mockImplementation(({ queryFn }) => {
const result = {
isLoading: false,
error: {},
data: sampleDate,
};
queryFn();
return result;
});
(getAllBookings as jest.Mock).mockResolvedValue(sampleDate);
const { result } = renderHook(() => useBookings(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
),
});
expect(result.current.bookings).toEqual(sampleDate.data);
expect(result.current.count).toEqual(sampleDate.count);
});
test('Should prefetch the second page when in the first page', async () => {
const sampleDate = { data: [{ id: 1, name: 'Booking 1' }], count: 7 };
(queryClient.prefetchQuery as jest.Mock) = jest.fn();
(useSearchParams as jest.Mock).mockReturnValue([
new URLSearchParams('page=1'),
new URLSearchParams('search=test'),
]);
(useQuery as jest.Mock).mockImplementation(({ queryFn }) => {
const result = {
isLoading: false,
error: {},
data: sampleDate,
};
queryFn();
return result;
});
(getAllBookings as jest.Mock).mockResolvedValue(sampleDate);
renderHook(() => useBookings(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
),
});
expect(queryClient.prefetchQuery).toHaveBeenCalledTimes(1);
expect(queryClient.prefetchQuery).toHaveBeenCalledWith({
queryKey: ['bookings', '', 2],
queryFn: expect.any(Function),
});
});
test('Should prefetch the previous page and next page when in the second page', async () => {
const sampleDate = { data: [{ id: 1, name: 'Booking 1' }], count: 12 };
(useSearchParams as jest.Mock).mockReturnValue([
new URLSearchParams('page=2'),
new URLSearchParams('search=test'),
]);
(useQuery as jest.Mock).mockImplementation(({ queryFn }) => {
const result = {
isLoading: false,
error: {},
data: sampleDate,
};
queryFn();
return result;
});
(getAllBookings as jest.Mock).mockResolvedValue(sampleDate);
renderHook(() => useBookings(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
),
});
expect(queryClient.prefetchQuery).toHaveBeenCalledTimes(2);
expect(queryClient.prefetchQuery).toHaveBeenCalledWith({
queryKey: ['bookings', '', 3],
queryFn: expect.any(Function),
});
expect(queryClient.prefetchQuery).toHaveBeenCalledWith({
queryKey: ['bookings', '', 1],
queryFn: expect.any(Function),
});
});
});
@@ -0,0 +1,104 @@
import {
QueryClient,
QueryClientProvider,
useQueryClient,
} from '@tanstack/react-query';
import toast from 'react-hot-toast';
import useCheckOut from '../useCheckout';
import { act, renderHook } from '@testing-library/react';
// Services
import { checkOutBooking } from '@service/bookingServices';
// Hooks
import { useUserRoomAvailable } from '@hook/useUserRoomAvailable';
// Constants
import { CHECKOUT_SUCCESS } from '@constant/messages';
// Mock services and constants
jest.mock('react-hot-toast');
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useQueryClient: jest.fn(),
}));
jest.mock('@service/bookingServices', () => ({
checkOutBooking: jest.fn(),
}));
jest.mock('@hook/useUserRoomAvailable', () => ({
useUserRoomAvailable: jest.fn(),
}));
const mockData = {
roomId: '123',
userId: '456',
};
describe('useCheckOut', () => {
const queryClient = new QueryClient();
it('Should checkout successful', async () => {
const queryClientMock = { invalidateQueries: jest.fn() };
(useQueryClient as jest.Mock).mockReturnValue(queryClientMock);
(toast.success as jest.Mock).mockImplementation(() => {});
const dispatchMock = jest.fn();
(useUserRoomAvailable as jest.Mock).mockReturnValue({
dispatch: dispatchMock,
});
const { result } = renderHook(() => useCheckOut(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
),
});
(checkOutBooking as jest.Mock).mockResolvedValue(mockData);
await act(async () => {
result.current.checkOutBooking({ idBooking: 1, roomId: 1, userId: 1 });
});
// Verify that necessary functions were called
expect(toast.success).toHaveBeenCalledWith(CHECKOUT_SUCCESS);
expect(queryClientMock.invalidateQueries).toHaveBeenCalledWith({
queryKey: ['bookings'],
});
expect(dispatchMock).toHaveBeenCalledWith({
type: 'updateStatusRoom',
payload: [{ id: mockData.roomId, status: false }],
});
expect(dispatchMock).toHaveBeenCalledWith({
type: 'updateStatusUser',
payload: [{ id: mockData.userId, isBooked: false }],
});
});
it('Should show error when checkout failed', async () => {
const errorMessage = 'Checkout failed';
(toast.error as jest.Mock).mockImplementation(() => {});
(checkOutBooking as jest.Mock).mockRejectedValue(new Error(errorMessage));
const { result } = renderHook(() => useCheckOut(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
),
});
await act(async () => {
result.current.checkOutBooking({ idBooking: 1, roomId: 1, userId: 1 });
});
// Verify that error toast is displayed
expect(toast.error).toHaveBeenCalledWith(errorMessage);
});
});
@@ -0,0 +1,94 @@
import {
QueryClient,
QueryClientProvider,
useQueryClient,
} from '@tanstack/react-query';
import { ReactNode } from 'react';
import { act, renderHook } from '@testing-library/react';
import toast from 'react-hot-toast';
// Hooks
import { useCreateBooking } from '../useCreateBooking';
// Types
import { IBooking } from '@type/booking';
// Constants
import { ADD_SUCCESS } from '@constant/messages';
// Services
import { createBooking } from '@service/bookingServices';
// Mock the necessary dependencies
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useQueryClient: jest.fn(),
}));
jest.mock('@service/bookingServices', () => ({
createBooking: jest.fn(),
}));
jest.mock('react-hot-toast');
const tempBooking: IBooking = {
id: 1,
startDate: '2023/11/12',
endDate: '2023/12/11',
amount: 2300,
roomId: 1,
status: true,
userId: 2,
};
describe('useCreateBooking', () => {
const queryClient = new QueryClient();
const env = ({ children }: { children: ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
test('Should create booking successful', async () => {
(toast.success as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(createBooking as jest.Mock).mockResolvedValue({
data: tempBooking,
});
const { result } = renderHook(() => useCreateBooking(), {
wrapper: env,
});
// Call function
await act(async () => {
result.current.createBooking(tempBooking);
});
expect(toast.success).toHaveBeenCalledWith(ADD_SUCCESS);
expect(invalidateQueriesMock).toHaveBeenCalledWith({
queryKey: ['bookings'],
});
});
test('Should have error toast when have an error', async () => {
const errorMessage = 'Error';
(toast.error as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(createBooking as jest.Mock).mockRejectedValueOnce(new Error(errorMessage));
const { result } = renderHook(() => useCreateBooking(), {
wrapper: env,
});
await act(async () => {
result.current.createBooking(tempBooking);
});
expect(toast.error).toHaveBeenCalledWith(errorMessage);
});
});
@@ -0,0 +1,95 @@
import { act, renderHook } from '@testing-library/react';
import toast from 'react-hot-toast';
import {
QueryClient,
QueryClientProvider,
useQueryClient,
} from '@tanstack/react-query';
import { ReactNode } from 'react';
// Types
import { IBooking } from '@type/booking';
// Constants
import { UPDATE_SUCCESS } from '@constant/messages';
// Services
import { updateBooking } from '@service/bookingServices';
// Hooks
import { useUpdateBooking } from '../useUpdateBooking';
// Mock the necessary dependencies
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useQueryClient: jest.fn(),
}));
jest.mock('@service/bookingServices', () => ({
updateBooking: jest.fn(),
}));
jest.mock('react-hot-toast');
const tempBooking: IBooking = {
id: 1,
startDate: '2023/11/12',
endDate: '2023/12/11',
amount: 2300,
roomId: 1,
status: true,
userId: 2,
};
describe('useUpdateBooking', () => {
const queryClient = new QueryClient();
const env = ({ children }: { children: ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
test('Should update booking successful', async () => {
(toast.success as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(updateBooking as jest.Mock).mockResolvedValue({
data: tempBooking,
});
const { result } = renderHook(() => useUpdateBooking(), {
wrapper: env,
});
// Call function
await act(async () => {
result.current.updateBooking(tempBooking);
});
expect(toast.success).toHaveBeenCalledWith(UPDATE_SUCCESS);
expect(invalidateQueriesMock).toHaveBeenCalledWith({
queryKey: ['bookings'],
});
});
test('should handle createBooking mutation error', async () => {
const errorMessage = 'Error';
(toast.error as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(updateBooking as jest.Mock).mockRejectedValueOnce(new Error(errorMessage));
const { result } = renderHook(() => useUpdateBooking(), {
wrapper: env,
});
await act(async () => {
result.current.updateBooking(tempBooking);
});
expect(toast.error).toHaveBeenCalledWith(errorMessage);
});
});
@@ -67,7 +67,11 @@ const useBookings = () => {
}); });
} }
return { isLoading, bookings, count }; return {
isLoading,
bookings,
count
};
}; };
export { useBookings }; export { useBookings };
@@ -37,7 +37,11 @@ const useCheckOut = () => {
onError: (err) => toast.error(err.message), onError: (err) => toast.error(err.message),
}); });
return { checkOutBooking, isChecking, isSuccess }; return {
checkOutBooking,
isChecking,
isSuccess
};
}; };
export default useCheckOut; export default useCheckOut;
@@ -27,7 +27,11 @@ const useCreateBooking = () => {
onError: (err) => toast.error(err.message), onError: (err) => toast.error(err.message),
}); });
return { isCreating, createBooking, isSuccess }; return {
isCreating,
createBooking,
isSuccess
};
}; };
export { useCreateBooking }; export { useCreateBooking };
@@ -27,7 +27,11 @@ const useUpdateBooking = () => {
onError: (err) => toast.error(err.message), onError: (err) => toast.error(err.message),
}); });
return { isUpdating, updateBooking, isSuccess }; return {
isUpdating,
updateBooking,
isSuccess
};
}; };
export { useUpdateBooking }; export { useUpdateBooking };
@@ -0,0 +1,92 @@
import { act, renderHook } from '@testing-library/react';
import toast from 'react-hot-toast';
import {
QueryClient,
QueryClientProvider,
useQueryClient,
} from '@tanstack/react-query';
import { ReactNode } from 'react';
// Types
import { IRoom } from '@type/room';
// Hooks
import { useCreateRoom } from '../useCreateRoom';
// Constants
import { ADD_SUCCESS } from '@constant/messages';
// Services
import { createRoom } from '@service/roomServices';
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useQueryClient: jest.fn(),
}));
jest.mock('@service/roomServices', () => ({
createRoom: jest.fn(),
}));
jest.mock('react-hot-toast');
const tempRoom: IRoom = {
id: 1,
name: 'Room 1',
price: 250,
status: true,
isDelete: false,
};
describe('useCreateRoom', () => {
const queryClient = new QueryClient();
const env = ({ children }: { children: ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
test('Should create room successful', async () => {
(toast.success as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(createRoom as jest.Mock).mockResolvedValue({
data: tempRoom,
});
const { result } = renderHook(() => useCreateRoom(), {
wrapper: env,
});
// Call function
await act(async () => {
result.current.createRoom(tempRoom);
});
expect(toast.success).toHaveBeenCalledWith(ADD_SUCCESS);
expect(invalidateQueriesMock).toHaveBeenCalledWith({
queryKey: ['rooms'],
});
});
test('Should have error toast when have an error', async () => {
const errorMessage = 'Error';
(toast.error as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(createRoom as jest.Mock).mockRejectedValueOnce(new Error(errorMessage));
const { result } = renderHook(() => useCreateRoom(), {
wrapper: env,
});
await act(async () => {
result.current.createRoom(tempRoom);
});
expect(toast.error).toHaveBeenCalledWith(errorMessage);
});
});
@@ -0,0 +1,149 @@
import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/react-query';
import { useSearchParams } from 'react-router-dom';
import { renderHook } from '@testing-library/react';
import { URLSearchParams } from 'url';
// Services
import { getAllRooms } from '@service/roomServices';
// Hooks
import { useRooms } from '../useRooms';
jest.mock('react-router-dom', () => ({
useSearchParams: jest.fn(),
}));
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useQuery: jest.fn(),
}));
jest.mock('@service/roomServices', () => ({
getAllRooms: jest.fn(),
}));
describe('useRooms hook', () => {
const queryClient = new QueryClient();
beforeEach(() => {
jest.clearAllMocks();
(queryClient.prefetchQuery as jest.Mock) = jest.fn();
});
test('Should fetch data successful', async () => {
const sampleDate = { data: [{ id: 1, name: 'Room 1' }], count: 3 };
(useSearchParams as jest.Mock).mockReturnValue([
new URLSearchParams('page=1'),
new URLSearchParams('search=test'),
]);
(useQuery as jest.Mock).mockImplementation(({ queryFn }) => {
const result = {
isLoading: false,
error: {},
data: sampleDate,
};
queryFn();
return result;
});
(getAllRooms as jest.Mock).mockResolvedValue(sampleDate);
const { result } = renderHook(() => useRooms(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
),
});
expect(result.current.rooms).toEqual(sampleDate.data);
expect(result.current.count).toEqual(sampleDate.count);
});
test('Should prefetch the second page when in the first page', async () => {
const sampleDate = { data: [{ id: 1, name: 'Room 1' }], count: 7 };
(useSearchParams as jest.Mock).mockReturnValue([
new URLSearchParams('page=1'),
new URLSearchParams('search=test'),
]);
(useQuery as jest.Mock).mockImplementation(({ queryFn }) => {
const result = {
isLoading: false,
error: {},
data: sampleDate,
};
queryFn();
return result;
});
(getAllRooms as jest.Mock).mockResolvedValue(sampleDate);
renderHook(() => useRooms(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
),
});
expect(queryClient.prefetchQuery).toHaveBeenCalledTimes(1);
expect(queryClient.prefetchQuery).toHaveBeenCalledWith({
queryKey: ['rooms', 'id', 'asc', '', 2],
queryFn: expect.any(Function),
});
});
test('Should prefetch the previous page and next page when in the second page', async () => {
const sampleDate = { data: [{ id: 1, name: 'Room 1' }], count: 12 };
(useSearchParams as jest.Mock).mockReturnValue([
new URLSearchParams('page=2'),
new URLSearchParams('search=test'),
]);
(useQuery as jest.Mock).mockImplementation(({ queryFn }) => {
const result = {
isLoading: false,
error: {},
data: sampleDate,
};
queryFn();
return result;
});
(getAllRooms as jest.Mock).mockResolvedValue(sampleDate);
renderHook(() => useRooms(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
),
});
expect(queryClient.prefetchQuery).toHaveBeenCalledTimes(2);
expect(queryClient.prefetchQuery).toHaveBeenCalledWith({
queryKey: ['rooms', 'id', 'asc', '', 3],
queryFn: expect.any(Function),
});
expect(queryClient.prefetchQuery).toHaveBeenCalledWith({
queryKey: ['rooms', 'id', 'asc', '', 1],
queryFn: expect.any(Function),
});
});
});
@@ -0,0 +1,93 @@
import { act, renderHook } from '@testing-library/react';
import toast from 'react-hot-toast';
import {
QueryClient,
QueryClientProvider,
useQueryClient,
} from '@tanstack/react-query';
import { ReactNode } from 'react';
// Types
import { IRoom } from '@type/room';
// Constants
import { DELETE_SUCCESS } from '@constant/messages';
// Services
import { setIsDeleteRoom } from '@service/roomServices';
// Hooks
import { useSetIsDeleteRoom } from '../useSetIsDeleteRoom';
// Mock the necessary dependencies
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useQueryClient: jest.fn(),
}));
jest.mock('@service/roomServices', () => ({
setIsDeleteRoom: jest.fn(),
}));
jest.mock('react-hot-toast');
const tempRoom: IRoom = {
id: 1,
name: 'Room 1',
price: 250,
status: true,
isDelete: false,
};
describe('useUpdateRoom', () => {
const queryClient = new QueryClient();
const env = ({ children }: { children: ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
test('Should update room successful', async () => {
(toast.success as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(setIsDeleteRoom as jest.Mock).mockResolvedValue({
data: tempRoom,
});
const { result } = renderHook(() => useSetIsDeleteRoom(), {
wrapper: env,
});
// Call function
await act(async () => {
result.current.setIsDeleteRoom(1);
});
expect(toast.success).toHaveBeenCalledWith(DELETE_SUCCESS);
expect(invalidateQueriesMock).toHaveBeenCalledWith({
queryKey: ['rooms'],
});
});
test('should handle createRoom mutation error', async () => {
const errorMessage = 'Error';
(toast.error as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(setIsDeleteRoom as jest.Mock).mockRejectedValueOnce(new Error(errorMessage));
const { result } = renderHook(() => useSetIsDeleteRoom(), {
wrapper: env,
});
// Call function
await act(async () => {
result.current.setIsDeleteRoom(1);
});
expect(toast.error).toHaveBeenCalledWith(errorMessage);
});
});
@@ -0,0 +1,93 @@
import { act, renderHook } from '@testing-library/react';
import toast from 'react-hot-toast';
import {
QueryClient,
QueryClientProvider,
useQueryClient,
} from '@tanstack/react-query';
import { ReactNode } from 'react';
// Types
import { IRoom } from '@type/room';
// Constants
import { UPDATE_SUCCESS } from '@constant/messages';
// Services
import { updateRoom } from '@service/roomServices';
// Hooks
import { useUpdateRoom } from '../useUpdateRoom';
// Mock the necessary dependencies
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useQueryClient: jest.fn(),
}));
jest.mock('@service/roomServices', () => ({
updateRoom: jest.fn(),
}));
jest.mock('react-hot-toast');
const tempRoom: IRoom = {
id: 1,
name: 'Room 1',
price: 250,
status: true,
isDelete: false,
};
describe('useUpdateRoom', () => {
const queryClient = new QueryClient();
const env = ({ children }: { children: ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
test('Should update room successful', async () => {
(toast.success as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(updateRoom as jest.Mock).mockResolvedValue({
data: tempRoom,
});
const { result } = renderHook(() => useUpdateRoom(), {
wrapper: env,
});
// Call function
await act(async () => {
result.current.updateRoom(tempRoom);
});
expect(toast.success).toHaveBeenCalledWith(UPDATE_SUCCESS);
expect(invalidateQueriesMock).toHaveBeenCalledWith({
queryKey: ['rooms'],
});
});
test('should handle createRoom mutation error', async () => {
const errorMessage = 'Error';
(toast.error as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(updateRoom as jest.Mock).mockRejectedValueOnce(new Error(errorMessage));
const { result } = renderHook(() => useUpdateRoom(), {
wrapper: env,
});
// Call function
await act(async () => {
result.current.updateRoom(tempRoom);
});
expect(toast.error).toHaveBeenCalledWith(errorMessage);
});
});
@@ -37,7 +37,11 @@ const useCreateRoom = () => {
onError: (err) => toast.error(err.message), onError: (err) => toast.error(err.message),
}); });
return { isCreating, createRoom, isSuccess }; return {
isCreating,
createRoom,
isSuccess
};
}; };
export { useCreateRoom }; export { useCreateRoom };
+5 -1
View File
@@ -73,7 +73,11 @@ const useRooms = () => {
}); });
} }
return { isLoading, rooms, count }; return {
isLoading,
rooms,
count
};
}; };
export { useRooms }; export { useRooms };
@@ -6,6 +6,8 @@ import { setIsDeleteRoom as setIsDeleteRoomFn } from '@service/roomServices';
// Constants // Constants
import * as messages from '@constant/messages'; import * as messages from '@constant/messages';
// Hooks
import { useUserRoomAvailable } from '@hook/useUserRoomAvailable'; import { useUserRoomAvailable } from '@hook/useUserRoomAvailable';
/** /**
@@ -33,7 +35,11 @@ const useSetIsDeleteRoom = () => {
onError: (err) => toast.error(err.message), onError: (err) => toast.error(err.message),
}); });
return { isDeleting, setIsDeleteRoom, isSuccess }; return {
isDeleting,
setIsDeleteRoom,
isSuccess
};
}; };
export { useSetIsDeleteRoom }; export { useSetIsDeleteRoom };
@@ -0,0 +1,93 @@
import { act, renderHook } from '@testing-library/react';
import toast from 'react-hot-toast';
import {
QueryClient,
QueryClientProvider,
useQueryClient,
} from '@tanstack/react-query';
import { ReactNode } from 'react';
// Hooks
import { useCreateUser } from '../useCreateUser';
// Types
import { IUser } from '@type/user';
// Constants
import { ADD_SUCCESS } from '@constant/messages';
// Services
import { createUser } from '@service/userServices';
// Mock the necessary dependencies
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useQueryClient: jest.fn(),
}));
jest.mock('@service/userServices', () => ({
createUser: jest.fn(),
}));
jest.mock('react-hot-toast');
const tempUser: IUser = {
id: 1,
name: 'User 1',
phone: '0324432312',
isBooked: true,
isDelete: false,
};
describe('useCreateUser', () => {
const queryClient = new QueryClient();
const env = ({ children }: { children: ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
test('Should create user successful', async () => {
(toast.success as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(createUser as jest.Mock).mockResolvedValue({
data: tempUser,
});
const { result } = renderHook(() => useCreateUser(), {
wrapper: env,
});
// Call function
await act(async () => {
result.current.createUser(tempUser);
});
expect(toast.success).toHaveBeenCalledWith(ADD_SUCCESS);
expect(invalidateQueriesMock).toHaveBeenCalledWith({
queryKey: ['users'],
});
});
test('Should have error toast when have an error', async () => {
const errorMessage = 'Error';
(toast.error as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(createUser as jest.Mock).mockRejectedValueOnce(new Error(errorMessage));
const { result } = renderHook(() => useCreateUser(), {
wrapper: env,
});
await act(async () => {
result.current.createUser(tempUser);
});
expect(toast.error).toHaveBeenCalledWith(errorMessage);
});
});
@@ -0,0 +1,92 @@
import { act, renderHook } from '@testing-library/react';
import toast from 'react-hot-toast';
import {
QueryClient,
QueryClientProvider,
useQueryClient,
} from '@tanstack/react-query';
import { ReactNode } from 'react';
// Types
import { IUser } from '@type/user';
// Constants
import { DELETE_SUCCESS } from '@constant/messages';
// Services
import { setIsDeleteUser } from '@service/userServices';
// Hooks
import { useIsDeleteUser } from '../useSetIsDeleteUser';
// Mock the necessary dependencies
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useQueryClient: jest.fn(),
}));
jest.mock('@service/userServices', () => ({
setIsDeleteUser: jest.fn(),
}));
jest.mock('react-hot-toast');
const tempUser: IUser = {
id: 1,
name: 'User 1',
phone: '0324432312',
isBooked: true,
isDelete: false,
};
describe('useUpdateUser', () => {
const queryClient = new QueryClient();
const env = ({ children }: { children: ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
test('Should update user successful', async () => {
(toast.success as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(setIsDeleteUser as jest.Mock).mockResolvedValue({
data: tempUser,
});
const { result } = renderHook(() => useIsDeleteUser(), {
wrapper: env,
});
// Call function
await act(async () => {
result.current.setIsDeleteUser(1);
});
expect(toast.success).toHaveBeenCalledWith(DELETE_SUCCESS);
expect(invalidateQueriesMock).toHaveBeenCalledWith({
queryKey: ['users'],
});
});
test('Should throw error when set failed', async () => {
const errorMessage = 'Error';
(toast.error as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(setIsDeleteUser as jest.Mock).mockRejectedValueOnce(new Error(errorMessage));
const { result } = renderHook(() => useIsDeleteUser(), {
wrapper: env,
});
await act(async () => {
result.current.setIsDeleteUser(1);
});
expect(toast.error).toHaveBeenCalledWith(errorMessage);
});
});
@@ -0,0 +1,93 @@
import { act, renderHook } from '@testing-library/react';
import toast from 'react-hot-toast';
import {
QueryClient,
QueryClientProvider,
useQueryClient,
} from '@tanstack/react-query';
import { ReactNode } from 'react';
// Types
import { IUser } from '@type/user';
// Constants
import { UPDATE_SUCCESS } from '@constant/messages';
// Services
import { updateUser } from '@service/userServices';
// Hooks
import { useUpdateUser } from '../useUpdateUser';
// Mock the necessary dependencies
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useQueryClient: jest.fn(),
}));
jest.mock('@service/userServices', () => ({
updateUser: jest.fn(),
}));
jest.mock('react-hot-toast');
const tempUser: IUser = {
id: 1,
name: 'User 1',
phone: '0324432312',
isBooked: true,
isDelete: false,
};
describe('useUpdateUser', () => {
const queryClient = new QueryClient();
const env = ({ children }: { children: ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
test('Should update user successful', async () => {
(toast.success as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(updateUser as jest.Mock).mockResolvedValue({
data: tempUser,
});
const { result } = renderHook(() => useUpdateUser(), {
wrapper: env,
});
// Call function
await act(async () => {
result.current.updateUser(tempUser);
});
expect(toast.success).toHaveBeenCalledWith(UPDATE_SUCCESS);
expect(invalidateQueriesMock).toHaveBeenCalledWith({
queryKey: ['users'],
});
});
test('should handle createUser mutation error', async () => {
const errorMessage = 'Error';
(toast.error as jest.Mock).mockImplementation(() => {});
const invalidateQueriesMock = jest.fn();
(useQueryClient as jest.Mock).mockReturnValueOnce({
invalidateQueries: invalidateQueriesMock,
});
(updateUser as jest.Mock).mockRejectedValueOnce(new Error(errorMessage));
const { result } = renderHook(() => useUpdateUser(), {
wrapper: env,
});
// Call function
await act(async () => {
result.current.updateUser(tempUser);
});
expect(toast.error).toHaveBeenCalledWith(errorMessage);
});
});
@@ -0,0 +1,149 @@
import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/react-query';
import { useSearchParams } from 'react-router-dom';
import { renderHook } from '@testing-library/react';
import { URLSearchParams } from 'url';
// Services
import { getAllUsers } from '@service/userServices';
// Hooks
import { useUsers } from '../useUsers';
jest.mock('react-router-dom', () => ({
useSearchParams: jest.fn(),
}));
jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useQuery: jest.fn(),
}));
jest.mock('@service/userServices', () => ({
getAllUsers: jest.fn(),
}));
describe('useUsers hook', () => {
let queryClient: QueryClient;
beforeEach(() => {
jest.clearAllMocks();
queryClient = new QueryClient();
(queryClient.prefetchQuery as jest.Mock) = jest.fn();
});
test('Should fetch data successful', async () => {
const sampleDate = { data: [{ id: 1, name: 'User 1' }], count: 3 };
(useSearchParams as jest.Mock).mockReturnValue([
new URLSearchParams('page=1'),
new URLSearchParams('search=test'),
]);
(useQuery as jest.Mock).mockImplementation(({ queryFn }) => {
const result = {
isLoading: false,
error: {},
data: sampleDate,
};
queryFn();
return result;
});
(getAllUsers as jest.Mock).mockResolvedValue(sampleDate);
const { result } = renderHook(() => useUsers(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
),
});
expect(result.current.users).toEqual(sampleDate.data);
expect(result.current.count).toEqual(sampleDate.count);
});
test('Should prefetch the second page when in the first page', async () => {
const sampleDate = { data: [{ id: 1, name: 'User 1' }], count: 7 };
(useSearchParams as jest.Mock).mockReturnValue([
new URLSearchParams('page=1'),
new URLSearchParams('search=test'),
]);
(useQuery as jest.Mock).mockImplementation(({ queryFn }) => {
const result = {
isLoading: false,
error: {},
data: sampleDate,
};
queryFn();
return result;
});
(getAllUsers as jest.Mock).mockResolvedValue(sampleDate);
renderHook(() => useUsers(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
),
});
expect(queryClient.prefetchQuery).toHaveBeenCalledTimes(1);
expect(queryClient.prefetchQuery).toHaveBeenCalledWith({
queryKey: ['users', 'id', 'asc', '', 2],
queryFn: expect.any(Function),
});
});
test('Should prefetch the previous page and next page when in the second page', async () => {
const sampleDate = { data: [{ id: 1, name: 'User 1' }], count: 12 };
(useSearchParams as jest.Mock).mockReturnValue([
new URLSearchParams('page=2'),
new URLSearchParams('search=test'),
]);
(useQuery as jest.Mock).mockImplementation(({ queryFn }) => {
const result = {
isLoading: false,
error: {},
data: sampleDate,
};
queryFn();
return result;
});
(getAllUsers as jest.Mock).mockResolvedValue(sampleDate);
renderHook(() => useUsers(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
),
});
expect(queryClient.prefetchQuery).toHaveBeenCalledTimes(2);
expect(queryClient.prefetchQuery).toHaveBeenCalledWith({
queryKey: ['users', 'id', 'asc', '', 3],
queryFn: expect.any(Function),
});
expect(queryClient.prefetchQuery).toHaveBeenCalledWith({
queryKey: ['users', 'id', 'asc', '', 1],
queryFn: expect.any(Function),
});
});
});
@@ -37,7 +37,11 @@ const useCreateUser = () => {
onError: (err) => toast.error(err.message), onError: (err) => toast.error(err.message),
}); });
return { isCreating, createUser, isSuccess }; return {
isCreating,
createUser,
isSuccess,
};
}; };
export { useCreateUser }; export { useCreateUser };
@@ -34,7 +34,11 @@ const useIsDeleteUser = () => {
onError: (err) => toast.error(err.message), onError: (err) => toast.error(err.message),
}); });
return { isDeleting, setIsDeleteUser, isSuccess }; return {
isDeleting,
setIsDeleteUser,
isSuccess,
};
}; };
export { useIsDeleteUser }; export { useIsDeleteUser };
@@ -37,7 +37,11 @@ const useUpdateUser = () => {
onError: (err) => toast.error(err.message), onError: (err) => toast.error(err.message),
}); });
return { isUpdating, updateUser, isSuccess }; return {
isUpdating,
updateUser,
isSuccess,
};
}; };
export { useUpdateUser }; export { useUpdateUser };
+8 -2
View File
@@ -18,7 +18,9 @@ const useUsers = () => {
const sortByValue = searchParams.get('sortBy') || 'id'; const sortByValue = searchParams.get('sortBy') || 'id';
const orderByValue = searchParams.get('orderBy') || 'asc'; const orderByValue = searchParams.get('orderBy') || 'asc';
const searchValue = searchParams.get('search') || ''; const searchValue = searchParams.get('search') || '';
const page = searchParams.get('page') ? Number(searchParams.get('page')) : 1; const page = searchParams.get('page')
? Number(searchParams.get('page'))
: 1;
const { const {
isLoading, isLoading,
@@ -72,7 +74,11 @@ const useUsers = () => {
}); });
} }
return { isLoading, users, count }; return {
isLoading,
users,
count,
};
}; };
export { useUsers }; export { useUsers };
@@ -0,0 +1,68 @@
import { act, fireEvent, render, RenderResult, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
// Components
import AccountInforForm from '@page/Account/AccountInforForm';
// Hooks
import { useAccount } from '@hook/authentication/useAccount';
import { useUpdateAccount } from '@hook/authentication/useUpdateAccount';
jest.mock('@hook/authentication/useUpdateAccount');
jest.mock('@hook/authentication/useAccount');
const mockAccount = {
email: 'admin@nezumi.site',
user_metadata: {
fullName: 'Loi Phan',
},
};
(useAccount as jest.Mock).mockReturnValue({
account: mockAccount,
});
(useUpdateAccount as jest.Mock).mockReturnValue({
updateAccount: jest.fn(),
isUpdating: false,
});
describe('AccountInforForm', () => {
let wrapper: RenderResult | null = null;
beforeEach(() => {
wrapper = render(<AccountInforForm />);
});
test('Should render correctly', () => {
expect(wrapper).toMatchSnapshot();
});
test('Should init data correctly', async () => {
const emailField = wrapper!.container.querySelector('#email');
const fullNameField = wrapper!.container.querySelector('#fullName');
expect(emailField!).toHaveValue(mockAccount.email);
expect(fullNameField).toHaveValue(mockAccount.user_metadata.fullName);
});
test('Should update account correctly', async () => {
const fullNameField = wrapper!.container.querySelector('#fullName');
const newFullName = 'Nezumi';
act(() => {
fireEvent.change(fullNameField!, { target: { value: newFullName } });
});
act(() => {
fireEvent.submit(wrapper!.getByText('Update account'));
});
await waitFor(() => {
expect(useUpdateAccount().updateAccount).toHaveBeenCalledWith({
fullName: newFullName,
});
});
});
});
@@ -0,0 +1,67 @@
import {
RenderResult,
fireEvent,
render,
waitFor,
} from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
// Components
import AccountPasswordForm from '../AccountPasswordForm';
// Hooks
import { useUpdateAccount } from '@hook/authentication/useUpdateAccount';
jest.mock('@hook/authentication/useUpdateAccount');
describe('AccountPasswordForm', () => {
let wrapper: RenderResult | null = null;
const queryClient = new QueryClient();
const mockUpdateAccount = jest.fn();
beforeEach(() => {
(useUpdateAccount as jest.Mock).mockReturnValue({
updateAccount: mockUpdateAccount,
isUpdating: false,
});
wrapper = render(
<QueryClientProvider client={queryClient}>
<AccountPasswordForm />
</QueryClientProvider>
);
});
test('Should render correctly', () => {
expect(wrapper).toMatchSnapshot();
});
test('Should submit form successful', async () => {
const passwordField = wrapper!.container.querySelector('#password');
const comfirmPasswordField =
wrapper!.container.querySelector('#confirmPassword');
const submitButton = wrapper!.getByText('Update password');
fireEvent.change(passwordField!, { target: { value: 'Phanhuuloi2@@1' } });
fireEvent.change(comfirmPasswordField!, {
target: { value: 'Phanhuuloi2@@1' },
});
fireEvent.click(submitButton);
await waitFor(() => {
expect(mockUpdateAccount).toHaveBeenCalled();
});
});
test('Should display error message when input invalid field', async () => {
const passwordField = wrapper!.container.querySelector('#password');
const submitButton = wrapper!.getByText('Update password');
fireEvent.change(passwordField!, { target: { value: '@' } });
fireEvent.click(submitButton);
await waitFor(() => {
expect(wrapper!.getByText('Password not match!')).toBeInTheDocument();
});
});
});
@@ -0,0 +1,170 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`AccountInforForm Should render correctly 1`] = `
{
"asFragment": [Function],
"baseElement": <body>
<div>
<form
class="sc-dlniIP bCPNqw"
>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Email:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
id="email"
readonly=""
type="text"
value="admin@nezumi.site"
/>
</div>
</div>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Full Name:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
id="fullName"
name="fullName"
type="text"
/>
</div>
</div>
<div
class="sc-hKFymg dteuGK"
>
<button
class="sc-gtsqUy sc-iCoHzw iXmfC cwhbgM"
name="submit"
type="submit"
variations="primary"
>
Update account
</button>
</div>
</form>
</div>
</body>,
"container": <div>
<form
class="sc-dlniIP bCPNqw"
>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Email:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
id="email"
readonly=""
type="text"
value="admin@nezumi.site"
/>
</div>
</div>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Full Name:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
id="fullName"
name="fullName"
type="text"
/>
</div>
</div>
<div
class="sc-hKFymg dteuGK"
>
<button
class="sc-gtsqUy sc-iCoHzw iXmfC cwhbgM"
name="submit"
type="submit"
variations="primary"
>
Update account
</button>
</div>
</form>
</div>,
"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],
}
`;
@@ -0,0 +1,168 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`AccountPasswordForm Should render correctly 1`] = `
{
"asFragment": [Function],
"baseElement": <body>
<div>
<form
class="sc-dlniIP bCPNqw"
>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Password:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
id="password"
name="password"
type="password"
/>
</div>
</div>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Confirm Password:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
id="confirmPassword"
name="confirmPassword"
type="password"
/>
</div>
</div>
<div
class="sc-hKFymg dteuGK"
>
<button
class="sc-gtsqUy sc-iCoHzw iXmfC cwhbgM"
name="submit"
type="submit"
variations="primary"
>
Update password
</button>
</div>
</form>
</div>
</body>,
"container": <div>
<form
class="sc-dlniIP bCPNqw"
>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Password:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
id="password"
name="password"
type="password"
/>
</div>
</div>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Confirm Password:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
id="confirmPassword"
name="confirmPassword"
type="password"
/>
</div>
</div>
<div
class="sc-hKFymg dteuGK"
>
<button
class="sc-gtsqUy sc-iCoHzw iXmfC cwhbgM"
name="submit"
type="submit"
variations="primary"
>
Update password
</button>
</div>
</form>
</div>,
"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],
}
`;
@@ -0,0 +1,326 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Account Should render correctly 1`] = `
{
"asFragment": [Function],
"baseElement": <body>
<div>
<div
class="sc-dlniIP jaPwYJ"
>
<h2
class="sc-bdnyFh gafMEQ"
>
Update account
</h2>
<div
class="sc-hKFymg iUYoZl"
>
<h3
class="sc-gtsqUy fkdaKz"
>
Update information
</h3>
<form
class="sc-gKAaef fefJbB"
>
<div
class="sc-fujznN ioyvGl"
direction="horizontal"
>
<label
class="sc-pNWRh gSLqll"
>
Email:
</label>
<div>
<input
class="sc-eCAqax bNAfHQ"
id="email"
readonly=""
type="text"
/>
</div>
</div>
<div
class="sc-fujznN ioyvGl"
direction="horizontal"
>
<label
class="sc-pNWRh gSLqll"
>
Full Name:
</label>
<div>
<input
class="sc-eCAqax bNAfHQ"
id="fullName"
name="fullName"
type="text"
/>
</div>
</div>
<div
class="sc-iCoHzw jMTsfU"
>
<button
class="sc-jSFipO sc-kEqXeH fQJaue bcOLTW"
name="submit"
type="submit"
variations="primary"
>
Update account
</button>
</div>
</form>
</div>
<div
class="sc-hKFymg iUYoZl"
>
<h3
class="sc-gtsqUy fkdaKz"
>
Update password
</h3>
<form
class="sc-gKAaef fefJbB"
>
<div
class="sc-fujznN ioyvGl"
direction="horizontal"
>
<label
class="sc-pNWRh gSLqll"
>
Password:
</label>
<div>
<input
class="sc-eCAqax bNAfHQ"
id="password"
name="password"
type="password"
/>
</div>
</div>
<div
class="sc-fujznN ioyvGl"
direction="horizontal"
>
<label
class="sc-pNWRh gSLqll"
>
Confirm Password:
</label>
<div>
<input
class="sc-eCAqax bNAfHQ"
id="confirmPassword"
name="confirmPassword"
type="password"
/>
</div>
</div>
<div
class="sc-iCoHzw jMTsfU"
>
<button
class="sc-jSFipO sc-kEqXeH fQJaue bcOLTW"
name="submit"
type="submit"
variations="primary"
>
Update password
</button>
</div>
</form>
</div>
</div>
</div>
</body>,
"container": <div>
<div
class="sc-dlniIP jaPwYJ"
>
<h2
class="sc-bdnyFh gafMEQ"
>
Update account
</h2>
<div
class="sc-hKFymg iUYoZl"
>
<h3
class="sc-gtsqUy fkdaKz"
>
Update information
</h3>
<form
class="sc-gKAaef fefJbB"
>
<div
class="sc-fujznN ioyvGl"
direction="horizontal"
>
<label
class="sc-pNWRh gSLqll"
>
Email:
</label>
<div>
<input
class="sc-eCAqax bNAfHQ"
id="email"
readonly=""
type="text"
/>
</div>
</div>
<div
class="sc-fujznN ioyvGl"
direction="horizontal"
>
<label
class="sc-pNWRh gSLqll"
>
Full Name:
</label>
<div>
<input
class="sc-eCAqax bNAfHQ"
id="fullName"
name="fullName"
type="text"
/>
</div>
</div>
<div
class="sc-iCoHzw jMTsfU"
>
<button
class="sc-jSFipO sc-kEqXeH fQJaue bcOLTW"
name="submit"
type="submit"
variations="primary"
>
Update account
</button>
</div>
</form>
</div>
<div
class="sc-hKFymg iUYoZl"
>
<h3
class="sc-gtsqUy fkdaKz"
>
Update password
</h3>
<form
class="sc-gKAaef fefJbB"
>
<div
class="sc-fujznN ioyvGl"
direction="horizontal"
>
<label
class="sc-pNWRh gSLqll"
>
Password:
</label>
<div>
<input
class="sc-eCAqax bNAfHQ"
id="password"
name="password"
type="password"
/>
</div>
</div>
<div
class="sc-fujznN ioyvGl"
direction="horizontal"
>
<label
class="sc-pNWRh gSLqll"
>
Confirm Password:
</label>
<div>
<input
class="sc-eCAqax bNAfHQ"
id="confirmPassword"
name="confirmPassword"
type="password"
/>
</div>
</div>
<div
class="sc-iCoHzw jMTsfU"
>
<button
class="sc-jSFipO sc-kEqXeH fQJaue bcOLTW"
name="submit"
type="submit"
variations="primary"
>
Update password
</button>
</div>
</form>
</div>
</div>
</div>,
"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],
}
`;
@@ -0,0 +1,18 @@
import { render } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
// Components
import Account from '..';
describe('Account', () => {
test('Should render correctly', () => {
const queryClient = new QueryClient();
const wrapper = render(
<QueryClientProvider client={queryClient}>
<Account />
</QueryClientProvider>
);
expect(wrapper).toMatchSnapshot();
});
});
@@ -276,7 +276,6 @@ const BookingForm = ({ onCloseModal, booking }: IBookingFormProp) => {
required: REQUIRED_FIELD_ERROR, required: REQUIRED_FIELD_ERROR,
onChange: () => trigger('amount'), onChange: () => trigger('amount'),
})} })}
readOnly
/> />
<span>{amountValue}</span> <span>{amountValue}</span>
@@ -0,0 +1,115 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BrowserRouter } from 'react-router-dom';
import {
RenderResult,
fireEvent,
render,
waitFor,
} from '@testing-library/react';
// Types
import { TBookingResponse } from '@type/booking';
// Components
import BookingForm from '../BookingForm';
// Hooks
import { useUserRoomAvailable } from '@hook/useUserRoomAvailable';
const mockUpdateBooking = jest.fn();
jest.mock('@hook/bookings/useUpdateBooking', () => ({
...jest.requireActual('@hook/bookings/useUpdateBooking'),
useUpdateBooking: jest.fn(() => ({
isUpdating: false,
updateBooking: mockUpdateBooking,
})),
}));
jest.mock('@hook/useUserRoomAvailable.ts');
const mockUseUserRoomAvailable = useUserRoomAvailable as jest.MockedFunction<
typeof useUserRoomAvailable
>;
mockUseUserRoomAvailable.mockReturnValue({
roomsAvailable: [
{ id: 1, name: 'Room 1', status: false },
{ id: 2, name: 'Room 2', status: false },
],
usersAvailable: [
{ id: 1, name: 'User 1', isBooked: false },
{ id: 2, name: 'User 2', isBooked: false },
],
dispatch: jest.fn(),
});
let result: {
name: string;
price: number;
};
describe('BookingForm', () => {
const queryClient = new QueryClient();
let wrapper: RenderResult | null = null;
test('Should render correctly', () => {
wrapper = render(
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<BookingForm />
</BrowserRouter>
</QueryClientProvider>
);
expect(wrapper).toMatchSnapshot();
});
test('Should edit correctly', async () => {
const tempBooking: TBookingResponse = {
id: 1,
startDate: '2024-11-21',
endDate: '2024-11-22',
amount: 1200,
status: true,
rooms: {
id: 1,
name: 'Room 1',
},
users: {
id: 2,
name: 'Room 2',
},
};
wrapper = render(
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<BookingForm booking={tempBooking} />
</BrowserRouter>
</QueryClientProvider>
);
const submitBtn = wrapper!.getByText('Save').closest('button');
mockUpdateBooking.mockImplementationOnce((newBooking, { onSuccess }) => {
result = newBooking;
onSuccess();
});
fireEvent.submit(submitBtn!);
await waitFor(() => {
expect(mockUpdateBooking).toHaveBeenCalled();
expect(result).toEqual({
amount: 1200,
endDate: '2024-11-22',
id: 1,
roomId: 1,
startDate: '2024-11-21',
userId: 2,
});
});
});
});
@@ -0,0 +1,37 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { render } from '@testing-library/react';
// Types
import { TBookingResponse } from '@type/booking';
// Components
import BookingRow from '../BookingRow';
describe('BookingRow', () => {
const tempBooking: TBookingResponse = {
id: 1,
startDate: '2024-11-21',
endDate: '2024-11-22',
amount: 1200,
status: true,
rooms: {
id: 1,
name: 'Room 1',
},
users: {
id: 2,
name: 'Room 2',
},
};
const queryClient = new QueryClient();
const wrapper = render(
<QueryClientProvider client={queryClient}>
<BookingRow booking={tempBooking} />
</QueryClientProvider>
);
test('Should render correctly', () => {
expect(wrapper).toMatchSnapshot();
});
});
@@ -0,0 +1,22 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BrowserRouter } from 'react-router-dom';
import { render } from '@testing-library/react';
// Components
import BookingTable from '@page/Booking/BookingTable';
describe('UserTable', () => {
const queryClient = new QueryClient();
const wrapper = render(
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<BookingTable />
</BrowserRouter>
</QueryClientProvider>
);
test('Should render correctly', () => {
expect(wrapper).toMatchSnapshot();
});
});
@@ -0,0 +1,346 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`BookingForm Should render correctly 1`] = `
{
"asFragment": [Function],
"baseElement": <body>
<div>
<form
class="sc-dlniIP bCPNqw"
>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
User:
</label>
<div>
<select
aria-label="user-select"
class="sc-fujznN rEQue"
id="userId"
name="userId"
>
<option
value="1"
>
User 1
</option>
<option
value="2"
>
User 2
</option>
</select>
</div>
</div>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Room:
</label>
<div>
<select
aria-label="user-select"
class="sc-fujznN rEQue"
id="roomId"
name="roomId"
>
<option
value="1"
>
Room 1
</option>
<option
value="2"
>
Room 2
</option>
</select>
</div>
</div>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Start Date:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
id="startDate"
min="2023-12-03"
name="startDate"
type="date"
/>
</div>
</div>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
End Date:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
disabled=""
id="endDate"
name="endDate"
type="date"
/>
</div>
</div>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Amount:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
id="amount"
name="amount"
type="hidden"
/>
<span>
$0.00
</span>
</div>
</div>
<div
class="sc-hKFymg dteuGK"
>
<button
class="sc-gtsqUy sc-iCoHzw iXmfC cwhbgM"
disabled=""
name="submit"
type="submit"
variations="primary"
>
Add
</button>
<button
class="sc-gtsqUy sc-iCoHzw hesuRJ cwhbgM"
type="button"
variations="secondary"
>
Close
</button>
</div>
</form>
</div>
</body>,
"container": <div>
<form
class="sc-dlniIP bCPNqw"
>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
User:
</label>
<div>
<select
aria-label="user-select"
class="sc-fujznN rEQue"
id="userId"
name="userId"
>
<option
value="1"
>
User 1
</option>
<option
value="2"
>
User 2
</option>
</select>
</div>
</div>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Room:
</label>
<div>
<select
aria-label="user-select"
class="sc-fujznN rEQue"
id="roomId"
name="roomId"
>
<option
value="1"
>
Room 1
</option>
<option
value="2"
>
Room 2
</option>
</select>
</div>
</div>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Start Date:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
id="startDate"
min="2023-12-03"
name="startDate"
type="date"
/>
</div>
</div>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
End Date:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
disabled=""
id="endDate"
name="endDate"
type="date"
/>
</div>
</div>
<div
class="sc-eCAqax dgDilB"
direction="horizontal"
>
<label
class="sc-jSFipO cMYxin"
>
Amount:
</label>
<div>
<input
class="sc-bdnyFh gXSWSo"
id="amount"
name="amount"
type="hidden"
/>
<span>
$0.00
</span>
</div>
</div>
<div
class="sc-hKFymg dteuGK"
>
<button
class="sc-gtsqUy sc-iCoHzw iXmfC cwhbgM"
disabled=""
name="submit"
type="submit"
variations="primary"
>
Add
</button>
<button
class="sc-gtsqUy sc-iCoHzw hesuRJ cwhbgM"
type="button"
variations="secondary"
>
Close
</button>
</div>
</form>
</div>,
"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],
}
`;
@@ -0,0 +1,218 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`BookingRow Should render correctly 1`] = `
{
"asFragment": [Function],
"baseElement": <body>
<div>
<div
class="sc-jSFipO sc-iCoHzw hTfHNc eWZMfB"
>
<div>
Room 2
</div>
<div
style="display: flex; align-items: center;"
>
2024-11-21
 
<svg
fill="none"
height="1em"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0 0h24v24H0z"
fill="none"
stroke="none"
/>
<path
d="M5 12l14 0"
/>
<path
d="M15 16l4 -4"
/>
<path
d="M15 8l4 4"
/>
</svg>
 
2024-11-22
</div>
<div>
Room 1
</div>
<div>
$1,200.00
</div>
<div>
Check in
</div>
<div>
<div
class="sc-kEqXeH jLboIv"
>
<button
aria-label="Menu item 1"
class="sc-crzpnZ gdsCet"
>
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M10.5 6a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0zm0 6a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0zm0 6a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0z"
fill-rule="evenodd"
/>
</svg>
</button>
</div>
</div>
</div>
</div>
</body>,
"container": <div>
<div
class="sc-jSFipO sc-iCoHzw hTfHNc eWZMfB"
>
<div>
Room 2
</div>
<div
style="display: flex; align-items: center;"
>
2024-11-21
 
<svg
fill="none"
height="1em"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0 0h24v24H0z"
fill="none"
stroke="none"
/>
<path
d="M5 12l14 0"
/>
<path
d="M15 16l4 -4"
/>
<path
d="M15 8l4 4"
/>
</svg>
 
2024-11-22
</div>
<div>
Room 1
</div>
<div>
$1,200.00
</div>
<div>
Check in
</div>
<div>
<div
class="sc-kEqXeH jLboIv"
>
<button
aria-label="Menu item 1"
class="sc-crzpnZ gdsCet"
>
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M10.5 6a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0zm0 6a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0zm0 6a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0z"
fill-rule="evenodd"
/>
</svg>
</button>
</div>
</div>
</div>
</div>,
"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],
}
`;

Some files were not shown because too many files have changed in this diff Show More