diff --git a/frontend/src/API/API_GetMethods.tsx b/frontend/src/API/API_GetMethods.tsx index 18a9eb4..040cb7f 100644 --- a/frontend/src/API/API_GetMethods.tsx +++ b/frontend/src/API/API_GetMethods.tsx @@ -269,10 +269,11 @@ export async function getUserById(id: string): Promise { */ export async function getGoogleAuthUser(): Promise { try { - const response = await axios.get(`${AUTH_URL}/google/whoami`, { withCredentials: true, }); + const response = await axios.get(`${AUTH_URL}/google/whoami`, { + withCredentials: true, + }); return response.data; - } - catch (error: any) { + } catch (error: any) { console.error(`Error fetching current user: ${error}`); return null; } diff --git a/frontend/src/components/HeaderFooter.tsx b/frontend/src/components/HeaderFooter.tsx index 75fbda7..a2dd5ea 100644 --- a/frontend/src/components/HeaderFooter.tsx +++ b/frontend/src/components/HeaderFooter.tsx @@ -158,12 +158,14 @@ export const Footer = () => {
- Britt Schiller, Ore Ogunleye, Nishka Mittal, Josh Hare, Sydney Ferris
+ Britt Schiller, Ore Ogunleye, Nishka Mittal, Josh Hare, Sydney + Ferris
Fall 2024 Capstone Team

- Jackson Stewart, Kaili Fogle, Robbie Cook, Donato Curvino, James Fontenot
+ Jackson Stewart, Kaili Fogle, Robbie Cook, Donato Curvino, James + Fontenot
Spring 2025 Capstone Team

diff --git a/frontend/src/pages/AuthContext.tsx b/frontend/src/pages/AuthContext.tsx index ae47a74..d6a8424 100644 --- a/frontend/src/pages/AuthContext.tsx +++ b/frontend/src/pages/AuthContext.tsx @@ -27,16 +27,17 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { let userInfo: User | null = storedUser ? JSON.parse(storedUser) : null; const authInfo = await getGoogleAuthUser(); - if (authInfo?.email && (!userInfo || userInfo?.email != authInfo?.email)) { + if ( + authInfo?.email && + (!userInfo || userInfo?.email != authInfo?.email) + ) { userInfo = await getUserByEmail(authInfo?.email); setUser(userInfo); localStorage.setItem("user", JSON.stringify(userInfo)); - } - else if (!authInfo?.nameId) { + } else if (!authInfo?.nameId) { setUser(null); localStorage.removeItem("user"); - } - else { + } else { setUser(userInfo); } }; diff --git a/frontend/src/pages/logIn.tsx b/frontend/src/pages/logIn.tsx index 986fb30..00af200 100644 --- a/frontend/src/pages/logIn.tsx +++ b/frontend/src/pages/logIn.tsx @@ -32,8 +32,7 @@ const LogIn: React.FC = () => { `${AUTH_URL}/google/logout?returnUrl=${returnUrl}`, ); window.location.assign(loginUrl); - } - else { + } else { navigate("loggedIn"); } }; diff --git a/frontend/test/logIn.test.tsx b/frontend/test/logIn.test.tsx index 3a22ae9..186e6f5 100644 --- a/frontend/test/logIn.test.tsx +++ b/frontend/test/logIn.test.tsx @@ -17,10 +17,10 @@ import axios, { AxiosHeaders, AxiosResponse } from "axios"; vi.mock("axios"); const mockUserInfo: User = { - "role": "admin", - "email": "test@email.com", - "username": "Test Account", -} + role: "admin", + email: "test@email.com", + username: "Test Account", +}; describe("Unauthenticated LogIn Component", () => { const originalLocation = window.location; @@ -41,15 +41,18 @@ describe("Unauthenticated LogIn Component", () => { } beforeEach(() => { - window.location = { ...originalLocation, assign: vi.fn((_: string | URL) => { }) }; + window.location = { + ...originalLocation, + assign: vi.fn((_: string | URL) => {}), + }; vi.spyOn(axios, "get").mockResolvedValue(createMockUserData()); render( - + - + , ); }); @@ -60,12 +63,11 @@ describe("Unauthenticated LogIn Component", () => { }); it("should render the login button and the guest button", () => { - expect(screen.getByText("Sign in")).toBeTruthy(); // Check presence of the login button - expect(screen.getByText("Continue as Guest")).toBeTruthy(); // Check presence of the guest button + expect(screen.getByText("Sign in")).toBeTruthy(); // Check presence of the login button + expect(screen.getByText("Continue as Guest")).toBeTruthy(); // Check presence of the guest button }); it("should open and close the About modal", async () => { - const aboutButton = screen.getAllByRole("button", { name: "About" })[0]; fireEvent.click(aboutButton); @@ -98,91 +100,98 @@ describe("Unauthenticated LogIn Component", () => { describe.each([ ["", mockUserInfo], ["with uncached user", null], - ["with other cached user", { - email: "wronguser@gmail.co.uk", - role: "unauthenticated", - username: "John Doe" - }], -]) - ("Authenticated LogIn Component %s", (_, cachedUserInfo) => { - const originalLocation = window.location; - - function createMockUserData(): AxiosResponse { - return { - data: { - nameId: "1234567890", - email: mockUserInfo.email, - id: "1234", - username: mockUserInfo.username, - role: mockUserInfo.role, - } as UserClaims & User, - status: 200, - statusText: "OK", - headers: {}, - config: { - headers: new AxiosHeaders({ "Content-Type": "text/plain" }), - }, - } as AxiosResponse; - } - - beforeEach(async () => { - vi.spyOn(axios, "get").mockResolvedValue(createMockUserData()); - window.location = { ...originalLocation, assign: vi.fn((_: string | URL) => { }) }; - localStorage.setItem("user", JSON.stringify(cachedUserInfo)); - render( - - - - - - ); - - await act(() => axios.get); // Allows the initial useLayoutEffect to fire - }); - - afterEach(() => { - cleanup(); - window.location = originalLocation; - localStorage.clear(); - }); + [ + "with other cached user", + { + email: "wronguser@gmail.co.uk", + role: "unauthenticated", + username: "John Doe", + }, + ], +])("Authenticated LogIn Component %s", (_, cachedUserInfo) => { + const originalLocation = window.location; - it("shows different buttons when logged in", () => { - expect(screen.getByText(`Continue as ${mockUserInfo.username}`)).toBeTruthy(); - expect(screen.getByText("Switch Account")).toBeTruthy(); - expect(screen.getByText("Continue as Guest")).toBeTruthy(); - }); + function createMockUserData(): AxiosResponse { + return { + data: { + nameId: "1234567890", + email: mockUserInfo.email, + id: "1234", + username: mockUserInfo.username, + role: mockUserInfo.role, + } as UserClaims & User, + status: 200, + statusText: "OK", + headers: {}, + config: { + headers: new AxiosHeaders({ "Content-Type": "text/plain" }), + }, + } as AxiosResponse; + } - it("navigates to the backend when switching accounts", () => { - const loginButton = screen.getByText("Switch Account"); - expect(loginButton).toBeTruthy(); - fireEvent.click(loginButton); - expect(window.location.assign).toHaveBeenCalledOnce(); // Redirect to backend auth/google/login endpoint - }); + beforeEach(async () => { + vi.spyOn(axios, "get").mockResolvedValue(createMockUserData()); + window.location = { + ...originalLocation, + assign: vi.fn((_: string | URL) => {}), + }; + localStorage.setItem("user", JSON.stringify(cachedUserInfo)); + render( + + + + + , + ); - it("navigates to the backend when continuing as a guest", () => { - const guestButton = screen.getByText("Continue as Guest"); - expect(guestButton).toBeTruthy(); - fireEvent.click(guestButton); - expect(window.location.assign).toHaveBeenCalledOnce(); - }); + await act(() => axios.get); // Allows the initial useLayoutEffect to fire + }); - it("removes user from local storage when logging out", () => { - expect(document.getElementById("side-nav-button")).toBeTruthy(); - expect(localStorage.getItem("user")).toBeTruthy(); + afterEach(() => { + cleanup(); + window.location = originalLocation; + localStorage.clear(); + }); - // Open side nav - const hamburgerMenu: HTMLElement = document.getElementById("side-nav-button")!; - fireEvent.click(hamburgerMenu); + it("shows different buttons when logged in", () => { + expect( + screen.getByText(`Continue as ${mockUserInfo.username}`), + ).toBeTruthy(); + expect(screen.getByText("Switch Account")).toBeTruthy(); + expect(screen.getByText("Continue as Guest")).toBeTruthy(); + }); - // Click logout button - const logoutButton = screen.getByText("Log Out"); - fireEvent.click(logoutButton); + it("navigates to the backend when switching accounts", () => { + const loginButton = screen.getByText("Switch Account"); + expect(loginButton).toBeTruthy(); + fireEvent.click(loginButton); + expect(window.location.assign).toHaveBeenCalledOnce(); // Redirect to backend auth/google/login endpoint + }); - expect(window.location.assign).toHaveBeenCalledOnce(); // Redirect to backend auth/google/logout endpoint - expect(localStorage.getItem("user")).toBeFalsy(); - }); + it("navigates to the backend when continuing as a guest", () => { + const guestButton = screen.getByText("Continue as Guest"); + expect(guestButton).toBeTruthy(); + fireEvent.click(guestButton); + expect(window.location.assign).toHaveBeenCalledOnce(); }); + it("removes user from local storage when logging out", () => { + expect(document.getElementById("side-nav-button")).toBeTruthy(); + expect(localStorage.getItem("user")).toBeTruthy(); + + // Open side nav + const hamburgerMenu: HTMLElement = + document.getElementById("side-nav-button")!; + fireEvent.click(hamburgerMenu); + + // Click logout button + const logoutButton = screen.getByText("Log Out"); + fireEvent.click(logoutButton); + + expect(window.location.assign).toHaveBeenCalledOnce(); // Redirect to backend auth/google/logout endpoint + expect(localStorage.getItem("user")).toBeFalsy(); + }); +}); describe("Sanity Check Tests", () => { it("should always pass test 1", () => {