test: Kürzel-Verdrahtung zwischen Layout und Seiten absichern
Sechs Tests für usePendingAction und useSearchFocus. Der Store wird vor dem Test zurückgesetzt statt danach – nach dem Test hängen die Komponenten noch am Store und React meldet ein Update außerhalb von act(). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014e7t8UpmoVNMtWivY5LiSH
This commit is contained in:
co-authored by
Claude Opus 5
parent
d63cc0af65
commit
ba02e17776
@@ -0,0 +1,108 @@
|
||||
/** Tests des Bindeglieds zwischen globalen Kürzeln und den Seiten. */
|
||||
|
||||
import { useRef } from "react";
|
||||
|
||||
import { act, render, screen, waitFor } from "@testing-library/react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { usePendingAction, useSearchFocus } from "@/hooks/usePageShortcuts";
|
||||
import { useUiStore } from "@/store/ui";
|
||||
|
||||
beforeEach(() => {
|
||||
// Der Store lebt global – sonst tropft eine Absicht in den nächsten Test.
|
||||
// Bewusst vor dem Test und nicht danach: nach dem Test hängen die Komponenten
|
||||
// noch am Store und React meldet ein Update außerhalb von act().
|
||||
useUiStore.setState({ pendingAction: null, searchFocusRequest: 0 });
|
||||
});
|
||||
|
||||
function Seite({ run }: { run: () => void }) {
|
||||
const suchfeld = useRef<HTMLInputElement>(null);
|
||||
usePendingAction("new-transaction", run);
|
||||
useSearchFocus(suchfeld);
|
||||
return <input ref={suchfeld} aria-label="Suche" defaultValue="Vorbelegung" />;
|
||||
}
|
||||
|
||||
describe("usePendingAction", () => {
|
||||
it("führt die Absicht aus, sobald sie hinterlegt wird", async () => {
|
||||
const oeffnen = vi.fn();
|
||||
render(<Seite run={oeffnen} />);
|
||||
|
||||
expect(oeffnen).not.toHaveBeenCalled();
|
||||
|
||||
await act(async () => {
|
||||
useUiStore.getState().requestAction("new-transaction");
|
||||
});
|
||||
|
||||
await waitFor(() => expect(oeffnen).toHaveBeenCalledOnce());
|
||||
// Die Absicht ist danach verbraucht.
|
||||
expect(useUiStore.getState().pendingAction).toBeNull();
|
||||
});
|
||||
|
||||
it("ignoriert eine Absicht, die einer anderen Seite gilt", async () => {
|
||||
const oeffnen = vi.fn();
|
||||
render(<Seite run={oeffnen} />);
|
||||
|
||||
await act(async () => {
|
||||
useUiStore.getState().requestAction("new-recurrence");
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(useUiStore.getState().pendingAction).toBe("new-recurrence");
|
||||
});
|
||||
expect(oeffnen).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("führt dieselbe Absicht nicht zweimal aus", async () => {
|
||||
const oeffnen = vi.fn();
|
||||
const { rerender } = render(<Seite run={oeffnen} />);
|
||||
|
||||
await act(async () => {
|
||||
useUiStore.getState().requestAction("new-transaction");
|
||||
});
|
||||
await waitFor(() => expect(oeffnen).toHaveBeenCalledOnce());
|
||||
|
||||
rerender(<Seite run={oeffnen} />);
|
||||
expect(oeffnen).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
|
||||
describe("useSearchFocus", () => {
|
||||
it("fokussiert und markiert das Suchfeld auf Anfrage", async () => {
|
||||
render(<Seite run={vi.fn()} />);
|
||||
const feld = screen.getByLabelText("Suche") as HTMLInputElement;
|
||||
|
||||
expect(feld).not.toHaveFocus();
|
||||
|
||||
await act(async () => {
|
||||
useUiStore.getState().requestSearchFocus();
|
||||
});
|
||||
|
||||
await waitFor(() => expect(feld).toHaveFocus());
|
||||
// Der vorhandene Text ist markiert, damit Tippen ihn ersetzt.
|
||||
expect(feld.selectionStart).toBe(0);
|
||||
expect(feld.selectionEnd).toBe("Vorbelegung".length);
|
||||
});
|
||||
|
||||
it("greift beim ersten Rendern noch nicht", () => {
|
||||
render(<Seite run={vi.fn()} />);
|
||||
|
||||
expect(screen.getByLabelText("Suche")).not.toHaveFocus();
|
||||
});
|
||||
|
||||
it("wirkt auch bei mehrfacher Anfrage", async () => {
|
||||
render(<Seite run={vi.fn()} />);
|
||||
const feld = screen.getByLabelText("Suche");
|
||||
|
||||
await act(async () => {
|
||||
useUiStore.getState().requestSearchFocus();
|
||||
});
|
||||
await waitFor(() => expect(feld).toHaveFocus());
|
||||
|
||||
await act(async () => feld.blur());
|
||||
await act(async () => {
|
||||
useUiStore.getState().requestSearchFocus();
|
||||
});
|
||||
|
||||
await waitFor(() => expect(feld).toHaveFocus());
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user