Files
kandev/apps/web/components/task/task-pr-picker-dialog.test.tsx
T

108 lines
3.5 KiB
TypeScript

import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
import { useState } from "react";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { TaskPR } from "@/lib/types/github";
import type { TaskMR } from "@/lib/types/gitlab";
import type { TaskReviewTarget } from "./task-pr-open";
import { TaskPRPickerDialog } from "./task-pr-picker-dialog";
const targets: TaskReviewTarget[] = [
{
type: "pr",
key: "pr:1",
url: "https://github.com/acme/kandev/pull/1",
review: {
id: "pr-1",
repo: "kandev",
pr_number: 1,
pr_title: "GitHub review",
state: "open",
checks_state: "",
checks_total: 0,
checks_passing: 0,
review_state: "",
mergeable_state: "",
review_count: 0,
pending_review_count: 0,
} as TaskPR,
},
{
type: "mr",
key: "mr:2",
url: "https://gitlab.example/acme/kandev/-/merge_requests/2",
review: {
id: "mr-2",
project_path: "acme/kandev",
mr_iid: 2,
mr_title: "GitLab review",
mr_url: "https://gitlab.example/acme/kandev/-/merge_requests/2",
state: "opened",
} as TaskMR,
},
];
const selectedAttribute = "data-selected";
function ControlledPicker({ onActivateIndex }: { onActivateIndex: (index: number) => void }) {
const [selectedIndex, setSelectedIndex] = useState(0);
return (
<TaskPRPickerDialog
open
onOpenChange={() => undefined}
targets={targets}
selectedIndex={selectedIndex}
onSelectedIndexChange={setSelectedIndex}
onActivateIndex={onActivateIndex}
/>
);
}
describe("TaskPRPickerDialog", () => {
afterEach(() => cleanup());
it("keeps controlled selection, focus, arrow keys, Enter, and click in sync", async () => {
const onActivateIndex = vi.fn();
render(<ControlledPicker onActivateIndex={onActivateIndex} />);
const prRow = screen.getByTestId("task-pr-picker-row-pr-1");
const mrRow = screen.getByTestId("task-mr-picker-row-mr-2");
expect(prRow.compareDocumentPosition(mrRow)).toBe(Node.DOCUMENT_POSITION_FOLLOWING);
await waitFor(() => expect(document.activeElement).toBe(prRow));
expect(prRow.getAttribute(selectedAttribute)).toBe("true");
fireEvent.keyDown(prRow, { key: "ArrowDown" });
await waitFor(() => expect(document.activeElement).toBe(mrRow));
expect(mrRow.getAttribute(selectedAttribute)).toBe("true");
fireEvent.keyDown(mrRow, { key: "ArrowDown" });
await waitFor(() => expect(document.activeElement).toBe(prRow));
expect(prRow.getAttribute(selectedAttribute)).toBe("true");
fireEvent.keyDown(prRow, { key: "ArrowUp" });
await waitFor(() => expect(document.activeElement).toBe(mrRow));
fireEvent.keyDown(mrRow, { key: "Enter" });
fireEvent.click(prRow);
expect(onActivateIndex).toHaveBeenNthCalledWith(1, 1);
expect(onActivateIndex).toHaveBeenNthCalledWith(2, 0);
});
it("activates the row focused with Tab when Enter is pressed", async () => {
const onActivateIndex = vi.fn();
render(<ControlledPicker onActivateIndex={onActivateIndex} />);
const prRow = screen.getByTestId("task-pr-picker-row-pr-1");
const mrRow = screen.getByTestId("task-mr-picker-row-mr-2");
await waitFor(() => expect(document.activeElement).toBe(prRow));
mrRow.focus();
expect(document.activeElement).toBe(mrRow);
await waitFor(() => expect(mrRow.getAttribute(selectedAttribute)).toBe("true"));
fireEvent.keyDown(mrRow, { key: "Enter" });
expect(onActivateIndex).toHaveBeenCalledWith(1);
});
});