CFE-21 sidebar test
This commit is contained in:
@@ -10,4 +10,6 @@ NEXT_PUBLIC_BASE_URL = "https://crm.witel.ir"
|
||||
NEXT_PUBLIC_SERVER_SOCKET_URL = "wss://crmws.witel.ir"
|
||||
NEXT_PUBLIC_POWERED_BY_URL = "https://witel.ir"
|
||||
|
||||
NEXT_HAS_NOTIFICATION = "false"
|
||||
|
||||
NODE_ENV = "development"
|
||||
@@ -6,8 +6,12 @@ export const handler = [
|
||||
return res(ctx.json({
|
||||
data:{
|
||||
id: 10,
|
||||
full_name: "Witel Company",
|
||||
position: "Software Engineer",
|
||||
permissions:[
|
||||
"manage_users"
|
||||
"manage_users",
|
||||
"manage_roles",
|
||||
"manage_boss"
|
||||
],
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -4,7 +4,7 @@ import SidebarList from "./SidebarList";
|
||||
import useUser from "@/lib/app/hooks/useUser";
|
||||
|
||||
const SidebarDrawer = ({handleDrawerToggle}) => {
|
||||
const {user} = useUser()
|
||||
const {user} = useUser();
|
||||
const t = useTranslations();
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -10,29 +10,15 @@ function reducer(state, action) {
|
||||
case "COLLAPSE_MENU":
|
||||
return state.map((itemsArr) =>
|
||||
itemsArr.map((item) =>
|
||||
action.key == item.key
|
||||
? {...item, showSubItem: !item.showSubItem}
|
||||
: item
|
||||
action.key === item.key ? { ...item, showSubItem: !item.showSubItem } : item
|
||||
)
|
||||
);
|
||||
case "SELECTED":
|
||||
return state.map((itemsArr) =>
|
||||
itemsArr.map((item) => {
|
||||
if (item.type === "page") {
|
||||
if (action.route === item.route)
|
||||
return {...item, selected: true}
|
||||
else
|
||||
return {...item, selected: false}
|
||||
}
|
||||
return {...item}
|
||||
// item.subItem.map((subitem) => {
|
||||
// if (action.route === subitem.route)
|
||||
// return {...item, showSubItem: true, subItem: {...subitem, selected: true}}
|
||||
// else
|
||||
// return {...item, showSubItem: false, subItem: {...subitem, selected: false}}
|
||||
// })
|
||||
}
|
||||
)
|
||||
itemsArr.map((item) => ({
|
||||
...item,
|
||||
selected: item.type === "page" && action.route === item.route,
|
||||
}))
|
||||
);
|
||||
default:
|
||||
throw new Error();
|
||||
@@ -54,7 +40,7 @@ export default function SidebarList({handleDrawerToggle}) {
|
||||
<Fragment key={index}>
|
||||
{itemArr.map((item) =>
|
||||
<Fragment key={item.key}>
|
||||
{(user.permissions.includes(item.permission) || item.permission === "all") &&
|
||||
{(user?.permissions?.includes(item.permission) || item.permission === "all") &&
|
||||
<SidebarListItem
|
||||
item={item}
|
||||
dispatch={dispatch}
|
||||
|
||||
@@ -9,23 +9,27 @@ import useNotification from "@/lib/app/hooks/useNotification";
|
||||
|
||||
const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
|
||||
const t = useTranslations();
|
||||
const {notification_count} = useNotification()
|
||||
const { notification_count } = useNotification();
|
||||
|
||||
const hasSubItems = item.type === "menu" && item.subItem && item.subItem.length > 0;
|
||||
|
||||
const renderBadge = () => (
|
||||
<IconButton>
|
||||
<Badge
|
||||
badgeContent={notification_count ? notification_count[item.name] : 0}
|
||||
color="error"
|
||||
variant="standard"
|
||||
anchorOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "right",
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ListItem disablePadding secondaryAction={
|
||||
<IconButton>
|
||||
<Badge
|
||||
badgeContent={notification_count ? notification_count[item.name] : 0}
|
||||
color="error"
|
||||
variant="standard"
|
||||
anchorOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "right",
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
}>
|
||||
<ListItem disablePadding secondaryAction={renderBadge()}>
|
||||
<ListItemButton
|
||||
selected={item.selected}
|
||||
{...(item.type == "page" && {
|
||||
@@ -35,10 +39,9 @@ const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
|
||||
},
|
||||
})}
|
||||
onClick={() => {
|
||||
if (item.type == "menu") {
|
||||
dispatch({type: "COLLAPSE_MENU", key: item.key});
|
||||
if (hasSubItems) {
|
||||
dispatch({ type: "COLLAPSE_MENU", key: item.key });
|
||||
}
|
||||
handleDrawerToggle();
|
||||
}}
|
||||
sx={{
|
||||
minHeight: 48,
|
||||
@@ -66,9 +69,7 @@ const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
{item.type == "menu" &&
|
||||
(item.showSubItem ? <ExpandLess/> : <ExpandMore/>)}
|
||||
{hasSubItems && (item.showSubItem ? <ExpandLess /> : <ExpandMore />)}
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
{item.subItem && (
|
||||
|
||||
@@ -15,25 +15,27 @@ import useNotification from "@/lib/app/hooks/useNotification";
|
||||
|
||||
const SidebarListSubItem = ({item, handleDrawerToggle}) => {
|
||||
const t = useTranslations();
|
||||
const {notification_count} = useNotification()
|
||||
const {notification_count} = useNotification();
|
||||
|
||||
const renderBadge = (subitem) => (
|
||||
<IconButton>
|
||||
<Badge
|
||||
badgeContent={notification_count ? notification_count[subitem.name] : 0}
|
||||
color="error"
|
||||
variant="standard"
|
||||
anchorOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "right",
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
);
|
||||
|
||||
return (
|
||||
<Collapse in={item.showSubItem} timeout="auto" mountOnEnter={true} unmountOnExit={true}>
|
||||
<List component="div" disablePadding sx={{bgcolor: "#f6f6f6", pr: 1}}>
|
||||
{item.subItem.map((subitem, index) => (
|
||||
<ListItem key={subitem.key} disablePadding secondaryAction={
|
||||
<IconButton>
|
||||
<Badge
|
||||
badgeContent={notification_count ? notification_count[subitem.name] : 0}
|
||||
color="error"
|
||||
variant="standard"
|
||||
anchorOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "right",
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
}>
|
||||
{item.subItem.map((subitem) => (
|
||||
<ListItem key={subitem.key} disablePadding secondaryAction={renderBadge(subitem)}>
|
||||
<ListItemButton
|
||||
selected={subitem.selected}
|
||||
component={NextLinkComposed}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import {render, screen, waitFor} from "@testing-library/react";
|
||||
import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
|
||||
import SidebarDrawer from "@/components/layouts/Dashboard/Sidebar/SidebarDrawer";
|
||||
|
||||
describe('SidebarDrawer', () => {
|
||||
describe('Rendering', () => {
|
||||
it('renders system name in sidebar', async () => {
|
||||
render(<MockAppWithProviders><SidebarDrawer/></MockAppWithProviders>);
|
||||
await waitFor(()=>{
|
||||
const systemName = screen.getByRole('heading', { level: 6 });
|
||||
expect(systemName).toHaveTextContent('سامانه CRM');
|
||||
})
|
||||
});
|
||||
it('renders user full name and position in sidebar', async () => {
|
||||
localStorage.setItem("_token", 'token');
|
||||
render(<MockAppWithProviders><SidebarDrawer/></MockAppWithProviders>);
|
||||
await waitFor(()=>{
|
||||
const userName = screen.queryByText(/Witel Company | Software Engineer/i);
|
||||
expect(userName).toBeInTheDocument();
|
||||
})
|
||||
});
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,16 @@
|
||||
import {render, screen, waitFor} from "@testing-library/react";
|
||||
import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
|
||||
import SidebarList from "@/components/layouts/Dashboard/Sidebar/SidebarList";
|
||||
|
||||
describe('SidebarList', () => {
|
||||
describe('Rendering', () => {
|
||||
it('renders sidebar items based on user permissions', async () => {
|
||||
localStorage.setItem("_token", 'token');
|
||||
render(<MockAppWithProviders><SidebarList/></MockAppWithProviders>);
|
||||
await waitFor(()=>{
|
||||
const sidebarItem = screen.getByText('مدیریت نقش ها');
|
||||
expect(sidebarItem).toBeInTheDocument();
|
||||
})
|
||||
});
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,125 @@
|
||||
import AccessibilityIcon from "@mui/icons-material/Accessibility";
|
||||
import {fireEvent, render, screen} from "@testing-library/react";
|
||||
import SidebarListItem from "@/components/layouts/Dashboard/Sidebar/SidebarListItem";
|
||||
import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
|
||||
|
||||
describe('SidebarListItemComponent', () => {
|
||||
describe('Rendering', () => {
|
||||
it('should show sidebarlistitem name in sidebar', () => {
|
||||
const sampleItem={
|
||||
key: "sidebar.role-management",
|
||||
name : "role_management",
|
||||
type: "page",
|
||||
route: "/dashboard/role-management",
|
||||
icon: <AccessibilityIcon />,
|
||||
selected: false,
|
||||
permission: "manage_roles",
|
||||
}
|
||||
render(<MockAppWithProviders><SidebarListItem item={sampleItem} /></MockAppWithProviders>);
|
||||
expect(screen.getByText('مدیریت نقش ها')).toBeInTheDocument();
|
||||
});
|
||||
it('should show sidebarlistitem icon in sidebar', () => {
|
||||
const sampleItem={
|
||||
key: "sidebar.role-management",
|
||||
name : "role_management",
|
||||
type: "page",
|
||||
route: "/dashboard/role-management",
|
||||
icon: <AccessibilityIcon aria-label="Sidebar Icon"/>,
|
||||
selected: false,
|
||||
permission: "manage_roles",
|
||||
}
|
||||
render(<MockAppWithProviders><SidebarListItem item={sampleItem} /></MockAppWithProviders>);
|
||||
const iconElement = screen.getByLabelText("Sidebar Icon");
|
||||
expect(iconElement).toBeInTheDocument();
|
||||
});
|
||||
it('should have selected class for subitem', () => {
|
||||
const sampleItem={
|
||||
key: "sidebar.role-management",
|
||||
name : "role_management",
|
||||
type: "page",
|
||||
route: "/dashboard/role-management",
|
||||
icon: <AccessibilityIcon />,
|
||||
selected: true,
|
||||
permission: "manage_roles",
|
||||
}
|
||||
render(<MockAppWithProviders><SidebarListItem item={sampleItem} /></MockAppWithProviders>);
|
||||
const element = screen.getByText('مدیریت نقش ها');
|
||||
expect(element.parentElement.parentElement).toHaveClass('Mui-selected');
|
||||
});
|
||||
|
||||
it('should not have selected class for subitem', () => {
|
||||
const sampleItem={
|
||||
key: "sidebar.role-management",
|
||||
name : "role_management",
|
||||
type: "menu",
|
||||
route: "/dashboard/role-management",
|
||||
icon: <AccessibilityIcon />,
|
||||
selected: false,
|
||||
permission: "manage_roles",
|
||||
}
|
||||
render(<MockAppWithProviders><SidebarListItem item={sampleItem} /></MockAppWithProviders>);
|
||||
const element = screen.getByText('مدیریت نقش ها');
|
||||
expect(element.parentElement.parentElement).not.toHaveClass('Mui-selected');
|
||||
});
|
||||
|
||||
it('should show sidebarlistitem secondary in sidebar', () => {
|
||||
const sampleItem={
|
||||
key: "sidebar.role-management",
|
||||
name : "role_management",
|
||||
secondary: "between",
|
||||
type: "menu",
|
||||
route: "/dashboard/role-management",
|
||||
icon: <AccessibilityIcon />,
|
||||
selected: false,
|
||||
permission: "manage_roles",
|
||||
}
|
||||
render(<MockAppWithProviders><SidebarListItem item={sampleItem} /></MockAppWithProviders>);
|
||||
expect(screen.getByText('میان')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not show sidebarlistitem secondary in sidebar', () => {
|
||||
const sampleItem={
|
||||
key: "sidebar.role-management",
|
||||
name : "role_management",
|
||||
type: "menu",
|
||||
route: "/dashboard/role-management",
|
||||
icon: <AccessibilityIcon />,
|
||||
selected: false,
|
||||
permission: "manage_roles",
|
||||
}
|
||||
render(<MockAppWithProviders><SidebarListItem item={sampleItem} /></MockAppWithProviders>);
|
||||
expect(screen.queryByText('secondry')).not.toBeInTheDocument();
|
||||
});
|
||||
})
|
||||
describe('Behavior', () => {
|
||||
it('should call dispatch when hasSubItems is true and item is clicked', () => {
|
||||
const dispatchMock = jest.fn();
|
||||
const sampleItem={
|
||||
key: "sidebar.role-management",
|
||||
name : "role_management",
|
||||
type: "menu",
|
||||
route: "/dashboard/role-management",
|
||||
icon: <AccessibilityIcon />,
|
||||
selected: false,
|
||||
permission: "manage_roles",
|
||||
subItem :[
|
||||
{
|
||||
key: "greaterThan",
|
||||
route: "/dashboard/role-management",
|
||||
secondary: "between",
|
||||
name : "sidebar.admin",
|
||||
selected: true,
|
||||
icon: <AccessibilityIcon />,
|
||||
}
|
||||
]
|
||||
}
|
||||
render(<MockAppWithProviders><SidebarListItem item={sampleItem} dispatch={dispatchMock}/></MockAppWithProviders>);
|
||||
const listItem = screen.getByText('مدیریت نقش ها');
|
||||
fireEvent.click(listItem);
|
||||
expect(dispatchMock).toHaveBeenCalledWith({
|
||||
type: 'COLLAPSE_MENU',
|
||||
key: "sidebar.role-management",
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,103 @@
|
||||
import {render, screen} from "@testing-library/react";
|
||||
import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
|
||||
import SidebarListSubItem from "@/components/layouts/Dashboard/Sidebar/SidebarListSubItem";
|
||||
import AccessibilityIcon from "@mui/icons-material/Accessibility";
|
||||
|
||||
describe('SidebarListSubItemComponent', () => {
|
||||
describe('Rendering', () => {
|
||||
const sampleItem={
|
||||
showSubItem:true,
|
||||
key: "sidebar.role-management",
|
||||
name : "role_management",
|
||||
type: "menu",
|
||||
route: "/dashboard/role-management",
|
||||
icon: <AccessibilityIcon />,
|
||||
selected: false,
|
||||
permission: "manage_roles",
|
||||
subItem :[
|
||||
{
|
||||
key: "greaterThan",
|
||||
route: "/dashboard/role-management",
|
||||
secondary: "between",
|
||||
name : "sidebar.admin",
|
||||
selected: true,
|
||||
icon: <AccessibilityIcon aria-label="Sidebar Icon"/>,
|
||||
}
|
||||
]
|
||||
}
|
||||
it('should show subitem name in sidebar', () => {
|
||||
render(<MockAppWithProviders><SidebarListSubItem item={sampleItem} /></MockAppWithProviders>);
|
||||
expect(screen.getByText('بزرگتر از')).toBeInTheDocument();
|
||||
|
||||
});
|
||||
it('should not show subitem name in sidebar', () => {
|
||||
const sampleItem={
|
||||
showSubItem:false,
|
||||
key: "sidebar.role-management",
|
||||
name : "role_management",
|
||||
type: "menu",
|
||||
route: "/dashboard/role-management",
|
||||
icon: <AccessibilityIcon />,
|
||||
selected: false,
|
||||
permission: "manage_roles",
|
||||
subItem :[
|
||||
{
|
||||
key: "greaterThan",
|
||||
route: "/dashboard/role-management",
|
||||
secondary: "between",
|
||||
name : "sidebar.admin",
|
||||
selected: false,
|
||||
icon: <AccessibilityIcon />,
|
||||
}
|
||||
]
|
||||
}
|
||||
render(<MockAppWithProviders><SidebarListSubItem item={sampleItem} /></MockAppWithProviders>);
|
||||
expect(screen.queryByText('مدیریت نقش ها')).not.toBeInTheDocument();
|
||||
});
|
||||
it('should show subitem secondary in sidebar', () => {
|
||||
render(<MockAppWithProviders><SidebarListSubItem item={sampleItem} /></MockAppWithProviders>);
|
||||
expect(screen.getByText('میان')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not show subitem secondary in sidebar', () => {
|
||||
render(<MockAppWithProviders><SidebarListSubItem item={sampleItem} /></MockAppWithProviders>);
|
||||
expect(screen.queryByText('secondry')).not.toBeInTheDocument();
|
||||
});
|
||||
it('should have selected class for subitem', () => {
|
||||
render(<MockAppWithProviders><SidebarListSubItem item={sampleItem} /></MockAppWithProviders>);
|
||||
const parentElement = screen.queryByText('بزرگتر از').parentElement.parentElement;
|
||||
expect(parentElement).toHaveClass('Mui-selected');
|
||||
});
|
||||
|
||||
it('should not have selected class for subitem', () => {
|
||||
const sampleItem={
|
||||
showSubItem:true,
|
||||
key: "sidebar.role-management",
|
||||
name : "role_management",
|
||||
type: "menu",
|
||||
route: "/dashboard/role-management",
|
||||
icon: <AccessibilityIcon />,
|
||||
selected: false,
|
||||
permission: "manage_roles",
|
||||
subItem :[
|
||||
{
|
||||
key: "greaterThan",
|
||||
route: "/dashboard/role-management",
|
||||
secondary: "between",
|
||||
name : "sidebar.admin",
|
||||
selected: false,
|
||||
icon: <AccessibilityIcon />,
|
||||
}
|
||||
]
|
||||
}
|
||||
render(<MockAppWithProviders><SidebarListSubItem item={sampleItem} /></MockAppWithProviders>);
|
||||
const parentElement = screen.queryByText('بزرگتر از').parentElement.parentElement;
|
||||
expect(parentElement).not.toHaveClass('Mui-selected');
|
||||
});
|
||||
it('should show subitem icon', () => {
|
||||
render(<MockAppWithProviders><SidebarListSubItem item={sampleItem} /></MockAppWithProviders>);
|
||||
const iconElement = screen.getByLabelText("Sidebar Icon");
|
||||
expect(iconElement).toBeInTheDocument();
|
||||
});
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,17 @@
|
||||
import {render, screen, act} from "@testing-library/react";
|
||||
import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
|
||||
import Sidebar from "@/components/layouts/Dashboard/Sidebar";
|
||||
|
||||
|
||||
describe('Sidebar', () => {
|
||||
describe('Rendering', () => {
|
||||
it('Mobile Drawer is displayed when mobileOpen is true', () => {
|
||||
const props={
|
||||
mobileOpen: true,
|
||||
};
|
||||
render(<MockAppWithProviders><Sidebar {...props}/></MockAppWithProviders>);
|
||||
const mobileDrawer = screen.getByTestId('mobile-drawer');
|
||||
expect(mobileDrawer).toBeVisible();
|
||||
});
|
||||
})
|
||||
})
|
||||
@@ -9,6 +9,7 @@ const Sidebar = (props) => {
|
||||
aria-label="mailbox folders"
|
||||
>
|
||||
<Drawer
|
||||
data-testid="mobile-drawer"
|
||||
container={props.container}
|
||||
variant="temporary"
|
||||
open={props.mobileOpen}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import useSWR from 'swr'
|
||||
import {GET_SIDEBAR_NOTIFICATION} from "@/core/data/apiRoutes";
|
||||
import useRequest from "@/lib/app/hooks/useRequest";
|
||||
const isNotificationEnabled = process.env.NEXT_HAS_NOTIFICATION === "true";
|
||||
|
||||
const useNotification = () => {
|
||||
|
||||
const requestServer = useRequest({auth: true, notification: false})
|
||||
|
||||
//swr config
|
||||
@@ -13,7 +15,7 @@ const useNotification = () => {
|
||||
})
|
||||
};
|
||||
|
||||
const {data, mutate} = useSWR(GET_SIDEBAR_NOTIFICATION, fetcher)
|
||||
const {data, mutate} = useSWR( isNotificationEnabled ? GET_SIDEBAR_NOTIFICATION : '', fetcher , {keepPreviousData:true})
|
||||
const notification_count = data
|
||||
//swr config
|
||||
|
||||
|
||||
Reference in New Issue
Block a user