TUI is a doomed path. Stick with CLI
This commit is contained in:
265
tests/tui/hooks/usePerformanceOptimization.test.js
Normal file
265
tests/tui/hooks/usePerformanceOptimization.test.js
Normal file
@@ -0,0 +1,265 @@
|
||||
const React = require("react");
|
||||
const { renderHook, act } = require("@testing-library/react");
|
||||
const {
|
||||
usePerformanceOptimization,
|
||||
useVirtualScrolling,
|
||||
useLazyLoading,
|
||||
useDebouncedSearch,
|
||||
} = require("../../../src/tui/hooks/usePerformanceOptimization.js");
|
||||
|
||||
// Mock timers for testing
|
||||
jest.useFakeTimers();
|
||||
|
||||
describe("usePerformanceOptimization", () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllTimers();
|
||||
});
|
||||
|
||||
it("should provide performance optimization functions", () => {
|
||||
const { result } = renderHook(() =>
|
||||
usePerformanceOptimization("test-component")
|
||||
);
|
||||
|
||||
expect(result.current).toHaveProperty("createDebouncedFunction");
|
||||
expect(result.current).toHaveProperty("createThrottledFunction");
|
||||
expect(result.current).toHaveProperty("createMemoizedFunction");
|
||||
expect(result.current).toHaveProperty("createVirtualScrolling");
|
||||
expect(result.current).toHaveProperty("createLazyLoading");
|
||||
expect(result.current).toHaveProperty("registerEventListener");
|
||||
expect(result.current).toHaveProperty("optimizeRender");
|
||||
expect(result.current).toHaveProperty("createBatchedUpdate");
|
||||
expect(result.current).toHaveProperty("forceCleanup");
|
||||
});
|
||||
|
||||
it("should create debounced functions", () => {
|
||||
const { result } = renderHook(() =>
|
||||
usePerformanceOptimization("test-component")
|
||||
);
|
||||
|
||||
let callCount = 0;
|
||||
const testFunction = () => {
|
||||
callCount++;
|
||||
};
|
||||
|
||||
act(() => {
|
||||
const debouncedFn = result.current.createDebouncedFunction(
|
||||
testFunction,
|
||||
100
|
||||
);
|
||||
debouncedFn();
|
||||
debouncedFn();
|
||||
debouncedFn();
|
||||
});
|
||||
|
||||
expect(callCount).toBe(0);
|
||||
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(150);
|
||||
});
|
||||
|
||||
expect(callCount).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("useVirtualScrolling", () => {
|
||||
it("should provide virtual scrolling data", () => {
|
||||
const items = Array.from({ length: 100 }, (_, i) => ({
|
||||
id: i,
|
||||
name: `Item ${i}`,
|
||||
}));
|
||||
const options = { itemHeight: 30, containerHeight: 300 };
|
||||
|
||||
const { result } = renderHook(() => useVirtualScrolling(items, options));
|
||||
|
||||
expect(result.current).toHaveProperty("visibleItems");
|
||||
expect(result.current).toHaveProperty("totalHeight");
|
||||
expect(result.current).toHaveProperty("startIndex");
|
||||
expect(result.current).toHaveProperty("endIndex");
|
||||
expect(result.current).toHaveProperty("handleScroll");
|
||||
expect(result.current.totalHeight).toBe(3000); // 100 * 30
|
||||
});
|
||||
|
||||
it("should handle scroll updates", () => {
|
||||
const items = Array.from({ length: 100 }, (_, i) => ({
|
||||
id: i,
|
||||
name: `Item ${i}`,
|
||||
}));
|
||||
const options = { itemHeight: 30, containerHeight: 300 };
|
||||
|
||||
const { result } = renderHook(() => useVirtualScrolling(items, options));
|
||||
|
||||
act(() => {
|
||||
result.current.handleScroll(150);
|
||||
});
|
||||
|
||||
expect(result.current.scrollTop).toBe(150);
|
||||
expect(result.current.startIndex).toBe(5); // 150 / 30
|
||||
});
|
||||
});
|
||||
|
||||
describe("useLazyLoading", () => {
|
||||
it("should load data lazily", async () => {
|
||||
const mockLoadFunction = jest.fn().mockResolvedValue({
|
||||
items: [
|
||||
{ id: 1, name: "Item 1" },
|
||||
{ id: 2, name: "Item 2" },
|
||||
],
|
||||
hasMore: true,
|
||||
});
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useLazyLoading(mockLoadFunction, { pageSize: 2 })
|
||||
);
|
||||
|
||||
// Initial state
|
||||
expect(result.current.loading).toBe(true);
|
||||
expect(result.current.items).toEqual([]);
|
||||
|
||||
// Wait for initial load
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(result.current.loading).toBe(false);
|
||||
expect(result.current.items).toHaveLength(2);
|
||||
expect(result.current.hasMore).toBe(true);
|
||||
expect(mockLoadFunction).toHaveBeenCalledWith({
|
||||
page: 0,
|
||||
pageSize: 2,
|
||||
offset: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it("should load more data", async () => {
|
||||
const mockLoadFunction = jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce({
|
||||
items: [{ id: 1, name: "Item 1" }],
|
||||
hasMore: true,
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
items: [{ id: 2, name: "Item 2" }],
|
||||
hasMore: false,
|
||||
});
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useLazyLoading(mockLoadFunction, { pageSize: 1, enablePreloading: false })
|
||||
);
|
||||
|
||||
// Wait for initial load
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(result.current.items).toHaveLength(1);
|
||||
|
||||
// Load more
|
||||
act(() => {
|
||||
result.current.loadMore();
|
||||
});
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(result.current.items).toHaveLength(2);
|
||||
expect(result.current.hasMore).toBe(false);
|
||||
});
|
||||
|
||||
it("should handle reload", async () => {
|
||||
const mockLoadFunction = jest.fn().mockResolvedValue({
|
||||
items: [{ id: 1, name: "Item 1" }],
|
||||
hasMore: false,
|
||||
});
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useLazyLoading(mockLoadFunction)
|
||||
);
|
||||
|
||||
// Wait for initial load
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(mockLoadFunction).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Reload
|
||||
act(() => {
|
||||
result.current.reload();
|
||||
});
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(mockLoadFunction).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("useDebouncedSearch", () => {
|
||||
it("should debounce search queries", async () => {
|
||||
const mockSearchFunction = jest
|
||||
.fn()
|
||||
.mockResolvedValue([{ id: 1, name: "Test Result" }]);
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useDebouncedSearch(mockSearchFunction, 100)
|
||||
);
|
||||
|
||||
// Update query multiple times rapidly
|
||||
act(() => {
|
||||
result.current.updateQuery("t");
|
||||
result.current.updateQuery("te");
|
||||
result.current.updateQuery("tes");
|
||||
result.current.updateQuery("test");
|
||||
});
|
||||
|
||||
expect(result.current.query).toBe("test");
|
||||
expect(result.current.loading).toBe(false); // Should not be loading yet due to debounce
|
||||
|
||||
// Advance timers to trigger debounced search
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(150);
|
||||
});
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(mockSearchFunction).toHaveBeenCalledTimes(1);
|
||||
expect(mockSearchFunction).toHaveBeenCalledWith("test");
|
||||
expect(result.current.results).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("should clear search", () => {
|
||||
const mockSearchFunction = jest.fn().mockResolvedValue([]);
|
||||
|
||||
const { result } = renderHook(() => useDebouncedSearch(mockSearchFunction));
|
||||
|
||||
act(() => {
|
||||
result.current.updateQuery("test");
|
||||
});
|
||||
|
||||
expect(result.current.query).toBe("test");
|
||||
|
||||
act(() => {
|
||||
result.current.clearSearch();
|
||||
});
|
||||
|
||||
expect(result.current.query).toBe("");
|
||||
expect(result.current.results).toEqual([]);
|
||||
});
|
||||
|
||||
it("should handle empty queries", async () => {
|
||||
const mockSearchFunction = jest.fn().mockResolvedValue([]);
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useLazyLoading(() =>
|
||||
Promise.resolve({ items: [{ id: 1 }], hasMore: false })
|
||||
)
|
||||
);
|
||||
|
||||
const { result: searchResult } = renderHook(() =>
|
||||
useDebouncedSearch(mockSearchFunction)
|
||||
);
|
||||
|
||||
act(() => {
|
||||
searchResult.current.updateQuery(" "); // Whitespace only
|
||||
});
|
||||
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(150);
|
||||
});
|
||||
|
||||
expect(mockSearchFunction).not.toHaveBeenCalled();
|
||||
expect(searchResult.current.results).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user