CFE-20 implement middlewarecomponent and middleware test
This commit is contained in:
@@ -5,7 +5,10 @@ export const handler = [
|
||||
rest.get(GET_USER_ROUTE, (req, res, ctx) => {
|
||||
return res(ctx.json({
|
||||
data:{
|
||||
id: 10
|
||||
id: 10,
|
||||
permissions:[
|
||||
"manage_users"
|
||||
],
|
||||
}
|
||||
}))
|
||||
}),
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"msw": "^1.3.1",
|
||||
"next-router-mock": "^0.9.9",
|
||||
"next-router-mock": "^0.9.10",
|
||||
"run-script-os": "^1.1.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"typography_your_login_is_valid_and_you_do_not_need_to_login_again": "شما دسترسی لازم به این صفحه را دارید نیاز به ورود مجدد نیست.",
|
||||
"typography_your_access_to_this_page_has_expired_Please_login_again": "دسترسی شما منقضی شده است لطفا دوباره ورود نمایید.",
|
||||
"typography_redirect_to": "درحال رفتن به صفحه",
|
||||
"typography_routing_previuos_page": "صفحه قبل...",
|
||||
"typography_routing_previuos_page": " قبل...",
|
||||
"typography_routing_dashbaord_page": "داشبورد..."
|
||||
},
|
||||
"Permission": {
|
||||
|
||||
33
src/core/components/Middleware/RolePermissionComponent.jsx
Normal file
33
src/core/components/Middleware/RolePermissionComponent.jsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Button, Typography } from "@mui/material";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { NextLinkComposed } from "@/core/components/LinkRouting";
|
||||
import Message from "@/core/components/Messages";
|
||||
|
||||
const RolePermissionComponent = () => {
|
||||
const t = useTranslations();
|
||||
|
||||
return (
|
||||
<Message
|
||||
text={
|
||||
<Typography sx={{ textAlign: "center" }}>
|
||||
{t("Permission.typography_you_dont_have_access")}
|
||||
</Typography>
|
||||
}
|
||||
actions={
|
||||
<>
|
||||
<Button
|
||||
variant="contained"
|
||||
component={NextLinkComposed}
|
||||
to={{
|
||||
pathname: "/dashboard",
|
||||
}}
|
||||
>
|
||||
{t("Permission.button_back_dashboard")}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default RolePermissionComponent;
|
||||
36
src/core/components/Middleware/WithAuthComponent.jsx
Normal file
36
src/core/components/Middleware/WithAuthComponent.jsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Button, Typography } from "@mui/material";
|
||||
import { useRouter } from "next/router";
|
||||
import Message from "@/core/components/Messages";
|
||||
import { NextLinkComposed } from "@/core/components/LinkRouting";
|
||||
import {useTranslations} from "next-intl";
|
||||
|
||||
const WithAuthComponent = () => {
|
||||
const router = useRouter();
|
||||
const t = useTranslations();
|
||||
|
||||
return (
|
||||
<Message
|
||||
text={
|
||||
<Typography sx={{ textAlign: "center" }}>
|
||||
{t("Authorization.typography_your_access_to_this_page_has_expired_Please_login_again")}
|
||||
</Typography>
|
||||
}
|
||||
actions={
|
||||
<>
|
||||
<Button
|
||||
variant="contained"
|
||||
component={NextLinkComposed}
|
||||
to={{
|
||||
pathname: "/login-expert",
|
||||
query: {back_url: encodeURIComponent(router.asPath)},
|
||||
}}
|
||||
>
|
||||
{t("login")}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default WithAuthComponent;
|
||||
25
src/core/components/Middleware/WithoutAuthComponent.jsx
Normal file
25
src/core/components/Middleware/WithoutAuthComponent.jsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import {Button, Stack, Typography} from "@mui/material";
|
||||
import Message from "@/core/components/Messages";
|
||||
import {useTranslations} from "next-intl";
|
||||
const WithoutAuthComponent = ({ backUrlDecodedPath }) => {
|
||||
const t = useTranslations();
|
||||
|
||||
return (
|
||||
<Message
|
||||
text={
|
||||
<Stack alignItems="center" spacing={2}>
|
||||
<Typography sx={{ textAlign: "center" }}>
|
||||
{t("Authorization.typography_your_login_is_valid_and_you_do_not_need_to_login_again")}
|
||||
</Typography>
|
||||
<Typography>
|
||||
{t("Authorization.typography_redirect_to")}{" "}
|
||||
{backUrlDecodedPath
|
||||
? t("Authorization.typography_routing_previuos_page")
|
||||
: t("Authorization.typography_routing_dashbaord_page")}
|
||||
</Typography>
|
||||
</Stack>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
export default WithoutAuthComponent;
|
||||
@@ -0,0 +1,23 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import MockAppWithProviders from "../../../../../mocks/AppWithProvider";
|
||||
import RolePermissionComponent from "@/core/components/Middleware/RolePermissionComponent";
|
||||
|
||||
describe('RolePermissionComponent From RolePermissionComponent page', () => {
|
||||
describe('Rendering', () => {
|
||||
it('should render the error message when user dont have permission', () => {
|
||||
render(<MockAppWithProviders><RolePermissionComponent /></MockAppWithProviders>);
|
||||
|
||||
expect(screen.queryByText('شما دسترسی لازم برای مشاهده این صفحه را ندارید!')).toBeInTheDocument();
|
||||
|
||||
});
|
||||
|
||||
it('should render the back dashboard button when user dont have permission', () => {
|
||||
render(<MockAppWithProviders><RolePermissionComponent /></MockAppWithProviders>);
|
||||
|
||||
const backButton = screen.queryByText('بازگشت به صفحه اصلی');
|
||||
|
||||
expect(backButton).toBeInTheDocument();
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import MockAppWithProviders from "../../../../../mocks/AppWithProvider";
|
||||
import WithAuthComponent from "@/core/components/Middleware/WithAuthComponent";
|
||||
import mockRouter from 'next-router-mock';
|
||||
|
||||
describe('WithAuthComponent From WithAuthMiddleware', () => {
|
||||
describe('Rendering', () => {
|
||||
it('should see expired text in render component', () => {
|
||||
render(<MockAppWithProviders><WithAuthComponent /></MockAppWithProviders>);
|
||||
|
||||
const authText = screen.queryByText('دسترسی شما منقضی شده است لطفا دوباره ورود نمایید.');
|
||||
|
||||
expect(authText).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should see login button in render component', () => {
|
||||
render(<MockAppWithProviders><WithAuthComponent /></MockAppWithProviders>);
|
||||
|
||||
const loginButton = screen.queryByText('ورود');
|
||||
|
||||
expect(loginButton).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
describe('behavior', () => {
|
||||
it('should see if router updated in login button', () => {
|
||||
|
||||
mockRouter.query.back_url = 'back_url'
|
||||
render(<MockAppWithProviders><WithAuthComponent /></MockAppWithProviders>);
|
||||
|
||||
const loginButton = screen.queryByText('ورود');
|
||||
|
||||
fireEvent.click(loginButton);
|
||||
|
||||
expect(mockRouter).toMatchObject({
|
||||
query: { back_url: "back_url" },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
import {render, screen, waitFor} from '@testing-library/react';
|
||||
import WithoutAuthComponent from "@/core/components/Middleware/WithoutAuthComponent";
|
||||
import MockAppWithProviders from "../../../../../mocks/AppWithProvider";
|
||||
import WithoutAuthMiddleware from "@/middlewares/WithoutAuth";
|
||||
|
||||
describe('WithoutAuthComponent From WithoutAuthMiddleware', () => {
|
||||
describe('Rendering', () => {
|
||||
it('should render the message with correct text when backUrlDecodedPath is not provided', async () => {
|
||||
|
||||
localStorage.setItem("_token", 'token');
|
||||
|
||||
render(<MockAppWithProviders><WithoutAuthMiddleware /></MockAppWithProviders>);
|
||||
|
||||
await waitFor(()=>{
|
||||
expect(screen.queryByText('شما دسترسی لازم به این صفحه را دارید نیاز به ورود مجدد نیست.')).toBeInTheDocument();
|
||||
|
||||
expect(screen.queryByText('درحال رفتن به صفحه داشبورد...')).toBeInTheDocument();
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
it('should render the message with a different text when backUrlDecodedPath is provided', async() => {
|
||||
render(<MockAppWithProviders><WithoutAuthComponent backUrlDecodedPath="/dashboard/change-password" /></MockAppWithProviders>);
|
||||
|
||||
localStorage.setItem("_token", 'token');
|
||||
|
||||
render(<MockAppWithProviders><WithoutAuthMiddleware /></MockAppWithProviders>);
|
||||
|
||||
await waitFor(()=>{
|
||||
|
||||
expect(screen.queryByText('درحال رفتن به صفحه قبل...')).toBeInTheDocument();
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,43 +1,14 @@
|
||||
import {NextLinkComposed} from "@/core/components/LinkRouting";
|
||||
import Message from "@/core/components/Messages";
|
||||
import useUser from "@/lib/app/hooks/useUser";
|
||||
import {Button, Typography} from "@mui/material";
|
||||
import {useTranslations} from "next-intl";
|
||||
import RolePermissionComponent from "@/core/components/Middleware/RolePermissionComponent";
|
||||
|
||||
const RolePermissionMiddleware = ({children, requiredPermissions}) => {
|
||||
const {user} = useUser();
|
||||
const t = useTranslations();
|
||||
|
||||
const hasPermission = requiredPermissions.some((permission) =>
|
||||
user?.permissions?.includes(permission)
|
||||
);
|
||||
|
||||
if (!hasPermission) {
|
||||
return (
|
||||
<Message
|
||||
text={
|
||||
<Typography sx={{textAlign: "center"}}>
|
||||
{t("Permission.typography_you_dont_have_access")}
|
||||
</Typography>
|
||||
}
|
||||
actions={
|
||||
<>
|
||||
<Button
|
||||
variant="contained"
|
||||
component={NextLinkComposed}
|
||||
to={{
|
||||
pathname: "/dashboard",
|
||||
}}
|
||||
>
|
||||
{t("Permission.button_back_dashboard")}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
return !hasPermission ? <RolePermissionComponent /> : <>{children}</>;
|
||||
};
|
||||
|
||||
export default RolePermissionMiddleware;
|
||||
|
||||
@@ -1,42 +1,11 @@
|
||||
import {NextLinkComposed} from "@/core/components/LinkRouting";
|
||||
import Message from "@/core/components/Messages";
|
||||
import useUser from "@/lib/app/hooks/useUser";
|
||||
import {Button, Typography} from "@mui/material";
|
||||
import {useTranslations} from "next-intl";
|
||||
import {useRouter} from "next/router";
|
||||
import WithAuthComponent from "@/core/components/Middleware/WithAuthComponent";
|
||||
|
||||
|
||||
const WithAuthMiddleware = ({children}) => {
|
||||
const {isAuth} = useUser();
|
||||
const t = useTranslations();
|
||||
const router = useRouter();
|
||||
|
||||
if (!isAuth)
|
||||
return (
|
||||
<Message
|
||||
text={
|
||||
<Typography sx={{textAlign: "center"}}>
|
||||
{t(
|
||||
"Authorization.typography_your_access_to_this_page_has_expired_Please_login_again"
|
||||
)}
|
||||
</Typography>
|
||||
}
|
||||
actions={
|
||||
<>
|
||||
<Button
|
||||
variant="contained"
|
||||
component={NextLinkComposed}
|
||||
to={{
|
||||
pathname: "/login-expert",
|
||||
query: {back_url: encodeURIComponent(router.asPath)},
|
||||
}}
|
||||
>
|
||||
{t("login")}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
return <>{children}</>;
|
||||
return isAuth ? <>{children}</> : <WithAuthComponent />;
|
||||
};
|
||||
|
||||
export default WithAuthMiddleware;
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
import Message from "@/core/components/Messages";
|
||||
import useUser from "@/lib/app/hooks/useUser";
|
||||
import {Stack, Typography} from "@mui/material";
|
||||
import {useTranslations} from "next-intl";
|
||||
import {useSearchParams} from "next/navigation";
|
||||
import {useRouter} from "next/router";
|
||||
import {useEffect} from "react";
|
||||
import WithoutAuthComponent from "@/core/components/Middleware/WithoutAuthComponent";
|
||||
|
||||
const WithoutAuthMiddleware = ({children}) => {
|
||||
const {isAuth} = useUser();
|
||||
const t = useTranslations();
|
||||
const router = useRouter();
|
||||
|
||||
// gettin url query
|
||||
const searchParams = useSearchParams();
|
||||
const backUrlDecodedPath = searchParams.get("back_url");
|
||||
const backUrlDecodedPath = router.query?.back_url;
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAuth) return;
|
||||
@@ -30,27 +24,11 @@ const WithoutAuthMiddleware = ({children}) => {
|
||||
};
|
||||
}, [isAuth]);
|
||||
|
||||
if (isAuth)
|
||||
return (
|
||||
<Message
|
||||
text={
|
||||
<Stack alignItems="center" spacing={2}>
|
||||
<Typography sx={{textAlign: "center"}}>
|
||||
{t(
|
||||
"Authorization.typography_your_login_is_valid_and_you_do_not_need_to_login_again"
|
||||
)}
|
||||
</Typography>
|
||||
<Typography>
|
||||
{t("Authorization.typography_redirect_to")}{" "}
|
||||
{backUrlDecodedPath
|
||||
? t("Authorization.typography_routing_previuos_page")
|
||||
: t("Authorization.typography_routing_dashbaord_page")}
|
||||
</Typography>
|
||||
</Stack>
|
||||
}
|
||||
/>
|
||||
);
|
||||
return <>{children}</>;
|
||||
return isAuth ? (
|
||||
<WithoutAuthComponent backUrlDecodedPath={backUrlDecodedPath} />
|
||||
) : (
|
||||
<>{children}</>
|
||||
);
|
||||
};
|
||||
|
||||
export default WithoutAuthMiddleware;
|
||||
|
||||
34
src/middlewares/__test__/RolePermission.test.js
Normal file
34
src/middlewares/__test__/RolePermission.test.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import {render, screen, waitFor} from '@testing-library/react';
|
||||
import MockAppWithProviders from "../../../mocks/AppWithProvider";
|
||||
import RolePermissionMiddleware from "@/middlewares/RolePermission";
|
||||
|
||||
|
||||
describe('RolePermissionMiddleware From RolePermissionMiddleware', () => {
|
||||
describe('Behavior', () => {
|
||||
it('show related child if permission exist', async () => {
|
||||
|
||||
const requiredPermissions = ["manage_users"];
|
||||
render(<MockAppWithProviders><RolePermissionMiddleware requiredPermissions={requiredPermissions}/>{'children'}</MockAppWithProviders>);
|
||||
|
||||
await waitFor(()=>{
|
||||
expect(screen.queryByText('children')).toBeInTheDocument();
|
||||
|
||||
})
|
||||
|
||||
});
|
||||
it('show related error if permission not exist', async () => {
|
||||
|
||||
const requiredPermissions = ["other-permission"];
|
||||
|
||||
render(<MockAppWithProviders><RolePermissionMiddleware requiredPermissions={requiredPermissions}/></MockAppWithProviders>);
|
||||
|
||||
await waitFor(()=>{
|
||||
|
||||
expect(screen.queryByText('شما دسترسی لازم برای مشاهده این صفحه را ندارید!')).toBeInTheDocument();
|
||||
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user