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
57 lines
2.1 KiB
TypeScript
57 lines
2.1 KiB
TypeScript
import { act, renderHook } from "@testing-library/react";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
import { useBulkConfirmDialog } from "./task-session-sidebar-selection";
|
|
|
|
const tasks = [
|
|
{ id: "a", remoteExecutorType: "docker" },
|
|
{ id: "b", remoteExecutorType: null },
|
|
{ id: "c", remoteExecutorType: "sprites" },
|
|
];
|
|
|
|
describe("useBulkConfirmDialog", () => {
|
|
it("open() captures the ids and their executor types", () => {
|
|
const bulkArchive = vi.fn().mockResolvedValue(undefined);
|
|
const { result } = renderHook(() => useBulkConfirmDialog(tasks, bulkArchive));
|
|
|
|
act(() => result.current.open(["a", "c"]));
|
|
expect(result.current.state).toEqual({ ids: ["a", "c"], executorTypes: ["docker", "sprites"] });
|
|
});
|
|
|
|
it("confirm() archives the captured ids and clears the dialog", async () => {
|
|
const bulkArchive = vi.fn().mockResolvedValue(undefined);
|
|
const { result } = renderHook(() => useBulkConfirmDialog(tasks, bulkArchive));
|
|
|
|
act(() => result.current.open(["a", "b"]));
|
|
await act(async () => {
|
|
await result.current.confirm({ cascade: true });
|
|
});
|
|
expect(bulkArchive).toHaveBeenCalledWith(["a", "b"], { cascade: true });
|
|
expect(result.current.state).toBeNull();
|
|
});
|
|
|
|
it("confirm() is a no-op when no dialog is open", async () => {
|
|
const bulkArchive = vi.fn().mockResolvedValue(undefined);
|
|
const { result } = renderHook(() => useBulkConfirmDialog(tasks, bulkArchive));
|
|
|
|
await act(async () => {
|
|
await result.current.confirm({ cascade: false });
|
|
});
|
|
expect(bulkArchive).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("clears the dialog even when archiving rejects", async () => {
|
|
const bulkArchive = vi.fn().mockRejectedValue(new Error("boom"));
|
|
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
try {
|
|
const { result } = renderHook(() => useBulkConfirmDialog(tasks, bulkArchive));
|
|
act(() => result.current.open(["a"]));
|
|
await act(async () => {
|
|
await result.current.confirm({ cascade: false });
|
|
});
|
|
expect(result.current.state).toBeNull();
|
|
} finally {
|
|
errorSpy.mockRestore();
|
|
}
|
|
});
|
|
});
|