From ac3881356508b305d6fbea7f077eea4ee7eb571f Mon Sep 17 00:00:00 2001 From: Helene Lotsberg Date: Tue, 6 Oct 2026 14:12:45 +0200 Subject: [PATCH 1/4] setup for explorePage test and test for displaying plants when no filters selected --- frontend/src/tests/ExplorePage.test.tsx | 45 +++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 frontend/src/tests/ExplorePage.test.tsx diff --git a/frontend/src/tests/ExplorePage.test.tsx b/frontend/src/tests/ExplorePage.test.tsx new file mode 100644 index 00000000..4cea5070 --- /dev/null +++ b/frontend/src/tests/ExplorePage.test.tsx @@ -0,0 +1,45 @@ +import { render, screen, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import ExplorePage from '../pages/explorePage/ExplorePage'; + +// mock i18next to return the key as the translation +vi.mock("react-i18next", () => ({ + useTranslation: () => ({ + t: (key: string) => key, + }), +})); + +// set up the page and user interactions for each test +function setup() { + const user = userEvent.setup({ delay: null }); + render(); + return user; +} + +// get all plant cards displayed on the page +const cards = () => screen.getAllByRole("listitem"); + +describe("ExplorePage", () => { + // clear stored filter and search values before each test, + // and use fake timers to control the search debounce + beforeEach(() => { + sessionStorage.clear(); + // shouldAdvanceTime keeps userEvent from hanging while fake timers are on + vi.useFakeTimers({ shouldAdvanceTime: true }); + }); + + // restore real timers after each test + afterEach(() => { + vi.useRealTimers(); + }); + + // test that all plants are displayed when no filters are selected + it("displays all plants when no filters are selected", () => { + setup(); + expect(cards()).toHaveLength(15); + expect( + screen.getByRole("button", { name: "Monstera" }), + ).toBeInTheDocument(); + }); +}); \ No newline at end of file From 21195c993376720c80da57e91e7d9b8430bdf01e Mon Sep 17 00:00:00 2001 From: Helene Lotsberg Date: Tue, 6 Oct 2026 14:14:13 +0200 Subject: [PATCH 2/4] add test for opening/closing card info on ExplorePage --- frontend/src/tests/ExplorePage.test.tsx | 40 +++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/frontend/src/tests/ExplorePage.test.tsx b/frontend/src/tests/ExplorePage.test.tsx index 4cea5070..8ae0cc2a 100644 --- a/frontend/src/tests/ExplorePage.test.tsx +++ b/frontend/src/tests/ExplorePage.test.tsx @@ -42,4 +42,44 @@ describe("ExplorePage", () => { screen.getByRole("button", { name: "Monstera" }), ).toBeInTheDocument(); }); + + // test that clicking a plant card displays its information + it("opens and closes plant card information", async () => { + const user = setup(); + + const monstera = screen.getByRole("button", { name: "Monstera" }); + + // --- Closed state --- + expect(monstera).toHaveAttribute("aria-pressed", "false"); + expect( + within(monstera).queryByText("explorePage.average"), + ).not.toBeInTheDocument(); + + // --- Open the card --- + await user.click(monstera); + + // the card now reports that it is pressed (open) + expect(monstera).toHaveAttribute("aria-pressed", "true"); + + expect( + within(monstera).getByText("explorePage.average"), + ).toBeInTheDocument(); + expect( + within(monstera).getByText("explorePage.part_shade"), + ).toBeInTheDocument(); + expect( + within(monstera).getByText("explorePage.poison"), + ).toBeInTheDocument(); + expect( + within(monstera).getByText("explorePage.indoor"), + ).toBeInTheDocument(); + + // --- Close the card by clicking it again --- + await user.click(monstera); + + expect(monstera).toHaveAttribute("aria-pressed", "false"); + expect( + within(monstera).queryByText("explorePage.average"), + ).not.toBeInTheDocument(); + }); }); \ No newline at end of file From 897e2e2cbb117685f7481ecd9d3bd525e454a9b7 Mon Sep 17 00:00:00 2001 From: Helene Lotsberg Date: Tue, 6 Oct 2026 14:16:26 +0200 Subject: [PATCH 3/4] mark the remaining tests as it.todo, with notes on which to move to the backend (search and filtering) and which are rewritten with MockProvider once Apollo is in place --- frontend/src/tests/ExplorePage.test.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/frontend/src/tests/ExplorePage.test.tsx b/frontend/src/tests/ExplorePage.test.tsx index 8ae0cc2a..836b253f 100644 --- a/frontend/src/tests/ExplorePage.test.tsx +++ b/frontend/src/tests/ExplorePage.test.tsx @@ -82,4 +82,23 @@ describe("ExplorePage", () => { within(monstera).queryByText("explorePage.average"), ).not.toBeInTheDocument(); }); + + // --- Moves to backend (the resolver/database decides which plants match) --- + it.todo("filters plants by search"); // -> backend (incl. case-insensitive) + it.todo("filters plants by watering needs"); // -> backend + it.todo("filters plants by sunlight requirements"); // -> backend + it.todo("filters plants by location"); // -> backend + it.todo("filters plants by edibility"); // -> backend + it.todo("combines multiple filters"); // -> backend + it.todo("returns an empty list when nothing matches"); // -> backend + + // --- Stays in frontend, written after Apollo (MockedProvider) --- + it.todo("sends the search text in the query after the debounce delay"); + it.todo("sends the selected filter values in the query"); + it.todo("resets the search and filters"); + it.todo("shows a loading state"); + it.todo("shows an error message when the query fails"); + it.todo("shows a message when the result is empty"); + + // Snapshot tests ? }); \ No newline at end of file From c7d538962706eb537d8f448b476f4e9d798caffe Mon Sep 17 00:00:00 2001 From: Helene Lotsberg Date: Tue, 6 Oct 2026 14:17:14 +0200 Subject: [PATCH 4/4] format with prettier --- frontend/src/tests/ExplorePage.test.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/tests/ExplorePage.test.tsx b/frontend/src/tests/ExplorePage.test.tsx index 836b253f..9e49f801 100644 --- a/frontend/src/tests/ExplorePage.test.tsx +++ b/frontend/src/tests/ExplorePage.test.tsx @@ -1,7 +1,7 @@ -import { render, screen, within } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import ExplorePage from '../pages/explorePage/ExplorePage'; +import { render, screen, within } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import ExplorePage from "../pages/explorePage/ExplorePage"; // mock i18next to return the key as the translation vi.mock("react-i18next", () => ({ @@ -101,4 +101,4 @@ describe("ExplorePage", () => { it.todo("shows a message when the result is empty"); // Snapshot tests ? -}); \ No newline at end of file +});