From 9d81b83afcdbe80b2039ce47cf1a6b2368821fe0 Mon Sep 17 00:00:00 2001
From: Giang Vu <dhgiang.vu@gmail.com>
Date: Wed, 9 Oct 2024 12:02:16 +1100
Subject: [PATCH] feat: update integration tests to work with Basic Auth

---
 frontend/src/scripts/api.ts    |  12 ++-
 frontend/src/tests/api.test.ts | 131 +++++++++++++++++----------------
 2 files changed, 77 insertions(+), 66 deletions(-)

diff --git a/frontend/src/scripts/api.ts b/frontend/src/scripts/api.ts
index 17c1326..41b56e2 100644
--- a/frontend/src/scripts/api.ts
+++ b/frontend/src/scripts/api.ts
@@ -1,8 +1,8 @@
 import { AuthHeader } from "../security/AuthContext";
 
 /* Timetable solver backend endpoint URL */
-const API_URL = "http://localhost:8080/timetabling";
-export const LOCAL_API_URL = "http://localhost:8080"
+export const API_URL = "http://localhost:8080";
+export const LOCAL_API_URL = "http://localhost:8080";
 
 /* =========================================== Defining types =========================================== */
 
@@ -62,9 +62,13 @@ export type Time = string;
  * @param problem A TimetableProblem is a list of units with no allocated time and room.
  * @returns A TimetableSolution with all units allocated a time and a room.
  */
-export async function fetchTimetableSolution(problem: TimetableProblem, authHeader: AuthHeader): Promise<TimetableSolution | null> {
+export async function fetchTimetableSolution(problem: TimetableProblem, authHeader: AuthHeader, url?: string): Promise<TimetableSolution | null> {
   try {
-    const response = await fetch(API_URL, {
+    let api_url = API_URL;
+    if (url !== undefined) {
+      api_url = url;
+    }
+    const response = await fetch(api_url+"/timetabling", {
       method: 'POST',
       headers: {
         'Content-Type': 'application/json',
diff --git a/frontend/src/tests/api.test.ts b/frontend/src/tests/api.test.ts
index 235c6bf..0f26572 100644
--- a/frontend/src/tests/api.test.ts
+++ b/frontend/src/tests/api.test.ts
@@ -1,73 +1,80 @@
+import { describe, it, expect } from 'vitest';
+import { fetchTimetableSolution, LOCAL_API_URL, TimetableProblem } from '../scripts/api';
+import moment from 'moment';
+import { AuthHeader } from '../security/AuthContext';
+
 /**
- * NOTE: NEED TO FIX THESE TESTS / THINK OF A WAY TO MAKE THESE TESTS WORK NOW THAT WE HAVE BASIC AUTH IN BACKEND.
+ * Test fetchTimetableSolution API method.
+ * Check if connection to backend is working.
+ * Check that output matches expected output.
  */
+describe('fetchTimetableSolution', { timeout: 200000 }, () => {
+  /**
+   * Validate end-to-end scheduling and data consistency of 1 API method call.
+   */
+  it('return TimetableSolution', async () => {
+    const problem: TimetableProblem = {
+      campusName: "Geelong",
+      units: [{ campus: "Geelong", course: "B", unitId: 0, name: "Unit0", duration: 1200, students: [], wantsLab: true }],
+      daysOfWeek: ["MONDAY"],
+      startTimes: ["11:00:00"],
+      rooms: [{ campus: "Geelong", buildingId: "01", roomCode: "Room A", capacity: 10, lab: true }]
+    };
 
+    const authHeader: AuthHeader = `Basic ${btoa(`${import.meta.env.VITE_FRONTEND_USERNAME}:${import.meta.env.VITE_FRONTEND_PASSWORD}`)}`;
 
-// import { describe, it, expect } from 'vitest';
-// import { fetchTimetableSolution, TimetableProblem } from '../scripts/api';
-// import moment from 'moment';
-
-// /**
-//  * Test fetchTimetableSolution API method.
-//  * Check if connection to backend is working.
-//  * Check that output matches expected output.
-//  */
-// describe('fetchTimetableSolution', { timeout: 60000 }, () => {
-//   /**
-//    * Validate end-to-end scheduling and data consistency of 1 API method call.
-//    */
-//   it('return TimetableSolution', async () => {
-//     const problem: TimetableProblem = {
-//       campusName: "A",
-//       units: [{ campus: "A", course: "B", unitId: 0, name: "Unit0", duration: 1200, students: [], wantsLab: true }],
-//       daysOfWeek: ["MONDAY"],
-//       startTimes: ["11:00:00"],
-//       rooms: [{ campus: "A", buildingId: "01", roomCode: "Room A", capacity: 10, lab: true }]
-//     };
-    
-//     const solution = await fetchTimetableSolution(problem, '');
-//     expect(solution).not.toBeNull();
-//     expect(solution?.units[0].dayOfWeek).toEqual(problem.daysOfWeek[0]);
-//     expect(solution?.units[0].startTime).toEqual(problem.startTimes[0]);
-//     expect(solution?.units[0].end).toEqual(addSecondsToTimeString(problem.startTimes[0], problem.units[0].duration));
-//     expect(solution?.units[0].room).toHaveProperty("roomCode", problem.rooms[0].roomCode);
-//     expect(solution?.daysOfWeek).toEqual(problem.daysOfWeek);
-//     expect(solution?.startTimes).toEqual(problem.startTimes);
+    const solution = await fetchTimetableSolution(problem, authHeader, LOCAL_API_URL);
+    expect(solution).not.toBeNull();
+    expect(solution?.units[0].dayOfWeek).toEqual(problem.daysOfWeek[0]);
+    expect(solution?.units[0].startTime).toEqual(problem.startTimes[0]);
+    expect(solution?.units[0].end).toEqual(addSecondsToTimeString(problem.startTimes[0], problem.units[0].duration));
+    expect(solution?.units[0].room).toHaveProperty("roomCode", problem.rooms[0].roomCode);
+    expect(solution?.daysOfWeek).toEqual(problem.daysOfWeek);
+    expect(solution?.startTimes).toEqual(problem.startTimes);
     
-//   });
+  });
 
-//   /**
-//    * Validate that backend server can handle multiple solve requests concurrently.
-//    */
-//   it ('can be called multiple times', async () => {
-//     const problem: TimetableProblem = {
-//       campusName: "B",
-//       units: [{ campus: "B", course: "C", unitId: 0, name: "Unit0", duration: 1200, students: [], wantsLab: true }],
-//       daysOfWeek: ["MONDAY"],
-//       startTimes: ["11:00:00"],
-//       rooms: [{ campus: "B", buildingId: "02", roomCode: "Room A", capacity: 10, lab: true }]
-//     };
+  /**
+   * Validate that backend server can handle multiple solve requests concurrently.
+   */
+  it ('can be called multiple times', async () => {
+    const problem0: TimetableProblem = {
+      campusName: "Adelaide",
+      units: [{ campus: "Adelaide", course: "C", unitId: 0, name: "Unit0", duration: 1200, students: [], wantsLab: true }],
+      daysOfWeek: ["MONDAY"],
+      startTimes: ["11:00:00"],
+      rooms: [{ campus: "Adelaide", buildingId: "02", roomCode: "Room A", capacity: 10, lab: true }]
+    };
 
-//     const solutions = await Promise.all([fetchTimetableSolution(problem, ''), fetchTimetableSolution(problem, ''), fetchTimetableSolution(problem, '')]);
+    const problem1: TimetableProblem = {
+      campusName: "Melbourne",
+      units: [{ campus: "Melbourne", course: "C", unitId: 0, name: "Unit0", duration: 1200, students: [], wantsLab: true }],
+      daysOfWeek: ["MONDAY"],
+      startTimes: ["11:00:00"],
+      rooms: [{ campus: "Melbourne", buildingId: "02", roomCode: "Room A", capacity: 10, lab: true }]
+    };
+
+    const authHeader: AuthHeader = `Basic ${btoa(`${import.meta.env.VITE_FRONTEND_USERNAME}:${import.meta.env.VITE_FRONTEND_PASSWORD}`)}`;
+    const solutions = await Promise.all([fetchTimetableSolution(problem0, authHeader, LOCAL_API_URL), fetchTimetableSolution(problem1, authHeader, LOCAL_API_URL)]);
     
-//     for (let i = 0; i < solutions.length; i++) {
-//       expect(solutions[i]).not.toBeNull();
-//     }
+    for (let i = 0; i < solutions.length; i++) {
+      expect(solutions[i]).not.toBeNull();
+    }
 
-//   });
+  });
   
-// });
+});
 
-// /**
-//  * Helper function.
-//  * Add a string representing time with a number representing number of seconds to add.
-//  * 
-//  * @param timeString string representing time
-//  * @param secondsToAdd number in seconds
-//  * @returns string representing time after specified seconds have been added to it
-//  */
-// function addSecondsToTimeString(timeString: string, secondsToAdd: number) {
-//   const time = moment(timeString, 'HH:mm:ss');
-//   time.add(secondsToAdd, 'seconds');
-//   return time.format('HH:mm:ss');
-// }
\ No newline at end of file
+/**
+ * Helper function.
+ * Add a string representing time with a number representing number of seconds to add.
+ * 
+ * @param timeString string representing time
+ * @param secondsToAdd number in seconds
+ * @returns string representing time after specified seconds have been added to it
+ */
+function addSecondsToTimeString(timeString: string, secondsToAdd: number) {
+  const time = moment(timeString, 'HH:mm:ss');
+  time.add(secondsToAdd, 'seconds');
+  return time.format('HH:mm:ss');
+}
\ No newline at end of file