Files
moneyfy/frontend/src/hooks/usePageShortcuts.test.tsx
T
Jonas MenzelandClaude Opus 5 ba02e17776
CI / backend (push) Successful in 2m2s
CI / frontend (push) Canceled after 2m41s
Images bauen / build (backend) (push) Successful in 3m54s
Images bauen / build (frontend) (push) Successful in 4m32s
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
2026-09-09 21:58:20 +02:00

109 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** 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());
});
});