Fix tests to wrap all calls changing the UI with act. (#12268)

This commit is contained in:
Jacob Richman
2025-10-30 11:50:26 -07:00
committed by GitHub
parent cc081337b7
commit 54fa26ef0e
69 changed files with 2002 additions and 1291 deletions

View File

@@ -7,6 +7,7 @@
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { act } from 'react';
import { renderHook } from '../../test-utils/render.js';
import { waitFor } from '../../test-utils/async.js';
import { useShellHistory } from './useShellHistory.js';
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
@@ -96,9 +97,11 @@ describe('useShellHistory', () => {
it('should initialize and read the history file from the correct path', async () => {
mockedFs.readFile.mockResolvedValue('cmd1\ncmd2');
const { result } = renderHook(() => useShellHistory(MOCKED_PROJECT_ROOT));
const { result, unmount } = renderHook(() =>
useShellHistory(MOCKED_PROJECT_ROOT),
);
await vi.waitFor(() => {
await waitFor(() => {
expect(mockedFs.readFile).toHaveBeenCalledWith(
MOCKED_HISTORY_FILE,
'utf-8',
@@ -112,6 +115,8 @@ describe('useShellHistory', () => {
// History is loaded newest-first: ['cmd2', 'cmd1']
expect(command).toBe('cmd2');
unmount();
});
it('should handle a nonexistent history file gracefully', async () => {
@@ -119,9 +124,11 @@ describe('useShellHistory', () => {
error.code = 'ENOENT';
mockedFs.readFile.mockRejectedValue(error);
const { result } = renderHook(() => useShellHistory(MOCKED_PROJECT_ROOT));
const { result, unmount } = renderHook(() =>
useShellHistory(MOCKED_PROJECT_ROOT),
);
await vi.waitFor(() => {
await waitFor(() => {
expect(mockedFs.readFile).toHaveBeenCalled();
});
@@ -131,12 +138,16 @@ describe('useShellHistory', () => {
});
expect(command).toBe(null);
unmount();
});
it('should add a command and write to the history file', async () => {
const { result } = renderHook(() => useShellHistory(MOCKED_PROJECT_ROOT));
const { result, unmount } = renderHook(() =>
useShellHistory(MOCKED_PROJECT_ROOT),
);
await vi.waitFor(() => {
await waitFor(() => {
expect(mockedFs.readFile).toHaveBeenCalled();
});
@@ -144,7 +155,7 @@ describe('useShellHistory', () => {
result.current.addCommandToHistory('new_command');
});
await vi.waitFor(() => {
await waitFor(() => {
expect(mockedFs.mkdir).toHaveBeenCalledWith(MOCKED_HISTORY_DIR, {
recursive: true,
});
@@ -159,14 +170,18 @@ describe('useShellHistory', () => {
command = result.current.getPreviousCommand();
});
expect(command).toBe('new_command');
unmount();
});
it('should navigate history correctly with previous/next commands', async () => {
mockedFs.readFile.mockResolvedValue('cmd1\ncmd2\ncmd3');
const { result } = renderHook(() => useShellHistory(MOCKED_PROJECT_ROOT));
const { result, unmount } = renderHook(() =>
useShellHistory(MOCKED_PROJECT_ROOT),
);
// Wait for history to be loaded: ['cmd3', 'cmd2', 'cmd1']
await vi.waitFor(() => {
await waitFor(() => {
expect(mockedFs.readFile).toHaveBeenCalled();
});
@@ -208,12 +223,16 @@ describe('useShellHistory', () => {
command = result.current.getNextCommand();
});
expect(command).toBe('');
unmount();
});
it('should not add empty or whitespace-only commands to history', async () => {
const { result } = renderHook(() => useShellHistory(MOCKED_PROJECT_ROOT));
const { result, unmount } = renderHook(() =>
useShellHistory(MOCKED_PROJECT_ROOT),
);
await vi.waitFor(() => {
await waitFor(() => {
expect(mockedFs.readFile).toHaveBeenCalled();
});
@@ -222,14 +241,18 @@ describe('useShellHistory', () => {
});
expect(mockedFs.writeFile).not.toHaveBeenCalled();
unmount();
});
it('should truncate history to MAX_HISTORY_LENGTH (100)', async () => {
const oldCommands = Array.from({ length: 120 }, (_, i) => `old_cmd_${i}`);
mockedFs.readFile.mockResolvedValue(oldCommands.join('\n'));
const { result } = renderHook(() => useShellHistory(MOCKED_PROJECT_ROOT));
await vi.waitFor(() => {
const { result, unmount } = renderHook(() =>
useShellHistory(MOCKED_PROJECT_ROOT),
);
await waitFor(() => {
expect(mockedFs.readFile).toHaveBeenCalled();
});
@@ -238,7 +261,7 @@ describe('useShellHistory', () => {
});
// Wait for the async write to happen and then inspect the arguments.
await vi.waitFor(() => {
await waitFor(() => {
expect(mockedFs.writeFile).toHaveBeenCalled();
});
@@ -252,14 +275,18 @@ describe('useShellHistory', () => {
expect(writtenLines.length).toBe(100);
expect(writtenLines[0]).toBe('old_cmd_21'); // New oldest command
expect(writtenLines[99]).toBe('new_cmd'); // Newest command
unmount();
});
it('should move an existing command to the top when re-added', async () => {
mockedFs.readFile.mockResolvedValue('cmd1\ncmd2\ncmd3');
const { result } = renderHook(() => useShellHistory(MOCKED_PROJECT_ROOT));
const { result, unmount } = renderHook(() =>
useShellHistory(MOCKED_PROJECT_ROOT),
);
// Initial state: ['cmd3', 'cmd2', 'cmd1']
await vi.waitFor(() => {
await waitFor(() => {
expect(mockedFs.readFile).toHaveBeenCalled();
});
@@ -270,7 +297,7 @@ describe('useShellHistory', () => {
// After re-adding 'cmd1': ['cmd1', 'cmd3', 'cmd2']
expect(mockedFs.readFile).toHaveBeenCalled();
await vi.waitFor(() => {
await waitFor(() => {
expect(mockedFs.writeFile).toHaveBeenCalled();
});
@@ -278,5 +305,7 @@ describe('useShellHistory', () => {
const writtenLines = writtenContent.split('\n');
expect(writtenLines).toEqual(['cmd2', 'cmd3', 'cmd1']);
unmount();
});
});