Files
Multi-Debrid-Downloader/tests/dialog.test.tsx
Sucukdeluxe 069babfd54 feat: deliver the redesigned desktop workspace
Rebuild downloads, link collection, settings, history, and statistics around a responsive desktop shell with compact account and queue tables, contextual navigation, persistent update affordances, unified overlays, and accessible keyboard interactions.

Add safe history-folder reveal IPC, responsive 2560/1920/1366/1120 coverage, deterministic visual fixtures, focused component regressions, and release-tree exclusions for internal working files. Bump the public application version to 2.0.13.
2026-08-10 14:15:57 +02:00

89 lines
4.1 KiB
TypeScript

import { createRef } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { describe, expect, it } from "vitest";
import {
Dialog,
getConnectedDialogRestoreTarget,
getDialogInitialFocusTarget,
getDialogKeyboardAction,
getDialogRestoreFocusTarget
} from "../src/renderer/ui/Dialog";
describe("Dialog", () => {
it("renders labelled modal semantics only while open", () => {
const closed = renderToStaticMarkup(
<Dialog actions={null} onClose={() => {}} open={false} title="Test">Body</Dialog>
);
const open = renderToStaticMarkup(
<Dialog actions={<button>OK</button>} description="Beschreibung" onClose={() => {}} open title="Test">Body</Dialog>
);
expect(closed).toBe("");
expect(open).toContain("role=\"dialog\"");
expect(open).toContain("aria-modal=\"true\"");
expect(open).toMatch(/aria-labelledby=\"[^\"]+\"/);
expect(open).toMatch(/aria-describedby=\"[^\"]+\"/);
expect(open).toContain("Beschreibung");
expect(open).toContain("Body");
expect(open).toContain("OK");
});
it("applies bounded account and update surfaces without changing the dialog contract", () => {
const account = renderToStaticMarkup(
<Dialog actions={null} initialFocusRef={createRef<HTMLButtonElement>()} onClose={() => {}} open size="account" title="Account">Body</Dialog>
);
const update = renderToStaticMarkup(
<Dialog actions={null} danger onClose={() => {}} open size="update" title="Update">Body</Dialog>
);
expect(account).toContain("md-dialog-size-account");
expect(update).toContain("md-dialog-size-update");
expect(update).toContain("is-danger");
});
it("traps forward and reverse tabbing and honors closable Escape", () => {
expect(getDialogKeyboardAction("Tab", false, -1, 4, true)).toEqual({ type: "focus", index: 0 });
expect(getDialogKeyboardAction("Tab", true, -1, 4, true)).toEqual({ type: "focus", index: 3 });
expect(getDialogKeyboardAction("Tab", false, 3, 4, true)).toEqual({ type: "focus", index: 0 });
expect(getDialogKeyboardAction("Tab", true, 0, 4, true)).toEqual({ type: "focus", index: 3 });
expect(getDialogKeyboardAction("Tab", false, 1, 4, true)).toBeNull();
expect(getDialogKeyboardAction("Escape", false, 0, 4, true)).toEqual({ type: "close" });
expect(getDialogKeyboardAction("Escape", false, 0, 4, false)).toBeNull();
});
it("keeps existing autofocus targets before falling back to the dialog surface", () => {
const explicitTarget = {} as HTMLElement;
const autofocusTarget = {} as HTMLElement;
const activeAutofocusTarget = {} as HTMLElement;
const dialog = {
contains: (target: HTMLElement) => target === activeAutofocusTarget,
querySelector: (selector: string) => selector === "[autofocus]" ? autofocusTarget : null
} as unknown as HTMLElement;
const fallbackDialog = { querySelector: () => null } as unknown as HTMLElement;
expect(getDialogInitialFocusTarget(dialog, explicitTarget)).toBe(explicitTarget);
expect(getDialogInitialFocusTarget(dialog, null, activeAutofocusTarget)).toBe(activeAutofocusTarget);
expect(getDialogInitialFocusTarget(dialog, null)).toBe(autofocusTarget);
expect(getDialogInitialFocusTarget(fallbackDialog, null)).toBe(fallbackDialog);
});
it("captures the opener before autofocus moves into the mounted dialog", () => {
const opener = { isConnected: true } as HTMLElement;
const dialogTarget = { isConnected: true } as HTMLElement;
const dialog = {
contains: (target: HTMLElement) => target === dialogTarget
} as unknown as HTMLElement;
expect(getDialogRestoreFocusTarget(dialog, opener)).toBe(opener);
expect(getDialogRestoreFocusTarget(dialog, dialogTarget)).toBeNull();
});
it("uses a stable caller fallback when a transient opener unmounts", () => {
const transientOpener = { isConnected: false } as HTMLElement;
const stableFallback = { isConnected: true } as HTMLElement;
expect(getConnectedDialogRestoreTarget(transientOpener, stableFallback)).toBe(stableFallback);
expect(getConnectedDialogRestoreTarget(stableFallback, null)).toBe(stableFallback);
});
});