feat(frontend): wire KeyboardCheatsheet into Claims page via ? toggle
This commit is contained in:
@@ -326,4 +326,98 @@ describe("Claims page drawer wiring", () => {
|
||||
await settle(() => !window.location.href.includes("?claim="));
|
||||
expect(window.location.href).not.toContain("?claim=");
|
||||
});
|
||||
|
||||
it("test_question_mark_toggles_cheatsheet", async () => {
|
||||
// The cheatsheet keystroke is wired through `useDrawerKeyboard`
|
||||
// (which lives inside ClaimDrawer and only enables when
|
||||
// `claimId !== null`). Deep-link with `?claim=CLM-1` so the
|
||||
// drawer mounts and the keyboard listener is active.
|
||||
setLocation("http://localhost/claims?claim=CLM-1");
|
||||
const { unmount } = renderClaims();
|
||||
|
||||
// Drawer must be open before we test the toggle.
|
||||
await settle(
|
||||
() => document.body.querySelector('[data-testid="claim-drawer"]') !== null
|
||||
);
|
||||
expect(
|
||||
document.body.querySelector('[data-testid="claim-drawer"]')
|
||||
).not.toBeNull();
|
||||
|
||||
// Cheatsheet starts closed.
|
||||
expect(
|
||||
document.body.querySelector('[data-testid="keyboard-cheatsheet"]')
|
||||
).toBeNull();
|
||||
|
||||
// First `?` press: useDrawerKeyboard's handler flips `helpOpen`
|
||||
// true on the page; the cheatsheet portals into document.body.
|
||||
await act(async () => {
|
||||
window.dispatchEvent(
|
||||
new KeyboardEvent("keydown", { key: "?", bubbles: true })
|
||||
);
|
||||
});
|
||||
await settle(
|
||||
() =>
|
||||
document.body.querySelector('[data-testid="keyboard-cheatsheet"]') !==
|
||||
null
|
||||
);
|
||||
expect(
|
||||
document.body.querySelector('[data-testid="keyboard-cheatsheet"]')
|
||||
).not.toBeNull();
|
||||
|
||||
// Second `?` press: same handler flips `helpOpen` back to false;
|
||||
// the cheatsheet unmounts. (The cheatsheet's own window-level
|
||||
// listener explicitly returns early on `?` — it never pre-empts
|
||||
// the parent's toggle, by design.)
|
||||
await act(async () => {
|
||||
window.dispatchEvent(
|
||||
new KeyboardEvent("keydown", { key: "?", bubbles: true })
|
||||
);
|
||||
});
|
||||
await settle(
|
||||
() =>
|
||||
document.body.querySelector('[data-testid="keyboard-cheatsheet"]') ===
|
||||
null
|
||||
);
|
||||
expect(
|
||||
document.body.querySelector('[data-testid="keyboard-cheatsheet"]')
|
||||
).toBeNull();
|
||||
|
||||
// Unmount so the next test (which asserts the drawer is absent)
|
||||
// doesn't see this test's still-open drawer leaking into
|
||||
// document.body.
|
||||
unmount();
|
||||
});
|
||||
|
||||
it("test_question_mark_does_nothing_when_drawer_closed", async () => {
|
||||
// The `?` keystroke is owned by `useDrawerKeyboard`, which only
|
||||
// attaches its `window` listener when `claimId !== null`. With no
|
||||
// `?claim=` in the URL, the drawer is closed and `?` is a no-op
|
||||
// — the cheatsheet must not appear.
|
||||
setLocation("http://localhost/claims");
|
||||
renderClaims();
|
||||
|
||||
// Wait for the table to populate (so the page is fully mounted).
|
||||
await settle(
|
||||
() => document.body.textContent?.includes("CLM-1") ?? false
|
||||
);
|
||||
expect(
|
||||
document.body.querySelector('[data-testid="claim-drawer"]')
|
||||
).toBeNull();
|
||||
|
||||
await act(async () => {
|
||||
window.dispatchEvent(
|
||||
new KeyboardEvent("keydown", { key: "?", bubbles: true })
|
||||
);
|
||||
});
|
||||
|
||||
// No cheatsheet should be present — and not just "not yet":
|
||||
// flush a tick to make sure a delayed listener couldn't have
|
||||
// snuck it in.
|
||||
await act(async () => {
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
});
|
||||
expect(
|
||||
document.body.querySelector('[data-testid="keyboard-cheatsheet"]')
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
import { StatusBadge } from "@/components/StatusBadge";
|
||||
import { NewClaimDialog } from "@/components/NewClaimDialog";
|
||||
import { ClaimDrawer } from "@/components/ClaimDrawer";
|
||||
import { KeyboardCheatsheet } from "@/components/KeyboardCheatsheet";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { EmptyState } from "@/components/ui/empty-state";
|
||||
import { ErrorState } from "@/components/ui/error-state";
|
||||
@@ -48,6 +49,7 @@ export function Claims() {
|
||||
const [npi, setNpi] = useState<string>(ALL);
|
||||
const [query, setQuery] = useState("");
|
||||
const [page, setPage] = useState(1);
|
||||
const [helpOpen, setHelpOpen] = useState(false);
|
||||
const searchRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
// SP4 drawer wiring: the URL is the source of truth for "which claim is
|
||||
@@ -114,9 +116,11 @@ export function Claims() {
|
||||
claims={items.map((c) => ({ id: c.id }))}
|
||||
onClose={close}
|
||||
onNavigate={setClaimId}
|
||||
onToggleHelp={() => {
|
||||
// T22 wires the KeyboardCheatsheet overlay; no-op for now.
|
||||
}}
|
||||
onToggleHelp={() => setHelpOpen((v) => !v)}
|
||||
/>
|
||||
<KeyboardCheatsheet
|
||||
open={helpOpen}
|
||||
onClose={() => setHelpOpen(false)}
|
||||
/>
|
||||
<div
|
||||
data-testid="claims-page-body"
|
||||
|
||||
Reference in New Issue
Block a user