From d9c883675d2f5836342fbc61615cbe7144fac0a4 Mon Sep 17 00:00:00 2001 From: Suzumiya Date: Wed, 9 Sep 2026 13:03:46 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85AGC=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E5=BC=82=E5=B8=B8revision=E7=9A=84=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 补充旧服务端不返回 revision(两次响应均为 undefined)时仍按目录变化刷新的用例 - 补充服务端目录重建导致 revision 回退(7 到 0)时仍更新界面的用例 - 补充 revision 未变化时不更新界面、沿用已应用目录的用例 --- .../tests/conversationModelSelect.test.tsx | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx b/apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx index 27f8b7c1a..25b1372f8 100644 --- a/apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx +++ b/apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx @@ -400,3 +400,73 @@ test('reuses a single in-flight catalog request', async () => { await waitFor(() => expect(loadClientLlmModels).toHaveBeenCalledTimes(2)); expect(loadClientLlmModels).toHaveBeenCalledTimes(2); }); + +test('keeps refreshing when the server omits the catalog revision', async () => { + vi.mocked(loadClientLlmModels).mockResolvedValue({ + defaultModelId: 'quality', + models: [ + { id: 'quality', displayName: '高质量' }, + { id: 'fast', displayName: '快速' }, + ], + revision: undefined as unknown as number, + }); + const onReady = vi.fn(); + render(); + await waitFor(() => expect(onReady).toHaveBeenLastCalledWith(true)); + + // 旧服务端不返回 revision 时,两次响应的 revision 都是 undefined, + // 不能因此判定「未变化」而停止刷新。 + vi.mocked(loadClientLlmModels).mockResolvedValue({ + defaultModelId: 'quality', + models: [ + { id: 'quality', displayName: '高质量' }, + { id: 'vision', displayName: '视觉' }, + ], + revision: undefined as unknown as number, + }); + fireEvent(window, new Event('focus')); + await waitFor(() => expect(loadClientLlmModels).toHaveBeenCalledTimes(2)); + fireEvent.click(screen.getByRole('button', { name: '对话模型' })); + expect(await screen.findByRole('option', { name: '视觉' })).not.toBeNull(); +}); + +test('applies a catalog when the revision goes backwards', async () => { + const onReady = vi.fn(); + render(); + await waitFor(() => expect(onReady).toHaveBeenLastCalledWith(true)); + + // 服务端目录重建后 revision 可能回退,仍要按「已变化」处理。 + vi.mocked(loadClientLlmModels).mockResolvedValue({ + defaultModelId: 'quality', + models: [ + { id: 'quality', displayName: '高质量' }, + { id: 'vision', displayName: '视觉' }, + ], + revision: 0, + }); + fireEvent(window, new Event('focus')); + await waitFor(() => expect(loadClientLlmModels).toHaveBeenCalledTimes(2)); + fireEvent.click(screen.getByRole('button', { name: '对话模型' })); + expect(await screen.findByRole('option', { name: '视觉' })).not.toBeNull(); +}); + +test('keeps the applied catalog when the revision is unchanged', async () => { + const onReady = vi.fn(); + render(); + await waitFor(() => expect(onReady).toHaveBeenLastCalledWith(true)); + + // revision 未变化时不更新界面,沿用已应用的目录。 + vi.mocked(loadClientLlmModels).mockResolvedValue({ + defaultModelId: 'quality', + models: [ + { id: 'quality', displayName: '高质量' }, + { id: 'vision', displayName: '视觉' }, + ], + revision: 1, + }); + fireEvent(window, new Event('focus')); + await waitFor(() => expect(loadClientLlmModels).toHaveBeenCalledTimes(2)); + fireEvent.click(screen.getByRole('button', { name: '对话模型' })); + expect(screen.queryByRole('option', { name: '视觉' })).toBeNull(); + expect(screen.getByRole('option', { name: '快速' })).not.toBeNull(); +});