fix: address issue #24279

This commit is contained in:
RoyVivat 2026-03-21 14:15:31 -07:00
parent 50f88c8642
commit 55b27265ea
2 changed files with 177 additions and 4 deletions

View file

@ -0,0 +1,173 @@
import { renderHook } from "@testing-library/react";
import { act } from "react";
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { useKeyboardNavigation } from "./useKeyboardNavigation";
import { LogEntry } from "../columns";
function makeLog(request_id: string): LogEntry {
return {
request_id,
api_key: "key",
team_id: "team",
model: "gpt-4",
model_id: "model-id",
call_type: "completion",
spend: 0,
total_tokens: 0,
prompt_tokens: 0,
completion_tokens: 0,
startTime: "2024-01-01T00:00:00Z",
endTime: "2024-01-01T00:00:01Z",
cache_hit: "False",
messages: [],
response: "",
};
}
const logA = makeLog("log-a");
const logB = makeLog("log-b");
const logC = makeLog("log-c");
const allLogs = [logA, logB, logC];
describe("useKeyboardNavigation", () => {
let onClose: ReturnType<typeof vi.fn>;
let onSelectLog: ReturnType<typeof vi.fn>;
beforeEach(() => {
onClose = vi.fn();
onSelectLog = vi.fn();
});
afterEach(() => {
vi.clearAllMocks();
});
const fireKey = (key: string) => {
act(() => {
window.dispatchEvent(new KeyboardEvent("keydown", { key, bubbles: true }));
});
};
it("J key calls selectNextLog (moves to next/down in list)", () => {
renderHook(() =>
useKeyboardNavigation({
isOpen: true,
currentLog: logA,
allLogs,
onClose,
onSelectLog,
})
);
fireKey("j");
expect(onSelectLog).toHaveBeenCalledWith(logB);
});
it("J (uppercase) key calls selectNextLog", () => {
renderHook(() =>
useKeyboardNavigation({
isOpen: true,
currentLog: logA,
allLogs,
onClose,
onSelectLog,
})
);
fireKey("J");
expect(onSelectLog).toHaveBeenCalledWith(logB);
});
it("K key calls selectPreviousLog (moves to previous/up in list)", () => {
renderHook(() =>
useKeyboardNavigation({
isOpen: true,
currentLog: logB,
allLogs,
onClose,
onSelectLog,
})
);
fireKey("k");
expect(onSelectLog).toHaveBeenCalledWith(logA);
});
it("K (uppercase) key calls selectPreviousLog", () => {
renderHook(() =>
useKeyboardNavigation({
isOpen: true,
currentLog: logB,
allLogs,
onClose,
onSelectLog,
})
);
fireKey("K");
expect(onSelectLog).toHaveBeenCalledWith(logA);
});
it("J key does not go past the last log", () => {
renderHook(() =>
useKeyboardNavigation({
isOpen: true,
currentLog: logC,
allLogs,
onClose,
onSelectLog,
})
);
fireKey("j");
expect(onSelectLog).not.toHaveBeenCalled();
});
it("K key does not go before the first log", () => {
renderHook(() =>
useKeyboardNavigation({
isOpen: true,
currentLog: logA,
allLogs,
onClose,
onSelectLog,
})
);
fireKey("k");
expect(onSelectLog).not.toHaveBeenCalled();
});
it("Escape key calls onClose", () => {
renderHook(() =>
useKeyboardNavigation({
isOpen: true,
currentLog: logA,
allLogs,
onClose,
onSelectLog,
})
);
fireKey("Escape");
expect(onClose).toHaveBeenCalled();
});
it("keys do nothing when drawer is closed", () => {
renderHook(() =>
useKeyboardNavigation({
isOpen: false,
currentLog: logA,
allLogs,
onClose,
onSelectLog,
})
);
fireKey("j");
fireKey("k");
fireKey("Escape");
expect(onSelectLog).not.toHaveBeenCalled();
expect(onClose).not.toHaveBeenCalled();
});
});

View file

@ -15,8 +15,8 @@ interface UseKeyboardNavigationProps {
* Handles J/K for next/previous and Escape for close.
*
* Keyboard shortcuts:
* - J: Navigate to previous log (up)
* - K: Navigate to next log (down)
* - J: Navigate to next log (down)
* - K: Navigate to previous log (up)
* - Escape: Close drawer
*/
export function useKeyboardNavigation({
@ -41,11 +41,11 @@ export function useKeyboardNavigation({
break;
case KEY_J_LOWER:
case KEY_J_UPPER:
selectPreviousLog();
selectNextLog();
break;
case KEY_K_LOWER:
case KEY_K_UPPER:
selectNextLog();
selectPreviousLog();
break;
}
};