diff --git a/.nyc_output/out.json b/.nyc_output/out.json index ee59ebc..4cc75eb 100644 --- a/.nyc_output/out.json +++ b/.nyc_output/out.json @@ -422,15 +422,6 @@ "f": {}, "b": {} }, - "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/app/api/requests/team-overall/route.js": { - "path": "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/app/api/requests/team-overall/route.js", - "statementMap": {}, - "fnMap": {}, - "branchMap": {}, - "s": {}, - "f": {}, - "b": {} - }, "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/app/context/arrangements/requests/arrangement-request-context.js": { "path": "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/app/context/arrangements/requests/arrangement-request-context.js", "statementMap": {}, @@ -557,15 +548,6 @@ "f": {}, "b": {} }, - "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/instrumented/api/requests/team-overall/route.js": { - "path": "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/instrumented/api/requests/team-overall/route.js", - "statementMap": {}, - "fnMap": {}, - "branchMap": {}, - "s": {}, - "f": {}, - "b": {} - }, "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/instrumented/context/arrangements/requests/arrangement-request-context.js": { "path": "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/instrumented/context/arrangements/requests/arrangement-request-context.js", "statementMap": {}, @@ -656,15 +638,6 @@ "f": {}, "b": {} }, - "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/app/api/requests/all-personal-arrangement/withdrawn/route.js": { - "path": "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/app/api/requests/all-personal-arrangement/withdrawn/route.js", - "statementMap": {}, - "fnMap": {}, - "branchMap": {}, - "s": {}, - "f": {}, - "b": {} - }, "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/instrumented/api/arrangements/all-personal-arrangement/withdrawn/route.js": { "path": "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/instrumented/api/arrangements/all-personal-arrangement/withdrawn/route.js", "statementMap": {}, @@ -692,15 +665,6 @@ "f": {}, "b": {} }, - "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/instrumented/api/requests/all-personal-arrangement/withdrawn/route.js": { - "path": "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/instrumented/api/requests/all-personal-arrangement/withdrawn/route.js", - "statementMap": {}, - "fnMap": {}, - "branchMap": {}, - "s": {}, - "f": {}, - "b": {} - }, "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/app/api/arrangements/pending/recurring/[arrangementID]/route.js": { "path": "/Users/ongsweelong/Library/CloudStorage/OneDrive-SingaporeManagementUniversity/Y3S1/SPM IS212/Project/wfh-tracking-system/app/api/arrangements/pending/recurring/[arrangementID]/route.js", "statementMap": {}, diff --git a/__tests__/all.test.js b/__tests__/all.test.js deleted file mode 100644 index 7545b9c..0000000 --- a/__tests__/all.test.js +++ /dev/null @@ -1,186 +0,0 @@ -// Endpoint unit test for US 4 http://localhost:3000/api/request/team-overall - -import { GET } from "@/app/api/requests/team-overall/route.js"; // Adjust the import path as necessary -import connection from "../app/lib/db"; // Adjust path as necessary -import { NextResponse } from "next/server"; // Import NextResponse for testing - -jest.mock("../app/lib/db"); // Mock the database connection - -describe("GET /api/requests/team-overall", () => { - let request; - - beforeEach(() => { - request = { - nextUrl: { - searchParams: new URLSearchParams({ - staffID: "12345", // Example Staff ID - }), - }, - }; - }); - - it("should return 200 and data for senior management", async () => { - const mockPositionData = [{ Position: "MD" }]; - const mockData = [ - { - Staff_ID: "1", - Staff_FName: "John", - Staff_LName: "Doe", - Dept: "HR", - Position: "MD", - Email: "john.doe@example.com", - Reporting_Manager: "Manager1", - Request_Status: "Approved", - Applied_Datetime: "2024-01-01 10:00:00", - Start_Date: "2024-01-02", - Shift_Type: "Morning", - }, - ]; - - const mockConn = { - query: jest.fn() - .mockResolvedValueOnce([mockPositionData]) - .mockResolvedValueOnce([mockData]), - release: jest.fn(), - }; - - const mockPool = { - getConnection: jest.fn().mockResolvedValue(mockConn), - }; - - connection.mockResolvedValue(mockPool); - - const response = await GET(request); - - expect(response.status).toBe(200); - expect(await response.json()).toEqual(mockData); - expect(mockConn.query).toHaveBeenCalledTimes(2); - expect(mockConn.release).toHaveBeenCalled(); - }); - - it("should return 200 and data for non-senior staff", async () => { - const mockPositionData = [{ Position: "Employee" }]; - const mockData = [ - { - Staff_ID: "2", - Staff_FName: "Jane", - Staff_LName: "Smith", - Dept: "IT", - Position: "Employee", - Email: "jane.smith@example.com", - Reporting_Manager: "Manager1", - Arrangement_Ids: "1,2", - Request_Status: "Pending", - Applied_Datetime: "2024-01-03 10:00:00", - Start_Date: "2024-01-04", - Shift_Type: "Afternoon", - }, - ]; - - const mockConn = { - query: jest.fn() - .mockResolvedValueOnce([mockPositionData]) - .mockResolvedValueOnce([mockData]), - release: jest.fn(), - }; - - const mockPool = { - getConnection: jest.fn().mockResolvedValue(mockConn), - }; - - connection.mockResolvedValue(mockPool); - - const response = await GET(request); - - expect(response.status).toBe(200); - expect(await response.json()).toEqual(mockData); - expect(mockConn.query).toHaveBeenCalledTimes(2); - expect(mockConn.release).toHaveBeenCalled(); - }); - - it("should return 404 if no employee is found", async () => { - const mockPositionData = []; // Mock empty position data - - const mockConn = { - query: jest.fn().mockResolvedValueOnce([mockPositionData]), // No results for position - release: jest.fn(), // Mock connection release function - }; - - const mockPool = { - getConnection: jest.fn().mockResolvedValue(mockConn), // Mock getting connection from pool - }; - - connection.mockResolvedValue(mockPool); // Mock the connection pool - - const response = await GET(request); // Call the GET function - - expect(response.status).toBe(404); // Check if the status is 404 - expect(await response.json()).toEqual({ error: "No employee found with the provided Staff_ID" }); // Check error response - expect(mockConn.release).toHaveBeenCalled(); // Ensure connection is released - }); - - it("should return 200 with no arrangements for non-senior staff with no reporting manager", async () => { - const mockPositionData = [{ Position: "Employee" }]; - const mockData = []; // No data for the non-senior staff - - const mockConn = { - query: jest.fn() - .mockResolvedValueOnce([mockPositionData]) // Non-senior position - .mockResolvedValueOnce([mockData]), // No arrangements for reporting team - release: jest.fn(), - }; - - const mockPool = { - getConnection: jest.fn().mockResolvedValue(mockConn), - }; - - connection.mockResolvedValue(mockPool); - - const response = await GET(request); - - expect(response.status).toBe(200); // Should return 200 even if no arrangements exist - expect(await response.json()).toEqual(mockData); // Expect an empty array or no data - expect(mockConn.query).toHaveBeenCalledTimes(2); - expect(mockConn.release).toHaveBeenCalled(); - }); - - it("should return 500 if there is a database error", async () => { - const errorMessage = "An unexpected error occurred."; // Simulated error message - const mockConn = { - query: jest.fn().mockRejectedValueOnce(new Error(errorMessage)), // Simulate DB query error - release: jest.fn(), // Mock connection release function - }; - - const mockPool = { - getConnection: jest.fn().mockResolvedValue(mockConn), // Mock getting connection from pool - }; - - connection.mockResolvedValue(mockPool); // Mock the connection pool - - const response = await GET(request); // Call the GET function - - expect(response.status).toBe(500); // Check if the status is 500 - const jsonResponse = await response.json(); // Read the response body once - expect(jsonResponse).toEqual({ error: errorMessage }); // Check if the response contains the error message - expect(mockConn.release).toHaveBeenCalled(); // Ensure connection is released -}); - - it("should return an unexpected error message if a generic error occurs", async () => { - const mockConn = { - query: jest.fn().mockRejectedValueOnce(new Error("An unexpected error occurred")), // Simulate a generic error - release: jest.fn(), - }; - - const mockPool = { - getConnection: jest.fn().mockResolvedValue(mockConn), - }; - - connection.mockResolvedValue(mockPool); // Mock the connection pool - - const response = await GET(request); // Call the GET function - - expect(response.status).toBe(500); // Check if the status is 500 - expect(await response.json()).toEqual({ error: "An unexpected error occurred." }); // Check if the response contains the specific error message - expect(mockConn.release).toHaveBeenCalled(); // Ensure connection is released - }); -}); diff --git a/app/api/requests/all-personal-arrangement/withdrawn/route.js b/app/api/requests/all-personal-arrangement/withdrawn/route.js deleted file mode 100755 index e296f30..0000000 --- a/app/api/requests/all-personal-arrangement/withdrawn/route.js +++ /dev/null @@ -1,121 +0,0 @@ -import connection from "@/app/lib/db"; -import { NextResponse } from "next/server"; -import { sendNotification } from "@/app/lib/notificationService.js"; - -// Example Endpoint: http://localhost:3000/api/requests/update-status -export async function PUT(request) { - try { - // Establish the connection using the pool - const pool = await connection(); - const conn = await pool.getConnection(); - - // Get Staff_ID input from the request - const searchParams = request.nextUrl.searchParams; - const staffID = searchParams.get("staffID"); - console.log("Staff ID:", staffID); - - // Parse the request body to get Arrangement_ID, Request_Status, and Update_Reason - const { Arrangement_ID, Request_Status, Update_Reason } = await request.json(); - - // Check that all parameters are provided - if (!Arrangement_ID || !Request_Status || !Update_Reason) { - return NextResponse.json( - { message: "Arrangement_ID, Request_Status, and Update_Reason are required." }, - { status: 400 } // Use 400 Bad Request for missing parameters - ); - } - - // Execute the query to update the Request_Status and Update_Reason - const [data] = await conn.query( - ` - UPDATE Arrangement - SET Request_Status = ?, Update_Reason = ? - WHERE Arrangement_ID = ?; - `, - [Request_Status, Update_Reason, Arrangement_ID] - ); - - // Check if any rows were affected (i.e., whether the update was successful) - if (data.affectedRows === 0) { - conn.release(); - return NextResponse.json( - { message: "No arrangement found with the given Arrangement_ID." }, - { status: 404 } // Not Found status if no matching Arrangement_ID - ); - } - - // ----Preparation for Notification---- - // Get the reporting manager's ID for the current staff - const managerResult = await conn.query( - ` - SELECT Reporting_Manager FROM Employee - WHERE Staff_ID = ? - `, - [staffID] - ); - - if (!managerResult || managerResult.length === 0) { - console.error(`No reporting manager found for staff ID ${staffID}`); - conn.release(); - return NextResponse.json( - { message: `No reporting manager found for staff ID ${staffID}` }, - { status: 404 } - ); - } - - const managerID = managerResult[0][0].Reporting_Manager; - - // Get the email of the reporting manager - const getEmailQuery = ` - SELECT Email FROM Employee - WHERE Staff_ID = ? - `; - const emailResult = await conn.query(getEmailQuery, [managerID]); - - if (!emailResult || emailResult.length === 0) { - console.error(`No email found for reporting manager ID ${managerID}`); - conn.release(); - return NextResponse.json( - { message: `No email found for reporting manager ID ${managerID}` }, - { status: 404 } - ); - } - - const managerEmail = emailResult[0][0].Email; - - // Prepare email content - const subject = "WFH Request Withdrawn"; - const body = `Dear Manager/Director ${managerID} (${managerEmail}),\n - A work-from-home arrangement has been withdrawn:\n - Staff ID: ${staffID}\n - Withdraw Reason: ${Update_Reason || "N/A"}\n\n - Please review the request, thank you.\n\n`; - - // Send notification using Mailtrap (or any email service) - try { - console.log("Sending email to:", managerEmail); - await sendNotification(subject, body); - } catch (emailError) { - console.error("Error sending email notification:", emailError); - conn.release(); - return NextResponse.json( - { message: "Failed to send notification email.", details: emailError.message }, - { status: 500 } - ); - } - // ----End of Notification---- - - // Release the connection back to the pool - conn.release(); - - // Return success message if withdrawn was successful - return NextResponse.json( - { message: "Arrangement is successfully withdrawn, and notification sent." }, - { status: 200 } - ); - } catch (error) { - // Handle any errors and return an error response - console.error("Error occurred:", error); - return NextResponse.json({ message: "Internal server error", details: error.message }, { status: 500 }); - } -} \ No newline at end of file diff --git a/app/api/requests/team-overall/route.js b/app/api/requests/team-overall/route.js deleted file mode 100755 index 493b538..0000000 --- a/app/api/requests/team-overall/route.js +++ /dev/null @@ -1,98 +0,0 @@ -import connection from "@/app/lib/db"; -import { NextResponse } from "next/server"; - -// Example endpoint to fetch all records from the employee table -export async function GET(request) { - let conn; - try { - // Establish the connection using the pool - const pool = await connection(); - conn = await pool.getConnection(); // Get a connection from the pool - - // Get Staff_ID from the request - const searchParams = request.nextUrl.searchParams; - const staffID = searchParams.get("staffID"); - - // Query to get Position from the Employee table - const [positionData] = await conn.query( - ` - SELECT Position - FROM Employee - WHERE Staff_ID = ? - `, - [staffID], - ); - - // Check if the query returned any results - if (positionData.length === 0) { - return NextResponse.json( - { error: "No employee found with the provided Staff_ID" }, - { status: 404 }, - ); - } - - // Extract Position from the query result - const { Position } = positionData[0]; - - // Array of valid positions that can view the entire organization - const HR_Senior_Management = ["MD", "Director", "HR Team"]; - - // Initialize data variable for query results - let data; - - // Conditional Query based on Position - if (HR_Senior_Management.includes(Position)) { - // Query for senior management to view entire organisation - [data] = await conn.query(` - SELECT Employee.Staff_ID, Employee.Staff_FName, Employee.Staff_LName, Employee.Dept, Employee.Position, Employee.Email, Employee.Reporting_Manager, - GROUP_CONCAT(Arrangement.Request_Status) AS Request_Status, - GROUP_CONCAT(Arrangement.Applied_Datetime) AS Applied_Datetime, - GROUP_CONCAT(Arrangement.Start_Date) AS Start_Date, - GROUP_CONCAT(Arrangement.Shift_Type) AS Shift_Type - FROM Arrangement - RIGHT JOIN Employee ON Employee.Staff_ID = Arrangement.Staff_ID - GROUP BY Employee.Staff_ID; - `); - } else { - // Query for non-senior staff, limited to their reporting team - [data] = await conn.query( - ` - SELECT Employee.Staff_ID, Employee.Staff_FName, Employee.Staff_LName, Employee.Dept, Employee.Position, Employee.Email, Employee.Reporting_Manager, - GROUP_CONCAT(Arrangement.Arrangement_ID) AS Arrangement_Ids, - GROUP_CONCAT(Arrangement.Request_Status) as Request_Status, - GROUP_CONCAT(Arrangement.Applied_Datetime) as Applied_Datetime, - GROUP_CONCAT(Arrangement.Start_Date) as Start_Date, - GROUP_CONCAT(Arrangement.Shift_Type) as Shift_Type - FROM Arrangement - RIGHT JOIN Employee ON Employee.Staff_ID = Arrangement.Staff_ID - WHERE Employee.Staff_ID IN ( - SELECT Staff_ID - FROM Employee - WHERE Reporting_Manager = ( - SELECT Reporting_Manager - FROM Employee - WHERE Staff_ID = ? - ) - ) - GROUP BY Employee.Staff_ID; - `, - [staffID], - ); - } - - // Return the fetched data as a JSON response - return NextResponse.json(data, { status: 200 }); - - } catch (error) { - // Return a structured error response - return NextResponse.json( - { error: "An unexpected error occurred." }, //corrected error handling - { status: 500 } - ); - } finally { - if (conn) { - conn.release(); // Ensure the connection is released - } - } -} - diff --git a/cypress/e2e/Actual-Tests/test_case_3_1.cy.js b/cypress/e2e/Actual-Tests/test_case_3_1.cy.js index 5b3fbd9..09816d9 100644 --- a/cypress/e2e/Actual-Tests/test_case_3_1.cy.js +++ b/cypress/e2e/Actual-Tests/test_case_3_1.cy.js @@ -78,7 +78,7 @@ describe("View Team's Schedule for Manager/Director", () => { cy.get('[role="tablist"]').contains("Work-From-Home").click(); // Verify number of records under the tab - cy.get('[role="tabpanel"]', { timeout: 10000 }).contains("John Lim"); + cy.get('[role="tabpanel"]').should("have.length", 3); // Verify the content of the first record cy.get(