Skip to content

Commit

Permalink
User: this pr enables user to logout from one's session
Browse files Browse the repository at this point in the history
  • Loading branch information
MugemaneBertin2001 committed Jul 28, 2024
1 parent 1186659 commit 3a7b49b
Show file tree
Hide file tree
Showing 14 changed files with 544 additions and 168 deletions.
67 changes: 47 additions & 20 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
version: '3.1'

services:
web:
build:
context: .
dockerfile: Dockerfile
container_name: eagle-ec-fe-container
image: mugemanebertin/eagle-ec-fe
ports:
- "5173:5173"
env_file:
- .env

# Backend Service
backend:
image: mugemanebertin/eagle_ec_be:latest
container_name: eagle-ec-be-container
container_name: express-server-container
ports:
- "499:499"
command: sh -c "npm run migrate && (npm run seed || true) && npm run dev"
- "${PORT}:${PORT}"
volumes:
- ./backend:/usr/src/app
- /usr/src/app/node_modules
command: sh -c "npm run migrate && npm run seed || true && npm run dev"
depends_on:
- db
- postgres_db
- redis
env_file:
- ./.env
environment:
- DB_CONNECTION=${DOCKER_DB_CONNECTION}
- JWT_SECRET=${JWT_SECRET}
Expand All @@ -35,12 +30,14 @@ services:
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
- GOOGLE_CALLBACK_URL=${GOOGLE_CALLBACK_URL}
- REDIS_HOST=redis
- REDIS_PORT=6379
- FE_URL=${FE_URL}
networks:
- eagle-ec

db:
# PostgreSQL Database Service
postgres_db:
image: postgres:latest
container_name: eagle-ec-db-container
container_name: postgres-db-container
ports:
- "5433:5432"
environment:
Expand All @@ -49,11 +46,41 @@ services:
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- eagle-ec

# Redis Service
redis:
image: redis:latest
container_name: redis-container
ports:
- "6379:6379"
networks:
- eagle-ec

# Web Frontend Service
frontend:
build:
context: .
dockerfile: Dockerfile
container_name: eagle-ec-fe-container
image: mugemanebertin/eagle-ec-fe
ports:
- "5173:5173"
env_file:
- ./.env
volumes:
- ./frontend:/app
- /app/node_modules
networks:
- eagle-ec
command: npm run dev -- --host
depends_on:
- backend

volumes:
postgres_data:
postgres_data:

networks:
eagle-ec:
driver: bridge
126 changes: 126 additions & 0 deletions src/__test__/LogoutContext.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import "@testing-library/jest-dom";
import React from "react";
import {
render, screen, fireEvent, waitFor,
} from "@testing-library/react";

import {
LogoutProvider,
useLogout,
} from "../components/dashboard/admin/LogoutContext";
import api from "../redux/api/api";

// Mock the API and localStorage
jest.mock("../redux/api/api");
const mockPost = api.post as jest.MockedFunction<typeof api.post>;

// Mock LogoutModal component
jest.mock("../components/dashboard/admin/LogoutModal", () => ({
__esModule: true,
default: ({ isOpen, onClose, onConfirm }: any) =>
(isOpen ? (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
<div className="p-6 bg-white rounded shadow-lg">
<h2 className="mb-4 text-xl">Confirm Logout</h2>
<p className="mb-4">Are you sure you want to logout?</p>
<div className="flex justify-end gap-4">
<button
className="px-4 py-2 text-white bg-gray-500 rounded"
onClick={onClose}
>
Cancel
</button>
<button
className="px-4 py-2 text-white bg-red-500 rounded"
onClick={onConfirm}
>
Logout
</button>
</div>
</div>
</div>
) : null),
}));

const TestComponent: React.FC = () => {
const { openLogoutModal } = useLogout();
return <button onClick={openLogoutModal}>Open Logout Modal</button>;
};

describe("LogoutProvider Component", () => {
beforeAll(() => {
jest.spyOn(console, "error").mockImplementation(() => {});
});

afterAll(() => {
(console.error as jest.Mock).mockRestore();
});

it("should render LogoutProvider and trigger logout modal", () => {
render(
<LogoutProvider>
<TestComponent />
</LogoutProvider>,
);

const openModalButton = screen.getByText("Open Logout Modal");
fireEvent.click(openModalButton);

// Verify that the modal is rendered
expect(screen.getByText("Confirm Logout")).toBeInTheDocument();
expect(
screen.getByText("Are you sure you want to logout?"),
).toBeInTheDocument();
expect(screen.getByText("Cancel")).toBeInTheDocument();
expect(screen.getByText("Logout")).toBeInTheDocument();
});

it("should call confirmLogout and perform logout", async () => {
localStorage.setItem("accessToken", "mockToken");
mockPost.mockResolvedValue({});

render(
<LogoutProvider>
<TestComponent />
</LogoutProvider>,
);

fireEvent.click(screen.getByText("Open Logout Modal"));
fireEvent.click(screen.getByText("Logout"));

await waitFor(() => {
expect(mockPost).toHaveBeenCalledWith(
"/users/logout",
{},
{
headers: {
Authorization: `Bearer mockToken`,
Accept: "*/*",
},
},
);
expect(localStorage.getItem("accessToken")).toBeNull();
});
});

it("should handle logout failure", async () => {
localStorage.setItem("accessToken", "mockToken");
mockPost.mockRejectedValue(new Error("Network error"));

render(
<LogoutProvider>
<TestComponent />
</LogoutProvider>,
);

fireEvent.click(screen.getByText("Open Logout Modal"));
fireEvent.click(screen.getByText("Logout"));

await waitFor(() => {
expect(console.error).toHaveBeenCalledWith(
"Failed to logout:",
expect.any(Error),
);
});
});
});
Loading

0 comments on commit 3a7b49b

Please sign in to comment.