Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
7676a06
[Refactor] - UT and AT 1 to 4
SaraH6734 Feb 28, 2026
f51b679
update AT and fixed changes
SaraH6734 Mar 4, 2026
78313cf
fixes
SaraH6734 Mar 4, 2026
a92fecb
fixes
SaraH6734 Mar 4, 2026
d9b491a
fixes
SaraH6734 Mar 4, 2026
cb5320b
fixes
SaraH6734 Mar 4, 2026
fa2c1c4
fixes
SaraH6734 Mar 5, 2026
360bf73
Merge remote-tracking branch 'origin/master' into unit-and-maestroTest
SaraH6734 Mar 6, 2026
1e62d6c
merge conflicts
SaraH6734 Mar 6, 2026
57a6ba9
Merge branch 'master' into unit-and-maestroTest
SaraH6734 Mar 6, 2026
72ba531
fix
SaraH6734 Mar 6, 2026
630a276
fix
SaraH6734 Mar 6, 2026
eb155aa
fixes
SaraH6734 Mar 6, 2026
b8f7adf
fixes
SaraH6734 Mar 6, 2026
fbcaea3
Merge branch 'master' into unit-and-maestroTest
SaraH6734 Mar 8, 2026
ed3a4dd
updated height and E2E overlay
SaraH6734 Mar 8, 2026
19cd2df
fixes
SaraH6734 Mar 8, 2026
97918ee
fixes
SaraH6734 Mar 8, 2026
b5de062
[REFACTOR] moved E2E code to seperate file
Vinuyans Mar 12, 2026
1485559
fixed merge conflicts from master
Vinuyans Mar 12, 2026
6fb3a74
fixed failling test post merge + updated sonarqubes exclusion to igno…
Vinuyans Mar 12, 2026
95db9bc
ran prettier
Vinuyans Mar 12, 2026
4ccff43
ran lint
Vinuyans Mar 12, 2026
82f83f6
fixed minor sonarqube warnings
Vinuyans Mar 12, 2026
f74592b
removed dup AT1 and updated sonarqubes properties
Vinuyans Mar 12, 2026
bc84319
test a marker
benjaminsunliu Mar 12, 2026
0ab1ed1
push fix
benjaminsunliu Mar 12, 2026
4fa0ac4
fixed formatting
SaraH6734 Mar 12, 2026
ca3f346
tests
SaraH6734 Mar 12, 2026
370db8d
added e2e test
SaraH6734 Mar 12, 2026
ef2ab45
added test
SaraH6734 Mar 13, 2026
26e242b
removed height
SaraH6734 Mar 13, 2026
1e5704a
removed e2e marker
SaraH6734 Mar 14, 2026
80faeac
removed e2e.ts
SaraH6734 Mar 14, 2026
c9e7d68
fixes
SaraH6734 Mar 14, 2026
75a328f
fixes
SaraH6734 Mar 14, 2026
e588049
removed marker-test.yaml
SaraH6734 Mar 15, 2026
bef52d1
fixes
SaraH6734 Mar 15, 2026
d7d6099
changed position
SaraH6734 Mar 15, 2026
f57293c
add web version of the map
benjaminsunliu Mar 15, 2026
b4f4eea
Merge branch 'master' into fix-web-map
benjaminsunliu Mar 15, 2026
0147bed
fix building search and selection for web
benjaminsunliu Mar 15, 2026
5d43a94
Microsoft Clarity script added
JenLys Mar 15, 2026
eefdd8e
removed clarity script
JenLys Mar 16, 2026
559e074
add expo EAS
benjaminsunliu Mar 18, 2026
6404bc4
resolve sonar
benjaminsunliu Mar 18, 2026
ab28943
format
benjaminsunliu Mar 18, 2026
ed9108a
Potential fix for pull request finding
benjaminsunliu Mar 18, 2026
80b1ef9
fix drag for web route popup
benjaminsunliu Mar 18, 2026
d2136e8
fix map snapping on web
benjaminsunliu Mar 18, 2026
f14eeb2
format
benjaminsunliu Mar 18, 2026
7b59fd0
add coverage
benjaminsunliu Mar 18, 2026
20068b0
fix
benjaminsunliu Mar 18, 2026
5621207
format
benjaminsunliu Mar 18, 2026
566b75b
push script
benjaminsunliu Mar 18, 2026
f767492
retry
benjaminsunliu Mar 18, 2026
a02eabf
navigation in web
YehJordan Apr 5, 2026
c42f03b
fix corrupt characters & indoor field dismiss buttons
benjaminsunliu Apr 5, 2026
8d58b61
fix calendar, UI, & some bugs on web
benjaminsunliu Apr 6, 2026
61f6da3
add poi button on web
benjaminsunliu Apr 6, 2026
ff4c277
mobile fix
benjaminsunliu Apr 6, 2026
cadd884
fix mobile web view of app
benjaminsunliu Apr 6, 2026
7aec619
web poi fix
benjaminsunliu Apr 6, 2026
06a1d03
force light mode on web
benjaminsunliu Apr 6, 2026
a325f4d
better web markers
benjaminsunliu Apr 6, 2026
6292531
update
benjaminsunliu Apr 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions __tests__/auth-cookies.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {
buildLoggedInDataFromCookieString,
parseCookieString,
} from "@/utils/authCookies";

describe("authCookies", () => {
it("parses cookie values that contain equals signs", () => {
const cookies = parseCookieString("SSO-Token=token==; Given-Name=Ben; Surname=L");

expect(cookies["SSO-Token"]).toBe("token==");
expect(cookies["Given-Name"]).toBe("Ben");
expect(cookies["Surname"]).toBe("L");
});

it("builds logged in data from the Concordia cookie string", () => {
expect(
buildLoggedInDataFromCookieString(
"Given-Name=Ben; Surname=L; SSO-Token=token==",
),
).toEqual({
authToken: "token==",
firstName: "Ben",
lastNameInitial: "L",
});
});
});
40 changes: 40 additions & 0 deletions __tests__/auth-web-view.web.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import AuthWebView from "@/components/authentication/AuthWebView.web";
import { fireEvent, render, waitFor } from "@testing-library/react-native";
import React from "react";

describe("AuthWebView web", () => {
it("accepts a pasted token", async () => {
const onLogin = jest.fn();
const authView = render(<AuthWebView onLogin={onLogin} />);

fireEvent.changeText(authView.getByTestId("calendar-web-auth-input"), "token-123");
fireEvent.press(authView.getByTestId("calendar-web-auth-submit"));

await waitFor(() => {
expect(onLogin).toHaveBeenCalledWith({
authToken: "token-123",
firstName: "Concordia",
lastNameInitial: "",
});
});
});

it("extracts the token from a pasted cookie string", async () => {
const onLogin = jest.fn();
const authView = render(<AuthWebView onLogin={onLogin} />);

fireEvent.changeText(
authView.getByTestId("calendar-web-auth-input"),
"Given-Name=Ben; Surname=L; SSO-Token=token==",
);
fireEvent.press(authView.getByTestId("calendar-web-auth-submit"));

await waitFor(() => {
expect(onLogin).toHaveBeenCalledWith({
authToken: "token==",
firstName: "Ben",
lastNameInitial: "L",
});
});
});
});
45 changes: 45 additions & 0 deletions __tests__/building-info-popup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import BuildingInfoPopup from "../components/map/building-info-popup";
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react-native";
import { CAMPUS_BUILDINGS } from "../constants/map";
import { Linking } from "react-native";
import { NavigationLoader } from "../globals/IndoorNavigationLoader";

const mockBuilding = CAMPUS_BUILDINGS[22]; // Hall Building

Expand All @@ -24,11 +25,17 @@ jest.mock("react-native", () => {

const mockOnNavigate = jest.fn();
const mockOnSetAsStart = jest.fn();
const mockOnExploreRooms = jest.fn();

jest.spyOn(Linking, "openURL").mockImplementation(jest.fn());
jest.spyOn(Linking, "canOpenURL").mockResolvedValue(true);

describe("building-info-popup", () => {
beforeEach(() => {
jest.clearAllMocks();
jest.spyOn(NavigationLoader, "buildingHasNavigationData").mockReturnValue(true);
});

it("renders nothing if building is null", () => {
const { queryByTestId } = render(<BuildingInfoPopup building={null} />);
expect(queryByTestId("building-info-popup")).toBeNull();
Expand Down Expand Up @@ -94,6 +101,44 @@ describe("building-info-popup", () => {
expect(mockOnSetAsStart).toHaveBeenCalled();
});

it('calls the on explore rooms function when "Explore Rooms" is pressed', async () => {
render(
<BuildingInfoPopup
building={mockBuilding}
onNavigate={mockOnNavigate}
onExploreRooms={mockOnExploreRooms}
/>,
);

const roomsButton = screen.getByTestId("rooms-action-button");

await act(async () => {
await fireEvent.press(roomsButton);
});

expect(mockOnExploreRooms).toHaveBeenCalled();
});

it('disables "Explore Rooms" when the building has no indoor map data', async () => {
jest.spyOn(NavigationLoader, "buildingHasNavigationData").mockReturnValue(false);

render(
<BuildingInfoPopup
building={mockBuilding}
onNavigate={mockOnNavigate}
onExploreRooms={mockOnExploreRooms}
/>,
);

const roomsButton = screen.getByTestId("rooms-action-button");

await act(async () => {
await fireEvent.press(roomsButton);
});

expect(mockOnExploreRooms).not.toHaveBeenCalled();
});

it('opens the correct link when "Website" is pressed', async () => {
render(<BuildingInfoPopup building={mockBuilding} onNavigate={mockOnNavigate} />);

Expand Down
17 changes: 17 additions & 0 deletions __tests__/calendar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,23 @@ describe("Calendar View", () => {
const webView = calendarView.queryByTestId("auth-web-view");
expect(webView).toBeNull();
});

it("Shows a calendar error when the token is invalid", async () => {
globalThis.fetch = jest.fn().mockResolvedValue({
text: jest.fn().mockResolvedValue(`'${JSON.stringify({ errorMessage: "Invalid Token" })}'`),
});

const calendarView = render(
<AuthContext value={loggedInContext}>
<QueryClientProvider client={testQueryClient}>
<CalendarScreen />
</QueryClientProvider>
</AuthContext>,
);

expect(await calendarView.findByTestId("calendar-error-view")).toBeVisible();
expect(calendarView.getByText("Invalid Token")).toBeVisible();
});
});

const loggedOutContext: LoggedOutContext = {
Expand Down
87 changes: 87 additions & 0 deletions __tests__/campus-toggle.web.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from "react";
import { fireEvent, render } from "@testing-library/react-native";
import CampusToggle from "@/components/map/campus-toggle.web";

jest.mock("@/hooks/use-color-scheme", () => ({
useColorScheme: () => "light",
}));

jest.mock("react-native-switch-selector", () => {
const React = require("react");
const { Pressable, Text, View } = require("react-native");

return function MockSwitchSelector(props: any) {
return (
<View testID={props.testID}>
<Text testID="selected-campus">{String(props.value)}</Text>
{props.options.map((option: { label: string; value: number }) => (
<Pressable
key={option.label}
testID={`option-${option.label}`}
onPress={() => props.onPress(option.value)}
>
<Text>{option.label}</Text>
</Pressable>
))}
</View>
);
};
});

const nearSGW = {
latitude: 45.4959,
longitude: -73.5772,
latitudeDelta: 0.01,
longitudeDelta: 0.01,
};

const nearLOY = {
latitude: 45.4578,
longitude: -73.6396,
latitudeDelta: 0.01,
longitudeDelta: 0.01,
};

describe("campus-toggle.web", () => {
it("selects the closest campus on initial render", () => {
const mapRef = { current: { animateToRegion: jest.fn() } };
const { getByTestId } = render(<CampusToggle mapRef={mapRef} viewRegion={nearSGW} />);

// Campus.SGW is enum value 1.
expect(getByTestId("selected-campus").props.children).toBe("1");
});

it("animates map when user switches campus", () => {
const animateToRegion = jest.fn();
const mapRef = { current: { animateToRegion } };
const { getByTestId } = render(<CampusToggle mapRef={mapRef} viewRegion={nearLOY} />);

fireEvent.press(getByTestId("option-SGW"));

expect(animateToRegion).toHaveBeenCalledWith(
expect.objectContaining({
latitude: 45.4957849,
longitude: -73.577225,
latitudeDelta: 0.01,
longitudeDelta: 0.01,
}),
);
});

it("syncs from map region changes and ignores resulting programmatic selector callback", () => {
const animateToRegion = jest.fn();
const mapRef = { current: { animateToRegion } };
const { getByTestId, rerender } = render(
<CampusToggle mapRef={mapRef} viewRegion={nearSGW} />,
);

rerender(<CampusToggle mapRef={mapRef} viewRegion={nearLOY} />);

// Simulate selector callback caused by controlled value sync.
fireEvent.press(getByTestId("option-LOY"));
expect(animateToRegion).not.toHaveBeenCalled();

fireEvent.press(getByTestId("option-SGW"));
expect(animateToRegion).toHaveBeenCalledTimes(1);
});
});
27 changes: 22 additions & 5 deletions __tests__/class-detail-popup.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from "react";
import { fireEvent, render } from "@testing-library/react-native";
import { fireEvent, render, waitFor } from "@testing-library/react-native";

import ClassDetailPopup from "../components/schedule/class-detail-popup";
import type { ClassSchedule } from "@/hooks/use-calendar";
import { Colors } from "@/constants/theme";

const mockNavigate = jest.fn();
const mockBuildClassMapNavigationParams = jest.fn();
const mockWithTiming = jest.fn((toValue, _config, callback) => {
if (callback) callback(true);
return toValue;
Expand Down Expand Up @@ -39,6 +40,11 @@ jest.mock("expo-router", () => ({
},
}));

jest.mock("@/utils/classMapDestination", () => ({
buildClassMapNavigationParams: (...args: unknown[]) =>
mockBuildClassMapNavigationParams(...args),
}));

jest.mock("@/hooks/use-color-scheme", () => ({
useColorScheme: () => "light",
}));
Expand Down Expand Up @@ -69,6 +75,11 @@ const MOCK_CLASS: ClassSchedule = {
describe("ClassDetailPopup", () => {
beforeEach(() => {
mockNavigate.mockClear();
mockBuildClassMapNavigationParams.mockReset();
mockBuildClassMapNavigationParams.mockResolvedValue({
buildingId: "EV",
destinationRoom: "EV 2.260",
});
mockWithTiming.mockClear();
mockScheduleOnRN.mockClear();
});
Expand Down Expand Up @@ -136,7 +147,7 @@ describe("ClassDetailPopup", () => {
expect(mockScheduleOnRN).toHaveBeenCalledTimes(1);
});

it("closes popup and navigates to map when View in Map is pressed", () => {
it("closes popup and navigates to the room-aware map popup when View in Map is pressed", async () => {
const onClose = jest.fn();

const screen = render(
Expand All @@ -150,9 +161,15 @@ describe("ClassDetailPopup", () => {
fireEvent.press(screen.getByText("View in Map"));

expect(onClose).toHaveBeenCalledTimes(1);
expect(mockNavigate).toHaveBeenCalledWith({
pathname: "/",
params: { buildingId: "EV" },
await waitFor(() => {
expect(mockBuildClassMapNavigationParams).toHaveBeenCalledWith(MOCK_CLASS);
expect(mockNavigate).toHaveBeenCalledWith({
pathname: "/",
params: {
buildingId: "EV",
destinationRoom: "EV 2.260",
},
});
});
expect(onClose.mock.invocationCallOrder[0]).toBeLessThan(
mockNavigate.mock.invocationCallOrder[0],
Expand Down
26 changes: 26 additions & 0 deletions __tests__/indoor-room-fields.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import IndoorRoomFields from "@/components/map/indoor-room-fields";
import { fireEvent, render } from "@testing-library/react-native";
import React, { useState } from "react";
import { StyleSheet } from "react-native";

jest.mock("@/hooks/use-color-scheme", () => ({
useColorScheme: () => "light",
Expand Down Expand Up @@ -214,6 +215,31 @@ describe("IndoorRoomFields", () => {
expect(screen.getByTestId("indoor-end-room-input").props.value).toBe("");
});

it("lets room inputs shrink so clear buttons stay inside the fields on web", () => {
const screen = render(
<IndoorRoomFields
buildingCode="MB"
startRoom="MB 1.315"
endRoom="MB S2.245"
roomSuggestions={ROOM_SUGGESTIONS}
canCreatePath
onChangeStartRoom={jest.fn()}
onChangeEndRoom={jest.fn()}
onCreatePath={jest.fn()}
/>,
);

const startInputStyle = StyleSheet.flatten(
screen.getByTestId("indoor-start-room-input").props.style,
);
const endInputStyle = StyleSheet.flatten(
screen.getByTestId("indoor-end-room-input").props.style,
);

expect(startInputStyle).toMatchObject({ flexShrink: 1, minWidth: 0 });
expect(endInputStyle).toMatchObject({ flexShrink: 1, minWidth: 0 });
});

it("keeps invalid room input while typing", () => {
const screen = render(<IndoorRoomFieldsHarness />);

Expand Down
Loading