From 777b5eb68858d00b7683bd5eea22e967a7d1512c Mon Sep 17 00:00:00 2001 From: Aidan Date: Fri, 26 Jun 2026 10:10:25 -0400 Subject: [PATCH 1/2] Update tests and constants for 2027 hackathon - Updated test cases in CartSummary, ItemTable, OrderTables, ProductOverview, and others to reflect changes in expected text and structure. - Changed the hackathon name from "MakeUofT 2026" to "MakeUofT 2027" in constants and various HTML templates. - Adjusted date formatting in views and templates to ensure consistent display across platforms. - Enhanced test isolation by clearing localStorage after each test. - Modified cartSlice tests to include credits in addToCart actions. --- .../dashboard/frontend/TEST_FINDINGS.md | 60 +++++++++++++++++++ .../cart/CartSummary/CartSummary.test.tsx | 6 +- .../dashboard/ItemTable/ItemTable.test.tsx | 2 +- .../general/OrderTables/OrderTables.test.tsx | 2 +- .../ProductOverview/ProductOverview.test.tsx | 25 +++++--- .../ProductOverview3D.test.tsx | 19 +++--- .../orders/OrdersFilter/OrderFilter.test.tsx | 4 +- .../TeamPendingOrderTable.test.tsx | 2 +- .../dashboard/frontend/src/constants.js | 2 +- .../Acknowledgement/Acknowledgement.test.tsx | 7 +-- .../frontend/src/pages/Cart/Cart.test.tsx | 4 +- .../src/pages/Dashboard/Dashboard.test.tsx | 9 +-- .../dashboard/frontend/src/setupTests.ts | 6 ++ .../src/slices/hardware/cartSlice.test.ts | 17 ++++-- hackathon_site/event/jinja2/event/base.html | 2 +- .../event/jinja2/event/change_password.html | 2 +- .../jinja2/event/change_password_done.html | 2 +- .../event/jinja2/event/dashboard_base.html | 6 +- .../event/jinja2/event/landing.html | 23 ++++--- hackathon_site/event/jinja2/event/login.html | 2 +- .../event/reset_password/reset_password.html | 2 +- .../reset_password_complete.html | 2 +- .../reset_password_confirm.html | 2 +- .../reset_password/reset_password_done.html | 2 +- hackathon_site/event/views.py | 8 ++- hackathon_site/hackathon_site/jinja2.py | 3 + hackathon_site/hackathon_site/utils.py | 15 +++++ .../registration/activation_failed.html | 2 +- .../registration/pending_activation.html | 2 +- .../jinja2/registration/signup.html | 2 +- .../jinja2/registration/signup_closed.html | 6 +- hackathon_site/review/views.py | 8 ++- 32 files changed, 177 insertions(+), 79 deletions(-) create mode 100644 hackathon_site/dashboard/frontend/TEST_FINDINGS.md diff --git a/hackathon_site/dashboard/frontend/TEST_FINDINGS.md b/hackathon_site/dashboard/frontend/TEST_FINDINGS.md new file mode 100644 index 0000000..8cb2022 --- /dev/null +++ b/hackathon_site/dashboard/frontend/TEST_FINDINGS.md @@ -0,0 +1,60 @@ +# Frontend Test Suite — Findings + +Status of the HSS React dashboard (`hackathon_site/dashboard/frontend`) Jest suite after a triage + fix pass. + +| | Test Suites | Tests | +|---|---|---| +| **Before** | 16 failed / 70 | 51 failed / 370 | +| **After** | 8 failed / 70 | 33 failed, **337 passed** / 370 | + +`tsc --noEmit` is clean (0 errors). Run tests with `NODE_OPTIONS=--openssl-legacy-provider` (Node 20 + react-scripts 4). + +**18 stale tests were fixed** (they had drifted from intentional code changes). The **33 that remain are intentionally left failing** — each one either signals a real bug or sits on top of an unfinished refactor, so "fixing" it by editing the test would hide the problem. They are grouped below with recommended fixes. + +--- + +## ✅ Fixed (stale tests updated to match intentional changes) + +- **Hardware "credits" feature** — `Hardware`/`CartItem`/`EnhancedAddToCartFormProps` gained a required `credits` field; test fixtures + expectations were updated (`cartSlice.test.ts`, `ProductOverview.test.tsx`, `Dashboard.test.tsx`, etc.). The add-to-cart button label became `Add to cart (N Credits)` → matchers relaxed to substring. +- **`OrderTables` "Pending status"** — `"Submitted"` chip label was renamed `"In progress"` → `"Submitted"` (commit d441f58); a new `"In Progress"` → `"Being Packed"` case was added. +- **`OrderFilter` clear-all** — `clearFilters` yields `{}`, not `{status: []}`. +- **`CartSummary` / `Cart` "0"** — an empty cart now shows three `0`s (quantity, credits subtotal, remaining credits); ambiguous `getByText("0")` → `getByTestId("cart-quantity-total")`. +- **`ItemTable` status chip / `Dashboard` constraints / `Acknowledgement` copy / `TeamPendingOrderTable` check-all** — updated to match current rendering (relabeled chips, commented-out constraint display, multi-node success message, status-gated bulk check). +- **Test isolation** — added `afterEach(() => window.localStorage.clear())` in `setupTests.ts` (admin order filters persist to localStorage and were leaking between tests). + +--- + +## 🔴 Remaining — flagged (need code / feature work or a decision) + +### A. The 3D-printing feature refactor is incomplete — 27 tests + 1 empty suite +`Inventory.test.tsx` (9), `Threedprinting.test.tsx` (9), `ProductOverview3D.test.tsx` (8), `hardware3dSlice.test.ts` (empty suite). + +- **Inventory hardware-load gating — likely a real bug.** `pages/Inventory/Inventory.tsx` now fetches hardware only *after* categories load **and** a category named exactly `"3D Printing"` exists (`selectThreeDPrintingId` in `slices/hardware/categorySlice.ts` matches `c.name === "3D Printing"`). If that category is missing, slow, or the category fetch fails, the page dispatches **no hardware fetch at all** → the inventory shows no hardware. `mockCategories` has no `"3D Printing"` category, so every render-based Inventory test never loads hardware ("Arduino" never appears). + - **Recommended fix:** fetch hardware on mount unconditionally and apply `exclude_category_ids` only *when* the 3D-printing category exists — don't gate the fetch itself on it. Then update `Inventory.test.tsx` to expect the `exclude_category_ids` filter and add a `"3D Printing"` category to mock data for the exclusion path. +- **`ProductOverview3D` reads a separate slice.** It uses `hardware3dInProductOverviewSelector` / `is3dUpdateDetailsLoading` from `slices/hardware/hardware3dSlice`, but `ProductOverview3D.test.tsx` seeds the *main* hardware slice (`makeStoreWithEntities` has no `hardware3d` support), so the component sees no hardware and renders nothing. + - **Recommended fix:** add `hardware3d` support to `makeStoreWithEntities` (`testing/utils.tsx`) and update the test to seed it. +- **`hardware3dSlice.test.ts` is not a test.** It contains a full copy of hardware-slice *source code* (with an older `category_ids`-based `setFilters`) and **zero test cases** → "Your test suite must contain at least one test." Looks like a leftover from the refactor. + - **Recommended fix:** delete it, or rename to a real `.ts` source file, or write actual tests — whichever matches the intent. +- **Overall:** finish the 3D-printing feature and its test infrastructure as one unit. These tests were deliberately not rewritten to match half-built code. + +### B. Real production bugs — 2 tests +- **Cart crash — `src/api/helpers.ts:43`.** `order.request.forEach(...)` is unguarded. If the orders endpoint returns an order without `request`, it throws `Cannot read properties of undefined (reading 'forEach')`, crashing the order-serialization path. (`Cart.test.tsx` → "Fetches any missing hardware on load".) + - **Fix:** `(order.request ?? []).forEach(...)` (sibling fields like `order.total_credits || 0` are already guarded). +- **`ItemTable` cancel-order modal stays open — `src/components/dashboard/ItemTable/ItemTable.tsx:248-271`.** `submitCancelOrderModal` calls `setShowCancelOrderModal(false)` only *after* `await dispatch(getTeamOrders())`, so the modal doesn't close promptly and can get stuck open if the refresh fails. (`ItemTable.test.tsx` → "cancel order modal disappears when modal is submitted".) + - **Fix:** move `setShowCancelOrderModal(false)` to the top of the handler (close synchronously, before the await), matching the "Go Back" dismiss path. + +### C. localStorage order-filter feature is incomplete — 4 tests +`OrdersSearch.test.tsx` (4). + +- A recent *"Local Storage Solution for Order Filters"* feature (`slices/order/adminOrderSlice.ts`) persists/seeds admin order filters via localStorage. After adding test isolation (`localStorage.clear()`), the old leaked-`limit` symptom is gone, but now the **search filter never reaches the API** — every `get("/api/hardware/orders/", …)` call carries `{}` instead of `{search: "foobar"}`. The component's `onSubmit` looks correct (`setFilters({ search }); getOrdersWithFilters()`), so the filter is being lost somewhere in the persistence/rehydrate path (note the `// Filter Bux Fix` comment and commented-out code in `OrdersSearch.tsx`). + - **Recommended:** finish/verify the localStorage filter feature so dispatched filters actually drive the request. I applied the safe test-isolation fix but did **not** rewrite the assertions to hide the lost-filter behavior. + +### D. Brittle test — 1 test +`IncidentForm.test.tsx` (1). + +- The test stubs `global.URLSearchParams` to fake a non-empty query string; that isn't intercepted in this CRA4/jsdom setup, so the component reads an empty `location.search` and renders nothing. **Production is fine** (`IncidentForm.tsx` reads `useLocation().search`). The test needs to drive a real route, but the shared `customRender` (`testing/utils.tsx`) hardcodes `BrowserRouter`, and route-seeding via `history.pushState` and a nested `MemoryRouter` both failed to propagate to `useLocation()` here. + - **Recommended:** add a `MemoryRouter`/`initialEntries`-aware render helper to `testing/utils.tsx`, then seed the route. Left at its original state. + +--- + +*Generated during a test-suite triage pass. Verified with `tsc --noEmit` (0 errors) and per-suite Jest runs.* diff --git a/hackathon_site/dashboard/frontend/src/components/cart/CartSummary/CartSummary.test.tsx b/hackathon_site/dashboard/frontend/src/components/cart/CartSummary/CartSummary.test.tsx index 9c9711c..1267622 100644 --- a/hackathon_site/dashboard/frontend/src/components/cart/CartSummary/CartSummary.test.tsx +++ b/hackathon_site/dashboard/frontend/src/components/cart/CartSummary/CartSummary.test.tsx @@ -63,13 +63,15 @@ export const mockHardwareSignOutDates = ( describe("Render cartQuantity", () => { it(`Renders correctly when it reads the number ${cartQuantity}`, async () => { - const { getByText } = render( + const { getByTestId } = render( ); await waitFor(() => { - expect(getByText(cartQuantity.toString())).toBeInTheDocument(); + expect(getByTestId("cart-quantity-total")).toHaveTextContent( + cartQuantity.toString() + ); }); }); // TODO: fix failing test case diff --git a/hackathon_site/dashboard/frontend/src/components/dashboard/ItemTable/ItemTable.test.tsx b/hackathon_site/dashboard/frontend/src/components/dashboard/ItemTable/ItemTable.test.tsx index b9a42f4..3f24be0 100644 --- a/hackathon_site/dashboard/frontend/src/components/dashboard/ItemTable/ItemTable.test.tsx +++ b/hackathon_site/dashboard/frontend/src/components/dashboard/ItemTable/ItemTable.test.tsx @@ -23,7 +23,7 @@ describe("", () => { }); const { getByText, queryByText } = render(, { store }); expect(getByText(/pending orders/i)).toBeInTheDocument(); - expect(queryByText("In progress")).toBeInTheDocument(); + expect(queryByText("Submitted")).toBeInTheDocument(); mockPendingOrdersInTable.map(({ id }) => { expect(getByText(`Order #${id}`)).toBeInTheDocument(); }); diff --git a/hackathon_site/dashboard/frontend/src/components/general/OrderTables/OrderTables.test.tsx b/hackathon_site/dashboard/frontend/src/components/general/OrderTables/OrderTables.test.tsx index 50468ef..9bb4c84 100644 --- a/hackathon_site/dashboard/frontend/src/components/general/OrderTables/OrderTables.test.tsx +++ b/hackathon_site/dashboard/frontend/src/components/general/OrderTables/OrderTables.test.tsx @@ -10,7 +10,7 @@ describe("", () => { test("Pending status", () => { const { getByText } = render(); - expect(getByText("In progress")).toBeInTheDocument(); + expect(getByText("Submitted")).toBeInTheDocument(); }); test("Error status", () => { diff --git a/hackathon_site/dashboard/frontend/src/components/inventory/ProductOverview/ProductOverview.test.tsx b/hackathon_site/dashboard/frontend/src/components/inventory/ProductOverview/ProductOverview.test.tsx index ab7fc7c..e37d0fd 100644 --- a/hackathon_site/dashboard/frontend/src/components/inventory/ProductOverview/ProductOverview.test.tsx +++ b/hackathon_site/dashboard/frontend/src/components/inventory/ProductOverview/ProductOverview.test.tsx @@ -82,7 +82,7 @@ describe("", () => { // Check if the main section, detailInfoSection, and add to cart section works expect(getByText("Category")).toBeInTheDocument(); expect(getByText("Datasheet")).toBeInTheDocument(); - expect(getByText("Add to cart")).toBeInTheDocument(); + expect(getByText(/Add to cart/)).toBeInTheDocument(); }); test("Category label doesn't appear when there are no categories", async () => { @@ -170,7 +170,7 @@ describe("", () => { // Check if the main section, detailInfoSection, and add to cart section works expect(getByText("Category")).toBeInTheDocument(); expect(getByText("Datasheet")).toBeInTheDocument(); - expect(getByText("Add to cart")).toBeInTheDocument(); + expect(getByText(/Add to cart/)).toBeInTheDocument(); expect(queryByText("Notes")).not.toBeInTheDocument(); }); @@ -273,14 +273,18 @@ describe("", () => { ); // by default, quantity is 1 - const button = getByText("Add to cart"); + const button = getByText(/Add to cart/); await waitFor(() => { fireEvent.click(button); }); expect(cartSelectors.selectAll(store.getState())).toEqual([ - { hardware_id: mockHardware[0].id, quantity: 1 }, + { + hardware_id: mockHardware[0].id, + quantity: 1, + credits: mockHardware[0].credits, + }, ]); expect( getByText(`Added 1 ${mockHardware[0].name} item(s) to your cart.`) @@ -320,7 +324,7 @@ describe("", () => { ); // by default, quantity is 1 - const button = getByText("Add to cart"); + const button = getByText(/Add to cart/); await waitFor(() => { fireEvent.click(button); @@ -402,13 +406,14 @@ describe("", () => { const { getByText, getByLabelText } = render( ); - const button = getByText("Add to cart").closest("button"); + const button = getByText(/Add to cart/).closest("button"); const select = getByLabelText("Qty"); expect(button).toBeDisabled(); @@ -419,13 +424,14 @@ describe("", () => { const { getByText, getByLabelText } = render( ); - const button = getByText("Add to cart").closest("button"); + const button = getByText(/Add to cart/).closest("button"); const select = getByLabelText("Qty"); expect(button).toBeDisabled(); @@ -436,6 +442,7 @@ describe("", () => { const { queryByText, getByText, getByRole } = render( ", () => { const { getByText, getByRole } = render( ", () => { const { getByText } = render( ); - const button = getByText("Add to cart").closest("button"); + const button = getByText(/Add to cart/).closest("button"); expect(button).toBeDisabled(); }); }); diff --git a/hackathon_site/dashboard/frontend/src/components/inventory/ProductOverview3D/ProductOverview3D.test.tsx b/hackathon_site/dashboard/frontend/src/components/inventory/ProductOverview3D/ProductOverview3D.test.tsx index ae7a922..cc61046 100644 --- a/hackathon_site/dashboard/frontend/src/components/inventory/ProductOverview3D/ProductOverview3D.test.tsx +++ b/hackathon_site/dashboard/frontend/src/components/inventory/ProductOverview3D/ProductOverview3D.test.tsx @@ -82,7 +82,7 @@ describe("", () => { // Check if the main section, detailInfoSection, and add to cart section works expect(getByText("Category")).toBeInTheDocument(); expect(getByText("Datasheet")).toBeInTheDocument(); - expect(getByText("Add to cart")).toBeInTheDocument(); + expect(getByText(/Add to cart/)).toBeInTheDocument(); }); test("Category label doesn't appear when there are no categories", async () => { @@ -170,7 +170,7 @@ describe("", () => { // Check if the main section, detailInfoSection, and add to cart section works expect(getByText("Category")).toBeInTheDocument(); expect(getByText("Datasheet")).toBeInTheDocument(); - expect(getByText("Add to cart")).toBeInTheDocument(); + expect(getByText(/Add to cart/)).toBeInTheDocument(); expect(queryByText("Notes")).not.toBeInTheDocument(); }); @@ -273,7 +273,7 @@ describe("", () => { ); // by default, quantity is 1 - const button = getByText("Add to cart"); + const button = getByText(/Add to cart/); await waitFor(() => { fireEvent.click(button); @@ -320,7 +320,7 @@ describe("", () => { ); // by default, quantity is 1 - const button = getByText("Add to cart"); + const button = getByText(/Add to cart/); await waitFor(() => { fireEvent.click(button); @@ -403,12 +403,13 @@ describe("", () => { ); - const button = getByText("Add to cart").closest("button"); + const button = getByText(/Add to cart/).closest("button"); const select = getByLabelText("Qty"); expect(button).toBeDisabled(); @@ -420,12 +421,13 @@ describe("", () => { ); - const button = getByText("Add to cart").closest("button"); + const button = getByText(/Add to cart/).closest("button"); const select = getByLabelText("Qty"); expect(button).toBeDisabled(); @@ -437,6 +439,7 @@ describe("", () => { @@ -453,6 +456,7 @@ describe("", () => { @@ -469,12 +473,13 @@ describe("", () => { ); - const button = getByText("Add to cart").closest("button"); + const button = getByText(/Add to cart/).closest("button"); expect(button).toBeDisabled(); }); }); diff --git a/hackathon_site/dashboard/frontend/src/components/orders/OrdersFilter/OrderFilter.test.tsx b/hackathon_site/dashboard/frontend/src/components/orders/OrdersFilter/OrderFilter.test.tsx index 691992c..fc07322 100644 --- a/hackathon_site/dashboard/frontend/src/components/orders/OrdersFilter/OrderFilter.test.tsx +++ b/hackathon_site/dashboard/frontend/src/components/orders/OrdersFilter/OrderFilter.test.tsx @@ -71,9 +71,7 @@ describe("", () => { fireEvent.click(resetButton); // check default filters are checked, nothing else - const expectedFilters: OrderFilters = { - status: [], - }; + const expectedFilters: OrderFilters = {}; await waitFor(() => { expect(store.getState()["adminOrder"]["filters"]).toEqual(expectedFilters); diff --git a/hackathon_site/dashboard/frontend/src/components/teamDetail/TeamPendingOrderTable/TeamPendingOrderTable.test.tsx b/hackathon_site/dashboard/frontend/src/components/teamDetail/TeamPendingOrderTable/TeamPendingOrderTable.test.tsx index ae4378b..4c78e90 100644 --- a/hackathon_site/dashboard/frontend/src/components/teamDetail/TeamPendingOrderTable/TeamPendingOrderTable.test.tsx +++ b/hackathon_site/dashboard/frontend/src/components/teamDetail/TeamPendingOrderTable/TeamPendingOrderTable.test.tsx @@ -91,7 +91,7 @@ describe("team pending order table", () => { // }); test("Check all button checks and unchecks every row", async () => { const { getByTestId } = render(, { store }); - const currentOrder = mockPendingOrdersInTable[0]; + const currentOrder = mockPendingOrdersInTable[1]; const checkallBox = getByTestId(`checkall-${currentOrder.id}`).querySelector( 'input[type="checkbox"]' ); diff --git a/hackathon_site/dashboard/frontend/src/constants.js b/hackathon_site/dashboard/frontend/src/constants.js index 985c5a5..caa474d 100644 --- a/hackathon_site/dashboard/frontend/src/constants.js +++ b/hackathon_site/dashboard/frontend/src/constants.js @@ -1,4 +1,4 @@ -export const hackathonName = "MakeUofT 2026"; +export const hackathonName = "MakeUofT 2027"; export const adminGroup = "Hardware Site Admins"; export const minTeamSize = 2; export const maxTeamSize = 4; diff --git a/hackathon_site/dashboard/frontend/src/pages/Acknowledgement/Acknowledgement.test.tsx b/hackathon_site/dashboard/frontend/src/pages/Acknowledgement/Acknowledgement.test.tsx index 9a1e056..a8df440 100644 --- a/hackathon_site/dashboard/frontend/src/pages/Acknowledgement/Acknowledgement.test.tsx +++ b/hackathon_site/dashboard/frontend/src/pages/Acknowledgement/Acknowledgement.test.tsx @@ -215,11 +215,8 @@ describe("", () => { createProfileAPI, createProfileRequest ); - expect( - getByText( - `${mockUserWithoutProfile.first_name}, you're ready to get started. We've placed you in Team ${createProfileAPIResponse.data.team} but you can leave and join another team anytime.` - ) - ).toBeInTheDocument(); + expect(getByText(/you're ready to get started/i)).toBeInTheDocument(); + expect(getByText(createProfileAPIResponse.data.team)).toBeInTheDocument(); fireEvent.click(getByText("Let's Go!")); }); }); diff --git a/hackathon_site/dashboard/frontend/src/pages/Cart/Cart.test.tsx b/hackathon_site/dashboard/frontend/src/pages/Cart/Cart.test.tsx index 115c694..d9b6fa1 100644 --- a/hackathon_site/dashboard/frontend/src/pages/Cart/Cart.test.tsx +++ b/hackathon_site/dashboard/frontend/src/pages/Cart/Cart.test.tsx @@ -113,11 +113,11 @@ describe("Cart Page", () => { test("No items in the cart", async () => { const store = makeStoreWithEntities({ hardware: mockHardware }); - const { getByText } = render(, { store }); + const { getByText, getByTestId } = render(, { store }); expect(getByText(/no items in cart/i)).toBeInTheDocument(); // Test for quantity - expect(getByText(0)).toBeInTheDocument(); + expect(getByTestId("cart-quantity-total")).toHaveTextContent("0"); }); test("removeFromCart button", async () => { diff --git a/hackathon_site/dashboard/frontend/src/pages/Dashboard/Dashboard.test.tsx b/hackathon_site/dashboard/frontend/src/pages/Dashboard/Dashboard.test.tsx index 6d86592..6410214 100644 --- a/hackathon_site/dashboard/frontend/src/pages/Dashboard/Dashboard.test.tsx +++ b/hackathon_site/dashboard/frontend/src/pages/Dashboard/Dashboard.test.tsx @@ -75,6 +75,7 @@ describe("Dashboard Page", () => { const newHardwareData: Hardware = { id: mockCheckedOutOrders[0].items[0].hardware_id, name: "Randome hardware", + credits: 5, model_number: "90", manufacturer: "Tesla", datasheet: "", @@ -126,14 +127,6 @@ describe("Dashboard Page", () => { await waitFor(() => { expect(get).toHaveBeenNthCalledWith(5, hardwareDetailUri); expect(getByText("Product Overview")).toBeVisible(); - expect( - getByText(`- Max ${newHardwareData.max_per_team} of this item`) - ).toBeInTheDocument(); - expect( - getByText( - `- Max ${category.max_per_team} of items under category ${category.name}` - ) - ).toBeInTheDocument(); expect(getByText(newHardwareData.model_number)).toBeInTheDocument(); expect(getByText(newHardwareData.manufacturer)).toBeInTheDocument(); if (newHardwareData.notes) diff --git a/hackathon_site/dashboard/frontend/src/setupTests.ts b/hackathon_site/dashboard/frontend/src/setupTests.ts index 611429f..a4f3d7e 100644 --- a/hackathon_site/dashboard/frontend/src/setupTests.ts +++ b/hackathon_site/dashboard/frontend/src/setupTests.ts @@ -14,3 +14,9 @@ window.matchMedia = removeListener: function () {}, }; }; + +// Keep tests isolated: some features persist state to localStorage +// (e.g. admin order filters), which would otherwise leak between tests. +afterEach(() => { + window.localStorage.clear(); +}); diff --git a/hackathon_site/dashboard/frontend/src/slices/hardware/cartSlice.test.ts b/hackathon_site/dashboard/frontend/src/slices/hardware/cartSlice.test.ts index 0fa0051..eda7c32 100644 --- a/hackathon_site/dashboard/frontend/src/slices/hardware/cartSlice.test.ts +++ b/hackathon_site/dashboard/frontend/src/slices/hardware/cartSlice.test.ts @@ -65,19 +65,21 @@ describe("addToCart action", () => { test("addToCart with new items", async () => { const store = makeStore(); - store.dispatch(addToCart({ hardware_id: 1, quantity: 2 })); + store.dispatch(addToCart({ hardware_id: 1, quantity: 2, credits: 5 })); - store.dispatch(addToCart({ hardware_id: 2, quantity: 3 })); + store.dispatch(addToCart({ hardware_id: 2, quantity: 3, credits: 5 })); await waitFor(() => { expect(cartSelectors.selectIds(store.getState())).toEqual([1, 2]); expect(cartSelectors.selectById(store.getState(), 1)).toEqual({ hardware_id: 1, quantity: 2, + credits: 5, }); expect(cartSelectors.selectById(store.getState(), 2)).toEqual({ hardware_id: 2, quantity: 3, + credits: 5, }); }); }); @@ -85,19 +87,21 @@ describe("addToCart action", () => { test("addToCart updates existing item", async () => { const store = makeStore(); - store.dispatch(addToCart({ hardware_id: 1, quantity: 2 })); - store.dispatch(addToCart({ hardware_id: 2, quantity: 3 })); - store.dispatch(addToCart({ hardware_id: 1, quantity: 3 })); + store.dispatch(addToCart({ hardware_id: 1, quantity: 2, credits: 5 })); + store.dispatch(addToCart({ hardware_id: 2, quantity: 3, credits: 5 })); + store.dispatch(addToCart({ hardware_id: 1, quantity: 3, credits: 5 })); await waitFor(() => { expect(cartSelectors.selectIds(store.getState())).toEqual([1, 2]); expect(cartSelectors.selectById(store.getState(), 1)).toEqual({ hardware_id: 1, quantity: 5, + credits: 5, }); expect(cartSelectors.selectById(store.getState(), 2)).toEqual({ hardware_id: 2, quantity: 3, + credits: 5, }); }); }); @@ -116,10 +120,12 @@ describe("removeFromCart action", () => { expect(cartSelectors.selectById(store.getState(), 1)).toEqual({ hardware_id: 1, quantity: 3, + credits: 5, }); expect(cartSelectors.selectById(store.getState(), 3)).toEqual({ hardware_id: 3, quantity: 2, + credits: 5, }); expect(cartSelectors.selectById(store.getState(), 2)).toEqual(undefined); }); @@ -143,6 +149,7 @@ describe("updateCart action", () => { expect(cartSelectors.selectById(store.getState(), 1)).toEqual({ hardware_id: mockCartItems[0].hardware_id, quantity: 25, + credits: 5, }); }); }); diff --git a/hackathon_site/event/jinja2/event/base.html b/hackathon_site/event/jinja2/event/base.html index 3135521..162cdbf 100644 --- a/hackathon_site/event/jinja2/event/base.html +++ b/hackathon_site/event/jinja2/event/base.html @@ -15,7 +15,7 @@ - {% block title %}{{ hackathon_name }} {{ localtime(event_start_date).strftime("%Y") }}{% endblock %} + {% block title %}{{ hackathon_name }} 2027{% endblock %} diff --git a/hackathon_site/event/jinja2/event/change_password.html b/hackathon_site/event/jinja2/event/change_password.html index d913ab7..60dfcc8 100644 --- a/hackathon_site/event/jinja2/event/change_password.html +++ b/hackathon_site/event/jinja2/event/change_password.html @@ -1,6 +1,6 @@ {% extends "event/form_base.html" %} -{% block title %}Change Password - MakeUofT 2026{% endblock %} +{% block title %}Change Password - MakeUofT 2027{% endblock %} {% block form_title %}Change Password{% endblock %} {% block nav_links %} diff --git a/hackathon_site/event/jinja2/event/change_password_done.html b/hackathon_site/event/jinja2/event/change_password_done.html index 1305457..7d9ce29 100644 --- a/hackathon_site/event/jinja2/event/change_password_done.html +++ b/hackathon_site/event/jinja2/event/change_password_done.html @@ -1,6 +1,6 @@ {% extends "event/base.html" %} -{% block title %}Change Password - MakeUofT 2026{% endblock %} +{% block title %}Change Password - MakeUofT 2027{% endblock %} {% block nav_links %}
  • Dashboard
  • Change Password
  • diff --git a/hackathon_site/event/jinja2/event/dashboard_base.html b/hackathon_site/event/jinja2/event/dashboard_base.html index 09b86bb..5d1ce76 100644 --- a/hackathon_site/event/jinja2/event/dashboard_base.html +++ b/hackathon_site/event/jinja2/event/dashboard_base.html @@ -15,7 +15,7 @@

    Dashboard

    {% if application is none %} {% if not is_registration_open() %}

    Applications have closed

    -

    Unfortunately, the deadline to apply for {{ hackathon_name }} was {{ localtime(registration_close_date).strftime("%B %-d, %Y") }}.

    +

    Unfortunately, the deadline to apply for {{ hackathon_name }} was {{ localtime(registration_close_date)|strftime("%B %-d, %Y") }}.


    If you have any questions or concerns, please contact us.

    {% else %} @@ -112,7 +112,7 @@

    Congratulations! You've been accepted into {{ hackatho {% elif review.status == "Waitlisted" %}

    You've been waitlisted for {{ hackathon_name }}

    The {{ hackathon_name }} team has reviewed your application, and have decided not to grant you a guaranteed spot - at {{ hackathon_name }} and to place you in our waitlist. On {{ waitlisted_acceptance_start_time.strftime("%B %-d, %Y, at %-I:%M %p") }}, we will begin allowing + at {{ hackathon_name }} and to place you in our waitlist. On {{ waitlisted_acceptance_start_time|strftime("%B %-d, %Y, at %-I:%M %p") }}, we will begin allowing people from the waitlist into the event on a first-come, first-serve basis if there is still room. We offer no guarantee that you will be allowed into the event, regardless of how early you arrive. Please read our participant package for all the info regarding the event if you plan on @@ -232,7 +232,7 @@

    Application FAQs

    Please send an email to {{ contact_email }} with your name, email you used to apply, expected arrival time, and reason as to why you’re arriving late and we’ll save your spot for you.

    How does the waitlist work the day of?

    -

    The rank on the waitlist is first-come first serve, meaning the sooner you arrive at the event on {{ waitlisted_acceptance_start_time.strftime("%A") }}, the higher your placement on our waitlist. At {{ waitlisted_acceptance_start_time.strftime("%-I:%M %p") }}, if we have any spots remaining, we will be letting waitlisted people in.

    +

    The rank on the waitlist is first-come first serve, meaning the sooner you arrive at the event on {{ waitlisted_acceptance_start_time.strftime("%A") }}, the higher your placement on our waitlist. At {{ waitlisted_acceptance_start_time|strftime("%-I:%M %p") }}, if we have any spots remaining, we will be letting waitlisted people in.

    Other questions?

    If you have any questions or concerns, feel free to contact us at {{ contact_email }}.

    diff --git a/hackathon_site/event/jinja2/event/landing.html b/hackathon_site/event/jinja2/event/landing.html index d0c08b2..901486f 100644 --- a/hackathon_site/event/jinja2/event/landing.html +++ b/hackathon_site/event/jinja2/event/landing.html @@ -4,9 +4,9 @@ {% block head_extends %} {% endblock %} @@ -23,13 +23,13 @@ {% block body %} -Major League Hacking 2026 Hackathon Season +Major League Hacking 2027 Hackathon Season
    -

    MakeUofT 2026

    +

    MakeUofT 2027

    Canada's Largest Makeathon

    @@ -42,8 +42,7 @@

    Canada's Largest Makeathon

    University of Toronto
    - {# Update this logic if your event ends in a different month or year #} - {{ localtime(event_start_date).strftime("%B %d") }}-{{ localtime(event_end_date).strftime("%d, %Y") }} + TBD, 2027