Files
MyGoNavi/frontend/src/components/ai/useAIChatRuntimeResources.test.tsx
2026-06-22 15:12:42 +08:00

117 lines
3.1 KiB
TypeScript

import { readFileSync } from 'node:fs';
import React from 'react';
import { act, create, type ReactTestRenderer } from 'react-test-renderer';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { useAIChatRuntimeResources } from './useAIChatRuntimeResources';
const source = readFileSync(new URL('./useAIChatRuntimeResources.ts', import.meta.url), 'utf8');
const runtimeService = vi.hoisted(() => ({
AIListModels: vi.fn(),
}));
const windowStub = vi.hoisted(() => ({
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
setTimeout,
}));
let latestHook: ReturnType<typeof useAIChatRuntimeResources> | undefined;
const flushAsyncWork = async () => {
await act(async () => {
await Promise.resolve();
await Promise.resolve();
});
};
const Harness = () => {
latestHook = useAIChatRuntimeResources({});
return null;
};
describe('useAIChatRuntimeResources', () => {
let consoleWarnSpy: ReturnType<typeof vi.spyOn>;
beforeEach(() => {
vi.clearAllMocks();
latestHook = undefined;
consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
vi.stubGlobal('window', {
...windowStub,
go: {
aiservice: {
Service: runtimeService,
},
},
});
});
afterEach(() => {
consoleWarnSpy.mockRestore();
vi.unstubAllGlobals();
});
it('keeps the model-fetch failure path free of legacy Chinese wrapper copy', () => {
expect(source).not.toContain('获取模型列表失败:');
expect(source).not.toContain("'未知错误'");
});
it('uses English notice chrome for thrown model load failures while preserving raw detail', async () => {
runtimeService.AIListModels.mockRejectedValue(new Error('HTTP 401 raw error'));
let renderer: ReactTestRenderer;
await act(async () => {
renderer = create(<Harness />);
});
await flushAsyncWork();
await act(async () => {
await latestHook!.fetchDynamicModels();
});
await flushAsyncWork();
expect(latestHook!.composerNotice).toEqual({
tone: 'error',
title: 'Model list failed to load',
description: 'HTTP 401 raw error',
action: {
key: 'reload-models',
label: 'Reload models',
},
});
await act(async () => {
renderer!.unmount();
});
});
it('uses the default English description when the thrown model load error has no message', async () => {
runtimeService.AIListModels.mockRejectedValue({});
let renderer: ReactTestRenderer;
await act(async () => {
renderer = create(<Harness />);
});
await flushAsyncWork();
await act(async () => {
await latestHook!.fetchDynamicModels();
});
await flushAsyncWork();
expect(latestHook!.composerNotice).toEqual({
tone: 'error',
title: 'Model list failed to load',
description: 'Check the provider endpoint, API Key, or account permissions, then reopen the model dropdown.',
action: {
key: 'reload-models',
label: 'Reload models',
},
});
await act(async () => {
renderer!.unmount();
});
});
});