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

@@ -18,6 +18,7 @@ import { renderHook } from '../../test-utils/render.js';
import {
type Config,
type FallbackModelHandler,
type FallbackIntent,
UserTierId,
AuthType,
TerminalQuotaError,
@@ -186,10 +187,13 @@ describe('useQuotaAndFallback', () => {
} of testCases) {
it(`should handle ${description} correctly`, async () => {
const handler = getRegisteredHandler(tier);
const result = await handler('model-A', 'model-B', error);
let result: FallbackIntent | null;
await act(async () => {
result = await handler('model-A', 'model-B', error);
});
// Automatic fallbacks should return 'stop'
expect(result).toBe('stop');
expect(result!).toBe('stop');
expect(mockHistoryManager.addItem).toHaveBeenCalledWith(
expect.objectContaining({ type: MessageType.INFO }),
@@ -224,25 +228,26 @@ describe('useQuotaAndFallback', () => {
.calls[0][0] as FallbackModelHandler;
// Call the handler but do not await it, to check the intermediate state
const promise = handler(
'gemini-pro',
'gemini-flash',
new TerminalQuotaError('pro quota', mockGoogleApiError),
);
await act(async () => {});
let promise: Promise<FallbackIntent | null>;
await act(() => {
promise = handler(
'gemini-pro',
'gemini-flash',
new TerminalQuotaError('pro quota', mockGoogleApiError),
);
});
// The hook should now have a pending request for the UI to handle
expect(result.current.proQuotaRequest).not.toBeNull();
expect(result.current.proQuotaRequest?.failedModel).toBe('gemini-pro');
// Simulate the user choosing to continue with the fallback model
act(() => {
await act(() => {
result.current.handleProQuotaChoice('continue');
});
// The original promise from the handler should now resolve
const intent = await promise;
const intent = await promise!;
expect(intent).toBe('retry');
// The pending request should be cleared from the state
@@ -263,31 +268,36 @@ describe('useQuotaAndFallback', () => {
const handler = setFallbackHandlerSpy.mock
.calls[0][0] as FallbackModelHandler;
const promise1 = handler(
'gemini-pro',
'gemini-flash',
new TerminalQuotaError('pro quota 1', mockGoogleApiError),
);
await act(async () => {});
let promise1: Promise<FallbackIntent | null>;
await act(() => {
promise1 = handler(
'gemini-pro',
'gemini-flash',
new TerminalQuotaError('pro quota 1', mockGoogleApiError),
);
});
const firstRequest = result.current.proQuotaRequest;
expect(firstRequest).not.toBeNull();
const result2 = await handler(
'gemini-pro',
'gemini-flash',
new TerminalQuotaError('pro quota 2', mockGoogleApiError),
);
let result2: FallbackIntent | null;
await act(async () => {
result2 = await handler(
'gemini-pro',
'gemini-flash',
new TerminalQuotaError('pro quota 2', mockGoogleApiError),
);
});
// The lock should have stopped the second request
expect(result2).toBe('stop');
expect(result2!).toBe('stop');
expect(result.current.proQuotaRequest).toBe(firstRequest);
act(() => {
await act(() => {
result.current.handleProQuotaChoice('continue');
});
const intent1 = await promise1;
const intent1 = await promise1!;
expect(intent1).toBe('retry');
expect(result.current.proQuotaRequest).toBeNull();
});
@@ -327,18 +337,20 @@ describe('useQuotaAndFallback', () => {
const handler = setFallbackHandlerSpy.mock
.calls[0][0] as FallbackModelHandler;
const promise = handler(
'gemini-pro',
'gemini-flash',
new TerminalQuotaError('pro quota', mockGoogleApiError),
);
await act(async () => {}); // Allow state to update
let promise: Promise<FallbackIntent | null>;
await act(() => {
promise = handler(
'gemini-pro',
'gemini-flash',
new TerminalQuotaError('pro quota', mockGoogleApiError),
);
});
act(() => {
await act(() => {
result.current.handleProQuotaChoice('auth');
});
const intent = await promise;
const intent = await promise!;
expect(intent).toBe('auth');
expect(mockSetAuthState).toHaveBeenCalledWith(AuthState.Updating);
expect(result.current.proQuotaRequest).toBeNull();
@@ -358,18 +370,20 @@ describe('useQuotaAndFallback', () => {
const handler = setFallbackHandlerSpy.mock
.calls[0][0] as FallbackModelHandler;
// The first `addItem` call is for the initial quota error message
const promise = handler(
'gemini-pro',
'gemini-flash',
new TerminalQuotaError('pro quota', mockGoogleApiError),
);
await act(async () => {}); // Allow state to update
let promise: Promise<FallbackIntent | null>;
await act(() => {
promise = handler(
'gemini-pro',
'gemini-flash',
new TerminalQuotaError('pro quota', mockGoogleApiError),
);
});
act(() => {
await act(() => {
result.current.handleProQuotaChoice('continue');
});
const intent = await promise;
const intent = await promise!;
expect(intent).toBe('retry');
expect(result.current.proQuotaRequest).toBeNull();