-
-
-
-
-
-
-
+
+ {/* On desktop, the component list determines the column height. */}
+
- >
+
);
}
diff --git a/frontend/src/test/PcPartCard.test.tsx b/frontend/src/test/PcPartCard.test.tsx
index 17904b6..8a314e0 100644
--- a/frontend/src/test/PcPartCard.test.tsx
+++ b/frontend/src/test/PcPartCard.test.tsx
@@ -50,14 +50,14 @@ it("retains specifications for reopening details and adding from the card", asyn
,
);
- await user.click(screen.getByRole("button", { name: "Show details" }));
+ await user.click(screen.getByRole("article"));
expect(onShowDetails).toHaveBeenCalledWith({ ...part, details });
// Closing the parent's dialog leaves the same card mounted. A fresh summary
// can also arrive without discarding its specifications or freezing its price.
const updatedPart = { ...part, price_eur: 499 };
rerender(
);
- await user.click(screen.getByRole("button", { name: "Show details" }));
+ await user.click(screen.getByRole("article"));
expect(onShowDetails).toHaveBeenLastCalledWith({ ...updatedPart, details });
await user.click(screen.getByRole("button", { name: "Add to build" }));
@@ -66,6 +66,7 @@ it("retains specifications for reopening details and adding from the card", asyn
details,
});
expect(getPartSpecifications).toHaveBeenCalledTimes(1);
+ expect(onShowDetails).toHaveBeenCalledTimes(2);
});
it("shows an error and lets the user retry a failed details request", async () => {
@@ -76,17 +77,17 @@ it("shows an error and lets the user retry a failed details request", async () =
.mockResolvedValueOnce(details);
renderWithStore(
);
- await user.click(screen.getByRole("button", { name: "Show details" }));
+ await user.click(screen.getByRole("article"));
expect(screen.getByRole("alert")).toHaveTextContent(
"Could not load component details",
);
expect(onShowDetails).not.toHaveBeenCalled();
- await user.click(screen.getByRole("button", { name: "Show details" }));
+ await user.click(screen.getByRole("article"));
expect(onShowDetails).toHaveBeenCalledWith({ ...part, details });
expect(screen.queryByRole("alert")).not.toBeInTheDocument();
});
-it("disables repeat detail clicks and ignores a response after the card unmounts", async () => {
+it("ignores repeat card clicks and a response after the card unmounts", async () => {
const user = userEvent.setup();
const onShowDetails = vi.fn();
let resolve!: (details: PcPart["details"]) => void;
@@ -99,10 +100,10 @@ it("disables repeat detail clicks and ignores a response after the card unmounts
,
);
- await user.click(screen.getByRole("button", { name: "Show details" }));
- expect(
- screen.getByRole("button", { name: "Loading details..." }),
- ).toBeDisabled();
+ await user.click(screen.getByRole("article"));
+ await user.click(screen.getByRole("article"));
+ expect(getPartSpecifications).toHaveBeenCalledTimes(1);
+ expect(onShowDetails).not.toHaveBeenCalled();
const signal = vi.mocked(getPartSpecifications).mock.calls[0][1];
unmount();
expect(signal?.aborted).toBe(true);
@@ -113,8 +114,9 @@ it("disables repeat detail clicks and ignores a response after the card unmounts
it("adds directly and removes the part through Redux without opening details", async () => {
const user = userEvent.setup();
vi.mocked(getPartSpecifications).mockResolvedValue(details);
+ const onShowDetails = vi.fn();
const { store } = renderWithStore(
-
,
+
,
);
await user.click(screen.getByRole("button", { name: "Add to build" }));
@@ -132,4 +134,5 @@ it("adds directly and removes the part through Redux without opening details", a
screen.getByRole("button", { name: "Add to build" }),
).toBeInTheDocument();
expect(getPartSpecifications).toHaveBeenCalledTimes(1);
+ expect(onShowDetails).not.toHaveBeenCalled();
});