diff --git a/canvas/src/components/__tests__/ConfirmDialog.test.tsx b/canvas/src/components/__tests__/ConfirmDialog.test.tsx
index 7798fdc5..adf5fa92 100644
--- a/canvas/src/components/__tests__/ConfirmDialog.test.tsx
+++ b/canvas/src/components/__tests__/ConfirmDialog.test.tsx
@@ -1,12 +1,114 @@
// @vitest-environment jsdom
-import { describe, it, expect, vi, afterEach } from "vitest";
-import { render, screen, fireEvent, cleanup } from "@testing-library/react";
+import { describe, it, expect, vi, afterEach, beforeEach } from "vitest";
+import { render, screen, fireEvent, cleanup, act } from "@testing-library/react";
import { ConfirmDialog } from "../ConfirmDialog";
afterEach(() => {
cleanup();
});
+describe("ConfirmDialog — WCAG dialog accessibility", () => {
+ it("dialog has role=dialog and aria-modal=true", () => {
+ render(
+
+ );
+ const dialog = screen.getByRole("dialog");
+ expect(dialog).toBeTruthy();
+ expect(dialog.getAttribute("aria-modal")).toBe("true");
+ });
+
+ it("dialog has aria-labelledby pointing to the title", () => {
+ render(
+
+ );
+ const dialog = screen.getByRole("dialog");
+ const labelledBy = dialog.getAttribute("aria-labelledby");
+ expect(labelledBy).toBeTruthy();
+ const titleEl = document.getElementById(labelledBy!);
+ expect(titleEl?.textContent?.trim()).toBe("Delete workspace");
+ });
+
+ it("Escape key invokes onCancel", () => {
+ const onCancel = vi.fn();
+ render(
+
+ );
+ fireEvent.keyDown(window, { key: "Escape" });
+ expect(onCancel).toHaveBeenCalledTimes(1);
+ });
+
+ it("Enter key invokes onConfirm", () => {
+ const onConfirm = vi.fn();
+ render(
+
+ );
+ fireEvent.keyDown(window, { key: "Enter" });
+ expect(onConfirm).toHaveBeenCalledTimes(1);
+ });
+
+ it("moves focus to the first button when dialog opens (WCAG 2.4.3)", async () => {
+ const onConfirm = vi.fn();
+ render(
+
+ );
+ // Flush requestAnimationFrame so ConfirmDialog's internal rAF focus fires
+ await act(async () => {
+ await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
+ });
+ const firstButton = screen.getAllByRole("button")[0];
+ expect(document.activeElement).toBe(firstButton);
+ });
+});
+
+describe("ConfirmDialog — backdrop", () => {
+ it("backdrop click invokes onCancel", () => {
+ const onCancel = vi.fn();
+ render(
+
+ );
+ const backdrop = document.querySelector('[aria-label="Dismiss dialog"]') as HTMLElement;
+ expect(backdrop).toBeTruthy();
+ fireEvent.click(backdrop);
+ expect(onCancel).toHaveBeenCalledTimes(1);
+ });
+});
+
describe("ConfirmDialog singleButton prop", () => {
it("renders Cancel button by default", () => {
render(