5105ac224c
* feat: add anchored range selection to multi-select reducer * feat: cmd+click and shift+click multi-select on kanban board * feat: add cmd/shift multi-select to sidebar task list * test: e2e coverage for cmd/shift multi-select * fix: harden multi-select selection lifecycle from review feedback * test: scope multi-select e2e helpers to active containers * fix: add sidebar multi-select hook tests and tighten bulk-action lifecycle * fix: prune hidden sidebar selections and order bulk moves by view * test: cover visible-order bulk move and anchor realignment * fix: harden sidebar bulk-move scope and keyboard selection parity * fix: order kanban bulk moves by board position * test: cover multi-select helpers and fix stale-id sort fallback * fix: order kanban card context-menu moves by board position * feat: sidebar multi-select shows only bulk-valid actions with bulk pin and delete * fix: harden multi-select bulk ordering, selection clearing, and a11y * fix: gate kanban card move-to-step for mixed-workflow selections * fix: unpin fully pinned sidebar selections * refactor: keep sidebar task components under limits * test: restore sidebar selection console spy safely
65 lines
2.1 KiB
TypeScript
65 lines
2.1 KiB
TypeScript
import { describe, it, expect, vi } from "vitest";
|
|
import { dispatchKanbanCardClick, type Task } from "./kanban-card";
|
|
|
|
function fakeEvent(mods: Partial<MouseEvent> = {}) {
|
|
return {
|
|
metaKey: false,
|
|
ctrlKey: false,
|
|
shiftKey: false,
|
|
preventDefault: vi.fn(),
|
|
...mods,
|
|
} as unknown as React.MouseEvent;
|
|
}
|
|
|
|
const task = { id: "t1", title: "T", workflowStepId: "s1" } as Task;
|
|
|
|
function handlers() {
|
|
return {
|
|
onToggleSelect: vi.fn(),
|
|
onRangeSelect: vi.fn(),
|
|
onClick: vi.fn(),
|
|
isMultiSelectMode: false,
|
|
};
|
|
}
|
|
|
|
describe("dispatchKanbanCardClick", () => {
|
|
it("cmd/meta-click toggles and prevents default", () => {
|
|
const h = handlers();
|
|
const e = fakeEvent({ metaKey: true });
|
|
dispatchKanbanCardClick(e, task.id, task, h);
|
|
expect(e.preventDefault).toHaveBeenCalled();
|
|
expect(h.onToggleSelect).toHaveBeenCalledWith("t1");
|
|
expect(h.onClick).not.toHaveBeenCalled();
|
|
expect(h.onRangeSelect).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("ctrl-click toggles (Windows/Linux)", () => {
|
|
const h = handlers();
|
|
dispatchKanbanCardClick(fakeEvent({ ctrlKey: true }), task.id, task, h);
|
|
expect(h.onToggleSelect).toHaveBeenCalledWith("t1");
|
|
});
|
|
|
|
it("shift-click range-selects and prevents default", () => {
|
|
const h = handlers();
|
|
const e = fakeEvent({ shiftKey: true });
|
|
dispatchKanbanCardClick(e, task.id, task, h);
|
|
expect(e.preventDefault).toHaveBeenCalled();
|
|
expect(h.onRangeSelect).toHaveBeenCalledWith("t1");
|
|
expect(h.onToggleSelect).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("plain click while in multi-select mode toggles", () => {
|
|
const h = { ...handlers(), isMultiSelectMode: true };
|
|
dispatchKanbanCardClick(fakeEvent(), task.id, task, h);
|
|
expect(h.onToggleSelect).toHaveBeenCalledWith("t1");
|
|
expect(h.onClick).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("plain click outside multi-select mode previews/opens", () => {
|
|
const h = handlers();
|
|
dispatchKanbanCardClick(fakeEvent(), task.id, task, h);
|
|
expect(h.onClick).toHaveBeenCalledWith(task);
|
|
expect(h.onToggleSelect).not.toHaveBeenCalled();
|
|
});
|
|
});
|