From ee984cd0f5d9a9741061b3ca8cb783f85c1e51d1 Mon Sep 17 00:00:00 2001
From: Federico Hurtado <fed_home@Federicos-Mac-mini.local>
Date: Wed, 23 Oct 2024 11:41:29 -0400
Subject: [PATCH] Able to create people and store all of their information
 except involvements. Began unit testing repository classes.

---
 backend/repository/addressRepository.js       |   6 +-
 backend/repository/contactRepository.js       |  11 +-
 backend/repository/degreeRepository.js        |   8 +-
 backend/routes/peopleRoutes.js                |   6 +-
 backend/service/peopleService.js              |   6 +
 .../test/repository/addressRepository.test.js | 114 ++++++++++++++++++
 .../test/repository/contactRepository.test.js |  56 +++++++++
 .../test/repository/degreeRepository.test.js  | 108 +++++++++++++++++
 .../test/repository/peopleRepository.test.js  |  29 ++---
 9 files changed, 317 insertions(+), 27 deletions(-)
 create mode 100644 backend/test/repository/addressRepository.test.js
 create mode 100644 backend/test/repository/contactRepository.test.js
 create mode 100644 backend/test/repository/degreeRepository.test.js

diff --git a/backend/repository/addressRepository.js b/backend/repository/addressRepository.js
index d2deaef..06da1ce 100644
--- a/backend/repository/addressRepository.js
+++ b/backend/repository/addressRepository.js
@@ -1,5 +1,8 @@
 const { pool } = require("../config/database/database.config");
 
+/*
+Add address info into address table and peopleXaddress table
+*/
 async function addAddress(address, peopleId) {
   // get all the parts of the address
   let { address1, address2, city, state, country, zipCode, preferredAddress } =
@@ -43,7 +46,6 @@ async function addAddress(address, peopleId) {
         INSERT INTO peopleXAddress (peopleId, addressId, preferredAddress)
         VALUES (?, ?, ?)
     `;
-
     const [peopleAddressResult] = await pool.query(peopleAddressQuery, [
       peopleId,
       addressId,
@@ -54,7 +56,9 @@ async function addAddress(address, peopleId) {
 
     return peopleAddressResult;
   } catch (error) {
+    // return null if error
     console.error(error);
+    return null;
   }
 }
 
diff --git a/backend/repository/contactRepository.js b/backend/repository/contactRepository.js
index b096cb2..0a091e9 100644
--- a/backend/repository/contactRepository.js
+++ b/backend/repository/contactRepository.js
@@ -1,11 +1,9 @@
 const { pool } = require("../config/database/database.config");
-// contacts: [
-//     {
-//         contactNumber: string --> i guess this can be a phone nunber, email, etc.
-//         contactType: string --> need to define list: phone, email, ....
-//         preferredContact: boolean
-//     },
 
+/*
+Function to add a row into the peopleContact
+table with the contact info given
+*/
 async function addContact(contact, peopleId) {
   // extract the parts of the contact
   let { contactNumber, contactType, preferredContact } = contact;
@@ -30,6 +28,7 @@ async function addContact(contact, peopleId) {
     return results;
   } catch (error) {
     console.log(error);
+    return null;
   }
 }
 
diff --git a/backend/repository/degreeRepository.js b/backend/repository/degreeRepository.js
index 9955b1d..9e7835f 100644
--- a/backend/repository/degreeRepository.js
+++ b/backend/repository/degreeRepository.js
@@ -1,5 +1,8 @@
 const { pool } = require("../config/database/database.config");
 
+/*
+Add degree information into the database.
+*/
 async function addDegree(degree, peopleId) {
   // get all the parts of the degree
   let {
@@ -16,6 +19,7 @@ async function addDegree(degree, peopleId) {
     // Use the helper function to determine the degreeTypeId
     let degreeTypeId = await _lookupDegreeTypeId(degreeType);
 
+    // query to insert degree info
     const query = `
         INSERT INTO peopleDegree (peopleId, degreeTypeId, degreeDepartment, degreeCollege, degreeYear, degreeDescription)
         VALUES (?,?,?,?,?,?)
@@ -33,7 +37,9 @@ async function addDegree(degree, peopleId) {
 
     return results;
   } catch (error) {
+    // return null if there is an error
     console.error(error);
+    return null;
   }
 }
 
@@ -61,4 +67,4 @@ async function _lookupDegreeTypeId(degreeType) {
   }
 }
 
-module.exports = { addDegree };
+module.exports = { addDegree, _lookupDegreeTypeId };
diff --git a/backend/routes/peopleRoutes.js b/backend/routes/peopleRoutes.js
index 3e707a6..fe7ff6b 100644
--- a/backend/routes/peopleRoutes.js
+++ b/backend/routes/peopleRoutes.js
@@ -122,13 +122,13 @@ peopleRouter.post("/create", validateCreatePerson, async (req, res) => {
     const person = await createPerson(req.body);
     console.log("In people routes after add: ", person);
 
-    return res.status(201).json({ message: "person added successfully" });
+    return res
+      .status(201)
+      .json({ message: "person added successfully", personId: person });
   } catch (error) {
     console.log("error");
     return res.status(500).json({ message: error });
   }
-  // no logic for now, return 200
-  return res.status(200).json({ message: "No errors" });
 });
 
 module.exports = peopleRouter;
diff --git a/backend/service/peopleService.js b/backend/service/peopleService.js
index 0c610db..e196f5c 100644
--- a/backend/service/peopleService.js
+++ b/backend/service/peopleService.js
@@ -1,4 +1,5 @@
 const { addAddress } = require("../repository/addressRepository");
+const { addContact } = require("../repository/contactRepository");
 const { addDegree } = require("../repository/degreeRepository");
 const { addPerson } = require("../repository/peopleRepository");
 
@@ -25,12 +26,17 @@ async function createPerson(person) {
 
   // insert the contact information into the database
   for (const contact of contacts) {
+    const addedContact = await addContact(contact, newPersonID);
+    console.log("added contact: ", contact);
   }
 
   // insert the involvment information into the database
   for (const involvment of involvements) {
+    console.log("not adding involvements yet.");
   }
 
+  // TODO: log database change here
+
   return newPersonID;
 }
 
diff --git a/backend/test/repository/addressRepository.test.js b/backend/test/repository/addressRepository.test.js
new file mode 100644
index 0000000..835e7a8
--- /dev/null
+++ b/backend/test/repository/addressRepository.test.js
@@ -0,0 +1,114 @@
+// Mock the database's pool and query function
+jest.mock("../../config/database/database.config", () => {
+  const queryMock = jest.fn(); // Mock query function
+  return { pool: { query: queryMock } }; // Return the mocked pool directly
+});
+
+const { pool } = require("../../config/database/database.config");
+const { addAddress } = require("../../repository/addressRepository");
+
+/*
+Test methods for addressRepository
+*/
+describe("Testing addressRepository.js", () => {
+  const mockAddress1 = {
+    address1: "123 Main St",
+    address2: "Apt 4",
+    city: "Springfield",
+    state: "VA",
+    country: "United States",
+    zipCode: "22150",
+    preferredAddress: true,
+  };
+
+  const mockAddress2 = {
+    address1: "12 Center St",
+    address2: "Apt 14",
+    city: "Centerville",
+    state: "VA",
+    country: "United States",
+    zipCode: "23456",
+    preferredAddress: true,
+  };
+
+  const mockPeopleId = 1;
+
+  describe("addAddress tests", () => {
+    it("Insert 1 address with no errors", async () => {
+      const mockAddressId = 2;
+      const mockPeopleXAddressResult = { affectedRows: 1 };
+
+      // Mock database query for inserting address and peopleXAddress
+      pool.query
+        .mockResolvedValueOnce([{ insertId: mockAddressId }]) // First query for address insertion
+        .mockResolvedValueOnce([mockPeopleXAddressResult]); // Second query for peopleXAddress insertion
+
+      const result = await addAddress(mockAddress1, mockPeopleId);
+
+      // Verify first query was called for address table
+      expect(pool.query).toHaveBeenCalledWith(expect.any(String), [
+        "123 Main St",
+        "Apt 4",
+        "Springfield",
+        1, // Hardcoded for now
+        1, // Hardcoded fow now
+        "22150",
+      ]);
+
+      // Verify second query was called for peopleXAddress table
+      expect(pool.query).toHaveBeenCalledWith(expect.any(String), [
+        mockPeopleId,
+        mockAddressId, // ensure the correct addressID was used
+        true,
+      ]);
+
+      // Expect the function to return the result of the second query
+      expect(result).toBe(mockPeopleXAddressResult);
+    });
+
+    it("should handle errors during address insertion", async () => {
+      // Mock database query to throw an error during address insertion
+      const mockError = new Error("Database query failed");
+      pool.query.mockRejectedValueOnce(mockError);
+
+      // Call addAddress and expect it to handle the error
+      const result = await addAddress(mockAddress1, mockPeopleId);
+
+      expect(result).toBe(null);
+    });
+
+    it("Insert 1 address with no errors", async () => {
+      const mockAddressId = 2;
+      const mockPeopleXAddressResult = { affectedRows: 1 };
+
+      // Mock database query for inserting address and peopleXAddress
+      pool.query.mockResolvedValueOnce([{ insertId: mockAddressId }]); // First query for address insertion
+
+      // Mock second query to throw an error during peopleXAddress insertion
+      const mockError = new Error("Failed to insert into peopleXAddress");
+      pool.query.mockRejectedValueOnce(mockError);
+
+      const result = await addAddress(mockAddress1, mockPeopleId);
+
+      // Verify first query was called for address table
+      expect(pool.query).toHaveBeenCalledWith(expect.any(String), [
+        "123 Main St",
+        "Apt 4",
+        "Springfield",
+        1, // Hardcoded for now
+        1, // Hardcoded fow now
+        "22150",
+      ]);
+
+      // Verify second query was called for peopleXAddress table
+      expect(pool.query).toHaveBeenCalledWith(expect.any(String), [
+        mockPeopleId,
+        mockAddressId, // ensure the correct addressID was used
+        true,
+      ]);
+
+      // expect a null return after the call
+      expect(result).toBe(null);
+    });
+  });
+});
diff --git a/backend/test/repository/contactRepository.test.js b/backend/test/repository/contactRepository.test.js
new file mode 100644
index 0000000..1dfadfb
--- /dev/null
+++ b/backend/test/repository/contactRepository.test.js
@@ -0,0 +1,56 @@
+// Mock the database's pool and query function
+jest.mock("../../config/database/database.config", () => {
+  const queryMock = jest.fn(); // Mock query function
+  return { pool: { query: queryMock } }; // Return the mocked pool directly
+});
+
+const { pool } = require("../../config/database/database.config");
+const { addContact } = require("../../repository/contactRepository");
+
+/*
+Test methods for peopleRepository
+*/
+describe("Testing peopleRepository.js", () => {
+  // mock contact value to use while testing
+  const mockContact = {
+    contactNumber: "1234567890",
+    contactType: "mobile",
+    preferredContact: true,
+  };
+  const mockPeopleId = 1;
+
+  /*
+  Tests for the addContact method
+  */
+  describe("addContact Tests", () => {
+    it("insert a contact with no errors", async () => {
+      // Mock the database to return a success response
+      const mockResults = { affectedRows: 1 };
+      pool.query.mockResolvedValueOnce([mockResults]);
+
+      // Call addContact
+      const result = await addContact(mockContact, mockPeopleId);
+
+      // Verify the SQL query and parameters
+      expect(pool.query).toHaveBeenCalledWith(expect.any(String), [
+        1,
+        "1234567890",
+        "mobile",
+        true,
+      ]);
+
+      // Expect function to return the database result
+      expect(result).toBe(mockResults);
+    });
+
+    it("handle errors if the query fails", async () => {
+      // Mock the database to throw an error
+      const mockError = new Error("Database query failed");
+      pool.query.mockRejectedValueOnce(mockError);
+
+      // Call addContact and expect it to handle the error
+      const result = await addContact(mockContact, mockPeopleId);
+      expect(result).toBe(null);
+    });
+  });
+});
diff --git a/backend/test/repository/degreeRepository.test.js b/backend/test/repository/degreeRepository.test.js
new file mode 100644
index 0000000..c0ee99f
--- /dev/null
+++ b/backend/test/repository/degreeRepository.test.js
@@ -0,0 +1,108 @@
+// Mock the database's pool and query function
+jest.mock("../../config/database/database.config", () => {
+  const queryMock = jest.fn(); // Mock query function
+  return { pool: { query: queryMock } }; // Return the mocked pool directly
+});
+
+const { pool } = require("../../config/database/database.config.js");
+const { addDegree } = require("../../repository/degreeRepository.js");
+
+/*
+Test methods for degreeRepository
+*/
+describe("Testing degreeRepository.js", () => {
+  const mockDegree = {
+    degreeType: "BS",
+    degreeDepartment: "Computer Science",
+    degreeCollege: "Engineering",
+    degreeYear: "2024",
+    degreeDescription: "Bachelor of Science in Computer Science",
+  };
+
+  const mockPeopleId = 1;
+
+  /*
+  Tests for the addDegree method
+  */
+  describe("addDegree tests", () => {
+    it("Insert a degree with no errors", async () => {
+      const mockDegreeTypeId = 1;
+      const mockResult = { affectedRows: 1 };
+
+      // Mock the helper function _lookupDegreeTypeId to return 1
+      const lookupDegreeTypeIdSpy = jest
+        .spyOn(
+          require("../../repository/degreeRepository"),
+          "_lookupDegreeTypeId"
+        )
+        .mockResolvedValueOnce(mockDegreeTypeId);
+
+      // Mock the database query for inserting the degree
+      pool.query.mockResolvedValueOnce([mockResult]);
+
+      // Call addDegree
+      const result = await addDegree(mockDegree, mockPeopleId);
+
+      // Verify the SQL query for inserting the degree
+      expect(pool.query).toHaveBeenCalledWith(expect.any(String), [
+        mockPeopleId,
+        null, // null for now
+        "Computer Science",
+        "Engineering",
+        "2024",
+        "Bachelor of Science in Computer Science",
+      ]);
+
+      // Expect the function to return the result from the database
+      expect(result).toBe(mockResult);
+
+      // Clean up spy
+      lookupDegreeTypeIdSpy.mockRestore();
+    });
+
+    it("error thrown during degree insertion", async () => {
+      const mockError = new Error("Database query failed");
+
+      // Mock the helper function _lookupDegreeTypeId to return 1
+      const lookupDegreeTypeIdSpy = jest
+        .spyOn(
+          require("../../repository/degreeRepository"),
+          "_lookupDegreeTypeId"
+        )
+        .mockResolvedValueOnce(1);
+
+      // Mock the database query to throw an error during degree insertion
+      pool.query.mockRejectedValueOnce(mockError);
+
+      // Call addDegree and expect it to handle the error
+      const result = await addDegree(mockDegree, mockPeopleId);
+
+      // Expect the function to return null on error
+      expect(result).toBeNull();
+
+      // Clean up the spy
+      lookupDegreeTypeIdSpy.mockRestore();
+    });
+
+    it("handle errors during degree type lookup", async () => {
+      const mockError = new Error("Degree type lookup failed");
+
+      // Mock the helper function _lookupDegreeTypeId to throw an error
+      const lookupDegreeTypeIdSpy = jest
+        .spyOn(
+          require("../../repository/degreeRepository"),
+          "_lookupDegreeTypeId"
+        )
+        .mockRejectedValueOnce(mockError);
+
+      // Call addDegree and expect it to handle the error
+      const result = await addDegree(mockDegree, mockPeopleId);
+
+      // Expect the function to return null on error
+      expect(result).toBeNull();
+
+      // Clean up the spy
+      lookupDegreeTypeIdSpy.mockRestore();
+    });
+  });
+});
diff --git a/backend/test/repository/peopleRepository.test.js b/backend/test/repository/peopleRepository.test.js
index c29c280..1408825 100644
--- a/backend/test/repository/peopleRepository.test.js
+++ b/backend/test/repository/peopleRepository.test.js
@@ -39,22 +39,19 @@ describe("Testing peopleRepository.js", () => {
       const result = await addPerson(mockPerson);
 
       // Verify the SQL query and parameters
-      expect(pool.query).toHaveBeenCalledWith(
-        expect.any(String), // SQL query string, can be further detailed if needed
-        [
-          "John",
-          "Doe",
-          "A",
-          null,
-          null,
-          "Johnny",
-          2, // hardcoded for now
-          "2024",
-          "2024",
-          "spring",
-          "male",
-        ]
-      );
+      expect(pool.query).toHaveBeenCalledWith(expect.any(String), [
+        "John",
+        "Doe",
+        "A",
+        null,
+        null,
+        "Johnny",
+        2, // hardcoded for now
+        "2024",
+        "2024",
+        "spring",
+        "male",
+      ]);
 
       // expect function to return the new insert id
       expect(result).toBe(mockInsertId);
-- 
GitLab