119 lines
3.4 KiB
TypeScript
119 lines
3.4 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 AionUi (aionui.com)
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { BackendHttpError } from '@/common/adapter/httpBridge';
|
|
import { ipcBridge } from '@/common';
|
|
import type { TChatConversation } from '@/common/config/storage';
|
|
import { mutate } from 'swr';
|
|
import { getConversationOrNull, refreshConversationCache } from '@/renderer/pages/conversation/utils/conversationCache';
|
|
|
|
vi.mock('@/common', () => ({
|
|
ipcBridge: {
|
|
conversation: {
|
|
get: {
|
|
invoke: vi.fn(),
|
|
},
|
|
},
|
|
},
|
|
}));
|
|
|
|
vi.mock('swr', () => ({
|
|
mutate: vi.fn(),
|
|
}));
|
|
|
|
const mockConversation = {
|
|
id: 'conv-1',
|
|
name: 'Test conversation',
|
|
type: 'acp',
|
|
status: 'finished',
|
|
extra: {},
|
|
} as TChatConversation;
|
|
|
|
describe('conversationCache', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('getConversationOrNull', () => {
|
|
it('returns null when the backend reports a missing conversation', async () => {
|
|
const error = new BackendHttpError({
|
|
method: 'GET',
|
|
path: '/api/conversations/missing',
|
|
status: 404,
|
|
body: {
|
|
success: false,
|
|
error: 'Not found: Conversation missing not found',
|
|
code: 'NOT_FOUND',
|
|
},
|
|
});
|
|
vi.mocked(ipcBridge.conversation.get.invoke).mockRejectedValue(error);
|
|
|
|
await expect(getConversationOrNull('missing')).resolves.toBeNull();
|
|
});
|
|
|
|
it('returns the conversation when the backend lookup succeeds', async () => {
|
|
vi.mocked(ipcBridge.conversation.get.invoke).mockResolvedValue(mockConversation);
|
|
|
|
await expect(getConversationOrNull('conv-1')).resolves.toBe(mockConversation);
|
|
});
|
|
|
|
it('rethrows non-404 backend errors so database failures remain visible', async () => {
|
|
const error = new BackendHttpError({
|
|
method: 'GET',
|
|
path: '/api/conversations/conv-1',
|
|
status: 500,
|
|
body: {
|
|
success: false,
|
|
error: 'Internal error: Database error: no such table: conversations',
|
|
code: 'INTERNAL_ERROR',
|
|
},
|
|
});
|
|
vi.mocked(ipcBridge.conversation.get.invoke).mockRejectedValue(error);
|
|
|
|
await expect(getConversationOrNull('conv-1')).rejects.toBe(error);
|
|
});
|
|
});
|
|
|
|
describe('refreshConversationCache', () => {
|
|
it('skips cache mutation when the conversation is missing', async () => {
|
|
const error = new BackendHttpError({
|
|
method: 'GET',
|
|
path: '/api/conversations/missing',
|
|
status: 404,
|
|
body: {
|
|
success: false,
|
|
error: 'Not found: Conversation missing not found',
|
|
code: 'NOT_FOUND',
|
|
},
|
|
});
|
|
vi.mocked(ipcBridge.conversation.get.invoke).mockRejectedValue(error);
|
|
|
|
await expect(refreshConversationCache('missing')).resolves.toBeUndefined();
|
|
|
|
expect(mutate).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('rethrows non-404 backend errors instead of hiding them', async () => {
|
|
const error = new BackendHttpError({
|
|
method: 'GET',
|
|
path: '/api/conversations/conv-1',
|
|
status: 500,
|
|
body: {
|
|
success: false,
|
|
error: 'Internal error: Database error: no such table: conversations',
|
|
code: 'INTERNAL_ERROR',
|
|
},
|
|
});
|
|
vi.mocked(ipcBridge.conversation.get.invoke).mockRejectedValue(error);
|
|
|
|
await expect(refreshConversationCache('conv-1')).rejects.toBe(error);
|
|
|
|
expect(mutate).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|