Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,32 @@ import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { WaveLeaderboardCurationGroupSelect } from "@/components/waves/leaderboard/header/WaveLeaderboardCurationGroupSelect";

const commonSelectMock = jest.fn();
let mockBreakpoint = "MD";

jest.mock("@/components/utils/select/CommonSelect", () => ({
jest.mock("react-use", () => ({
createBreakpoint: jest.fn(() => () => mockBreakpoint),
}));

jest.mock("@tanstack/react-query", () => ({
useQueries: jest.fn(({ queries, combine }: any) => {
const results = (queries ?? []).map(() => ({ data: undefined }));
return combine ? combine(results) : results;
}),
}));

const commonDropdownMock = jest.fn((props: any) => (
<div data-testid="mobile-dropdown">
{props.items.map((item: any) => (
<button key={item.key} onClick={() => props.setSelected(item.value)}>
{item.label}
</button>
))}
</div>
));

jest.mock("@/components/utils/select/dropdown/CommonDropdown", () => ({
__esModule: true,
default: (props: any) => {
commonSelectMock(props);
return (
<div data-testid="common-select">
{props.items.map((item: any) => (
<button key={item.key} onClick={() => props.setSelected(item.value)}>
{item.label}
</button>
))}
<span data-testid="active-item">
{props.activeItem === null ? "null" : props.activeItem}
</span>
</div>
);
},
default: (props: any) => commonDropdownMock(props),
}));

const groups = [
Expand All @@ -44,7 +51,8 @@ const groups = [

describe("WaveLeaderboardCurationGroupSelect", () => {
beforeEach(() => {
commonSelectMock.mockClear();
mockBreakpoint = "MD";
commonDropdownMock.mockClear();
});

it("returns null when there are no curation groups", () => {
Expand All @@ -57,10 +65,9 @@ describe("WaveLeaderboardCurationGroupSelect", () => {
);

expect(container).toBeEmptyDOMElement();
expect(commonSelectMock).not.toHaveBeenCalled();
});

it("maps curation options and passes select configuration", () => {
it("renders horizontal tabs on desktop", () => {
render(
<WaveLeaderboardCurationGroupSelect
groups={groups}
Expand All @@ -70,19 +77,31 @@ describe("WaveLeaderboardCurationGroupSelect", () => {
);

expect(screen.getByTestId("curation-group-select")).toBeInTheDocument();
expect(screen.getByTestId("active-item")).toHaveTextContent("cg-2");

const commonSelectProps = commonSelectMock.mock.calls[0][0];
expect(commonSelectProps.filterLabel).toBe("Curation");
expect(commonSelectProps.fill).toBe(false);
expect(commonSelectProps.items).toEqual([
{ key: "all-submissions", label: "All submissions", value: null },
{ key: "cg-1", label: "Curators One", value: "cg-1" },
{ key: "cg-2", label: "Curators Two", value: "cg-2" },
]);
expect(screen.getByText("All submissions")).toBeInTheDocument();
expect(screen.getByText("Curators One")).toBeInTheDocument();
expect(screen.getByText("Curators Two")).toBeInTheDocument();
expect(commonDropdownMock).not.toHaveBeenCalled();
});

it("highlights the active tab on desktop", () => {
render(
<WaveLeaderboardCurationGroupSelect
groups={groups}
selectedGroupId={"cg-2"}
onChange={jest.fn()}
/>
);

const activeButton = screen.getByText("Curators Two").closest("button")!;
expect(activeButton.className).toContain("tw-ring-iron-600");

const inactiveButton = screen
.getByText("All submissions")
.closest("button")!;
expect(inactiveButton.className).toContain("tw-ring-transparent");
});

it("handles selecting curation options", async () => {
it("handles tab clicks on desktop", async () => {
const user = userEvent.setup();
const onChange = jest.fn();

Expand All @@ -94,10 +113,49 @@ describe("WaveLeaderboardCurationGroupSelect", () => {
/>
);

await user.click(screen.getByRole("button", { name: "Curators One" }));
await user.click(screen.getByRole("button", { name: "All submissions" }));
await user.click(screen.getByText("Curators One"));
await user.click(screen.getByText("All submissions"));

expect(onChange).toHaveBeenNthCalledWith(1, "cg-1");
expect(onChange).toHaveBeenNthCalledWith(2, null);
});

it("renders dropdown on mobile", () => {
mockBreakpoint = "S";

render(
<WaveLeaderboardCurationGroupSelect
groups={groups}
selectedGroupId={null}
onChange={jest.fn()}
/>
);

expect(screen.getByTestId("mobile-dropdown")).toBeInTheDocument();
expect(commonDropdownMock).toHaveBeenCalledWith(
expect.objectContaining({
filterLabel: "Group",
showFilterLabel: true,
size: "sm",
activeItem: null,
})
);
});

it("handles dropdown selection on mobile", async () => {
mockBreakpoint = "S";
const user = userEvent.setup();
const onChange = jest.fn();

render(
<WaveLeaderboardCurationGroupSelect
groups={groups}
selectedGroupId={null}
onChange={onChange}
/>
);

await user.click(screen.getByText("Curators One"));
expect(onChange).toHaveBeenCalledWith("cg-1");
});
});
Original file line number Diff line number Diff line change
@@ -1,96 +1,73 @@
import { WaveleaderboardSort } from "@/components/waves/leaderboard/header/WaveleaderboardSort";
import { WaveDropsLeaderboardSort } from "@/hooks/useWaveDropsLeaderboard";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

let mockBreakpoint = "MD";
const commonDropdownMock = jest.fn((props: any) => (
<button
data-testid="mobile-sort"
data-testid="sort-dropdown"
onClick={() => props.setSelected(WaveDropsLeaderboardSort.CREATED_AT)}
>
{props.filterLabel}: {props.activeItem}
</button>
));

jest.mock("react-use", () => ({
createBreakpoint: jest.fn(() => () => mockBreakpoint),
}));

jest.mock("@/components/utils/select/dropdown/CommonDropdown", () => ({
__esModule: true,
default: (props: any) => commonDropdownMock(props),
}));

describe("WaveleaderboardSort", () => {
beforeEach(() => {
mockBreakpoint = "MD";
commonDropdownMock.mockClear();
});

it("shows desktop sort tabs and triggers changes on desktop", async () => {
it("always renders dropdown sort and forwards selection", async () => {
const onSortChange = jest.fn();
const user = userEvent.setup();
const queryClient = new QueryClient();

render(
<QueryClientProvider client={queryClient}>
<WaveleaderboardSort
sort={WaveDropsLeaderboardSort.RANK}
onSortChange={onSortChange}
/>
</QueryClientProvider>
<WaveleaderboardSort
sort={WaveDropsLeaderboardSort.RANK}
onSortChange={onSortChange}
/>
);

const current = screen.getByText("Current Vote");
expect(current.className).toContain("tw-bg-white/10");

await user.click(screen.getByText("Projected Vote"));
expect(onSortChange).toHaveBeenCalledWith(
WaveDropsLeaderboardSort.RATING_PREDICTION
expect(screen.getByTestId("sort-dropdown")).toHaveTextContent("Sort: RANK");
expect(screen.getByTestId("sort-dropdown").parentElement).toHaveClass(
"tw-min-w-0"
);

await user.click(screen.getByText("Hot"));
expect(onSortChange).toHaveBeenCalledWith(WaveDropsLeaderboardSort.TREND);

await user.click(screen.getByText("Newest"));
await user.click(screen.getByTestId("sort-dropdown"));
expect(onSortChange).toHaveBeenCalledWith(
WaveDropsLeaderboardSort.CREATED_AT
);

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

it("shows dropdown sort and forwards selection on small screens", async () => {
mockBreakpoint = "S";

const onSortChange = jest.fn();
const user = userEvent.setup();
const queryClient = new QueryClient();

it("passes correct props to CommonDropdown", () => {
render(
<QueryClientProvider client={queryClient}>
<WaveleaderboardSort
sort={WaveDropsLeaderboardSort.RANK}
onSortChange={onSortChange}
/>
</QueryClientProvider>
<WaveleaderboardSort
sort={WaveDropsLeaderboardSort.TREND}
onSortChange={jest.fn()}
/>
);

expect(screen.queryByText("Current Vote")).not.toBeInTheDocument();
expect(screen.getByTestId("mobile-sort")).toHaveTextContent("Sort: RANK");
expect(screen.getByTestId("mobile-sort").parentElement).toHaveClass(
"tw-w-full",
"tw-min-w-0"
expect(commonDropdownMock).toHaveBeenCalledWith(
expect.objectContaining({
activeItem: WaveDropsLeaderboardSort.TREND,
filterLabel: "Sort",
size: "sm",
showFilterLabel: true,
})
);
expect(
screen.getByTestId("mobile-sort").parentElement?.className
).not.toContain("tw-w-[11rem]");

await user.click(screen.getByTestId("mobile-sort"));
expect(onSortChange).toHaveBeenCalledWith(
WaveDropsLeaderboardSort.CREATED_AT
);
const items = commonDropdownMock.mock.calls[0]![0].items;
expect(items).toHaveLength(4);
expect(items.map((i: any) => i.label)).toEqual([
"Current Vote",
"Projected Vote",
"Hot",
"Newest",
]);
});
});
14 changes: 7 additions & 7 deletions components/utils/select/dropdown/CommonDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,15 @@ export default function CommonDropdown<T, U = unknown>(
: "tw-bg-iron-800"
} ${
size === "md"
? "tw-py-3"
? "tw-py-3 tw-text-sm"
: size === "tabs"
? "tw-py-[11px]"
: "tw-py-2.5"
} tw-w-full tw-truncate tw-text-left tw-relative tw-block tw-whitespace-nowrap tw-rounded-lg tw-border-0 tw-pl-3.5 tw-pr-10 tw-font-semibold tw-caret-primary-400 tw-shadow-sm tw-ring-1 tw-ring-inset tw-ring-iron-700
focus:tw-outline-none focus:tw-ring-1 focus:tw-ring-inset focus:tw-ring-primary-400 tw-text-sm hover:tw-bg-iron-800 tw-transition tw-duration-300 tw-ease-out tw-justify-between`}
? "tw-py-[11px] tw-text-sm"
: "tw-py-2.5 tw-text-xs"
} tw-w-full tw-truncate tw-text-left tw-relative tw-block tw-whitespace-nowrap tw-rounded-lg tw-border-0 tw-pl-3.5 tw-pr-8 tw-font-semibold tw-caret-primary-400 tw-shadow-sm tw-ring-1 tw-ring-inset tw-ring-iron-700
focus:tw-outline-none focus:tw-ring-1 focus:tw-ring-inset focus:tw-ring-primary-400 hover:tw-bg-iron-800 tw-transition tw-duration-300 tw-ease-out tw-justify-between`}
>
{showFilterLabel && (
<span className="tw-font-semibold">{filterLabel}: </span>
<span className="tw-font-semibold tw-text-iron-500">{filterLabel}: </span>
)}
{computedLabel}
{sortDirection && (
Expand All @@ -107,7 +107,7 @@ export default function CommonDropdown<T, U = unknown>(
<div className="tw-pointer-events-none tw-absolute tw-inset-y-0 tw-right-0 tw-flex tw-items-center -tw-mr-1 tw-pr-3.5">
<svg
ref={iconScope}
className="tw-h-5 tw-w-5"
className="tw-h-4 tw-w-4"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
Expand Down
Loading