Skip to content

Commit c62ea67

Browse files
User: this pr enables user to logout from one's session
1 parent 968b444 commit c62ea67

22 files changed

+1002
-247
lines changed

docker-compose.yml

+47-20
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,21 @@
11
version: '3.1'
22

33
services:
4-
web:
5-
build:
6-
context: .
7-
dockerfile: Dockerfile
8-
container_name: eagle-ec-fe-container
9-
image: mugemanebertin/eagle-ec-fe
10-
ports:
11-
- "5173:5173"
12-
env_file:
13-
- .env
14-
4+
# Backend Service
155
backend:
166
image: mugemanebertin/eagle_ec_be:latest
17-
container_name: eagle-ec-be-container
7+
container_name: express-server-container
188
ports:
19-
- "499:499"
20-
command: sh -c "npm run migrate && (npm run seed || true) && npm run dev"
9+
- "${PORT}:${PORT}"
10+
volumes:
11+
- ./backend:/usr/src/app
12+
- /usr/src/app/node_modules
13+
command: sh -c "npm run migrate && npm run seed || true && npm run dev"
2114
depends_on:
22-
- db
15+
- postgres_db
2316
- redis
17+
env_file:
18+
- ./.env
2419
environment:
2520
- DB_CONNECTION=${DOCKER_DB_CONNECTION}
2621
- JWT_SECRET=${JWT_SECRET}
@@ -35,12 +30,14 @@ services:
3530
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
3631
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
3732
- GOOGLE_CALLBACK_URL=${GOOGLE_CALLBACK_URL}
38-
- REDIS_HOST=redis
39-
- REDIS_PORT=6379
33+
- FE_URL=${FE_URL}
34+
networks:
35+
- eagle-ec
4036

41-
db:
37+
# PostgreSQL Database Service
38+
postgres_db:
4239
image: postgres:latest
43-
container_name: eagle-ec-db-container
40+
container_name: postgres-db-container
4441
ports:
4542
- "5433:5432"
4643
environment:
@@ -49,11 +46,41 @@ services:
4946
- POSTGRES_DB=${POSTGRES_DB}
5047
volumes:
5148
- postgres_data:/var/lib/postgresql/data
49+
networks:
50+
- eagle-ec
5251

52+
# Redis Service
5353
redis:
5454
image: redis:latest
55+
container_name: redis-container
5556
ports:
5657
- "6379:6379"
58+
networks:
59+
- eagle-ec
60+
61+
# Web Frontend Service
62+
frontend:
63+
build:
64+
context: .
65+
dockerfile: Dockerfile
66+
container_name: eagle-ec-fe-container
67+
image: mugemanebertin/eagle-ec-fe
68+
ports:
69+
- "5173:5173"
70+
env_file:
71+
- ./.env
72+
volumes:
73+
- ./frontend:/app
74+
- /app/node_modules
75+
networks:
76+
- eagle-ec
77+
command: npm run dev -- --host
78+
depends_on:
79+
- backend
5780

5881
volumes:
59-
postgres_data:
82+
postgres_data:
83+
84+
networks:
85+
eagle-ec:
86+
driver: bridge

src/__test__/HomeButton.test.tsx

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import "@testing-library/jest-dom";
2+
import { render, screen } from "@testing-library/react";
3+
import { MemoryRouter, Routes, Route } from "react-router-dom";
4+
5+
import HomeButton from "../components/dashboard/HomeButton";
6+
7+
describe("HomeButton", () => {
8+
it("should render the Home button", () => {
9+
render(
10+
<MemoryRouter initialEntries={["/test"]}>
11+
<Routes>
12+
<Route path="/test" element={<HomeButton />} />
13+
</Routes>
14+
</MemoryRouter>,
15+
);
16+
17+
const homeButton = screen.getByText("Home");
18+
expect(homeButton).toBeInTheDocument();
19+
});
20+
});

src/__test__/LogoutContext.test.tsx

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import "@testing-library/jest-dom";
2+
import React from "react";
3+
import { render, screen, fireEvent } from "@testing-library/react";
4+
5+
import {
6+
LogoutProvider,
7+
useLogout,
8+
} from "../components/dashboard/admin/LogoutContext";
9+
10+
// Mock LogoutModal component
11+
jest.mock("../components/dashboard/admin/LogoutModal", () => ({
12+
__esModule: true,
13+
default: ({ isOpen, onClose, onConfirm }: any) =>
14+
(isOpen ? (
15+
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
16+
<div className="p-6 bg-white rounded shadow-lg">
17+
<h2 className="mb-4 text-xl">Confirm Logout</h2>
18+
<p className="mb-4">Are you sure you want to logout?</p>
19+
<div className="flex justify-end gap-4">
20+
<button
21+
className="px-4 py-2 text-white bg-gray-500 rounded"
22+
onClick={onClose}
23+
>
24+
Cancel
25+
</button>
26+
<button
27+
className="px-4 py-2 text-white bg-red-500 rounded"
28+
onClick={onConfirm}
29+
>
30+
Logout
31+
</button>
32+
</div>
33+
</div>
34+
</div>
35+
) : null),
36+
}));
37+
38+
const TestComponent: React.FC = () => {
39+
const { openLogoutModal } = useLogout();
40+
return <button onClick={openLogoutModal}>Open Logout Modal</button>;
41+
};
42+
43+
describe("LogoutProvider Component", () => {
44+
it("should render LogoutProvider and trigger logout modal", () => {
45+
render(
46+
<LogoutProvider>
47+
<TestComponent />
48+
</LogoutProvider>,
49+
);
50+
51+
const openModalButton = screen.getByText("Open Logout Modal");
52+
fireEvent.click(openModalButton);
53+
54+
// Verify that the modal is rendered
55+
expect(screen.getByText("Confirm Logout")).toBeInTheDocument();
56+
expect(
57+
screen.getByText("Are you sure you want to logout?"),
58+
).toBeInTheDocument();
59+
expect(screen.getByText("Cancel")).toBeInTheDocument();
60+
expect(screen.getByText("Logout")).toBeInTheDocument();
61+
});
62+
});

src/__test__/ProfileDropdown.test.tsx

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import "@testing-library/jest-dom";
2+
import React from "react";
3+
import { render, screen, fireEvent } from "@testing-library/react";
4+
import { BrowserRouter as Router } from "react-router-dom";
5+
6+
import { useLogout } from "../components/dashboard/admin/LogoutContext"; // Ensure the correct path
7+
import ProfileDropdown from "../components/common/ProfileDropdown";
8+
9+
// Mock the useLogout hook
10+
jest.mock("../components/dashboard/admin/LogoutContext", () => ({
11+
useLogout: jest.fn(),
12+
}));
13+
14+
describe("ProfileDropdown", () => {
15+
const openLogoutModalMock = jest.fn();
16+
17+
beforeEach(() => {
18+
(useLogout as jest.Mock).mockReturnValue({
19+
openLogoutModal: openLogoutModalMock,
20+
});
21+
});
22+
23+
afterEach(() => {
24+
jest.clearAllMocks();
25+
});
26+
27+
it("should render profile and orders links for a user with roleId 1", () => {
28+
const userInfo = { roleId: 1 };
29+
30+
render(
31+
<Router>
32+
<ProfileDropdown userInfo={userInfo} />
33+
</Router>,
34+
);
35+
36+
expect(screen.getByText("Profile")).toBeInTheDocument();
37+
expect(screen.getByText("My Orders")).toBeInTheDocument();
38+
expect(screen.getByText("Logout")).toBeInTheDocument();
39+
});
40+
41+
it("should render the correct dashboard link for roleId 2", () => {
42+
const userInfo = { roleId: 2 };
43+
44+
render(
45+
<Router>
46+
<ProfileDropdown userInfo={userInfo} />
47+
</Router>,
48+
);
49+
50+
expect(screen.getByText("My Dashboard")).toBeInTheDocument();
51+
expect(screen.getByRole("link", { name: /My Dashboard/i })).toHaveAttribute(
52+
"href",
53+
"/dashboard",
54+
);
55+
});
56+
57+
it("should render the correct dashboard link for roleId 3", () => {
58+
const userInfo = { roleId: 3 };
59+
60+
render(
61+
<Router>
62+
<ProfileDropdown userInfo={userInfo} />
63+
</Router>,
64+
);
65+
66+
expect(screen.getByText("My Dashboard")).toBeInTheDocument();
67+
expect(screen.getByRole("link", { name: /My Dashboard/i })).toHaveAttribute(
68+
"href",
69+
"/admin/dashboard",
70+
);
71+
});
72+
73+
it("should call openLogoutModal when logout button is clicked", () => {
74+
const userInfo = { roleId: 1 };
75+
76+
render(
77+
<Router>
78+
<ProfileDropdown userInfo={userInfo} />
79+
</Router>,
80+
);
81+
82+
const logoutButton = screen.getByText("Logout");
83+
fireEvent.click(logoutButton);
84+
85+
expect(openLogoutModalMock).toHaveBeenCalled();
86+
});
87+
88+
it("should render login link if userInfo is not provided", () => {
89+
render(
90+
<Router>
91+
<ProfileDropdown userInfo={null} />
92+
</Router>,
93+
);
94+
95+
expect(screen.getByText("Login")).toBeInTheDocument();
96+
});
97+
});

0 commit comments

Comments
 (0)