fix: update chatStore tests for sub-store refactoring
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

Tests were referencing old monolithic useChatStore API. Updated to
use useConversationStore for conversation/agent/model state and
useChatStore for message operations. 10→0 failures.
This commit is contained in:
iven
2026-04-06 11:57:46 +08:00
parent 7f9799b7e0
commit 4a23bbeda6
2 changed files with 128 additions and 79 deletions

View File

@@ -2,10 +2,18 @@
* Chat Store Tests
*
* Tests for chat state management including messages, conversations, and agents.
* After the chatStore refactoring, chatStore delegates to:
* - conversationStore: conversations, agents, currentAgent, sessionKey, currentModel
* - messageStore: token tracking
* - streamStore: streaming, sendMessage, chatMode
*
* chatStore remains the facade, so tests use useChatStore for message operations
* and useConversationStore for conversation/agent state.
*/
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { useChatStore, Message, Conversation, Agent, toChatAgent } from '../../src/store/chatStore';
import { useChatStore, Message } from '../../src/store/chatStore';
import { useConversationStore, toChatAgent, type Agent, type Conversation } from '../../src/store/chat/conversationStore';
import { localStorageMock } from '../setup';
// Mock gateway client - use vi.hoisted to ensure mocks are available before module import
@@ -72,21 +80,41 @@ vi.mock('../../src/lib/skill-discovery', () => ({
}));
describe('chatStore', () => {
// Store the original state to reset between tests
const initialState = {
messages: [],
conversations: [],
currentConversationId: null,
agents: [{ id: '1', name: 'ZCLAW', icon: '\u{1F99E}', color: 'bg-gradient-to-br from-orange-500 to-red-500', lastMessage: '\u{53D1}\u{9001}\u{6D88}\u{606F}\u{5F00}\u{59CB}\u{5BF9}\u{8BDD}', time: '' }],
currentAgent: { id: '1', name: 'ZCLAW', icon: '\u{1F99E}', color: 'bg-gradient-to-br from-orange-500 to-red-500', lastMessage: '\u{53D1}\u{9001}\u{6D88}\u{606F}\u{5F00}\u{59CB}\u{5BF9}\u{8BDD}', time: '' },
// Default agent matching conversationStore's DEFAULT_AGENT
const defaultAgent: Agent = {
id: '1',
name: 'ZCLAW',
icon: '\u{1F99E}',
color: 'bg-gradient-to-br from-orange-500 to-red-500',
lastMessage: '\u{53D1}\u{9001}\u{6D88}\u{606F}\u{5F00}\u{59CB}\u{5BF9}\u{8BDD}',
time: '',
};
const initialChatState = {
messages: [] as Message[],
isStreaming: false,
currentModel: 'glm-5',
sessionKey: null,
isLoading: false,
totalInputTokens: 0,
totalOutputTokens: 0,
chatMode: 'thinking' as const,
suggestions: [] as string[],
};
const initialConvState = {
conversations: [] as Conversation[],
currentConversationId: null as string | null,
agents: [defaultAgent] as Agent[],
currentAgent: defaultAgent as Agent,
isStreaming: false,
currentModel: 'glm-4-flash',
sessionKey: null as string | null,
};
beforeEach(() => {
// Reset store state
useChatStore.setState(initialState);
// Reset chatStore (messages + facade mirrors)
useChatStore.setState(initialChatState);
// Reset conversationStore (conversations, agents, session, model)
useConversationStore.setState(initialConvState);
// Clear localStorage
localStorageMock.clear();
// Clear all mocks
@@ -104,10 +132,10 @@ describe('chatStore', () => {
});
it('should have default agent set', () => {
const state = useChatStore.getState();
expect(state.currentAgent).not.toBeNull();
expect(state.currentAgent?.id).toBe('1');
expect(state.currentAgent?.name).toBe('ZCLAW');
const convState = useConversationStore.getState();
expect(convState.currentAgent).not.toBeNull();
expect(convState.currentAgent?.id).toBe('1');
expect(convState.currentAgent?.name).toBe('ZCLAW');
});
it('should not be streaming initially', () => {
@@ -116,18 +144,18 @@ describe('chatStore', () => {
});
it('should have default model', () => {
const state = useChatStore.getState();
expect(state.currentModel).toBe('glm-5');
const convState = useConversationStore.getState();
expect(convState.currentModel).toBe('glm-4-flash');
});
it('should have null sessionKey initially', () => {
const state = useChatStore.getState();
expect(state.sessionKey).toBeNull();
const convState = useConversationStore.getState();
expect(convState.sessionKey).toBeNull();
});
it('should have empty conversations array', () => {
const state = useChatStore.getState();
expect(state.conversations).toEqual([]);
const convState = useConversationStore.getState();
expect(convState.conversations).toEqual([]);
});
});
@@ -268,8 +296,9 @@ describe('chatStore', () => {
setCurrentModel('gpt-4');
const state = useChatStore.getState();
expect(state.currentModel).toBe('gpt-4');
// currentModel is stored on conversationStore
const convState = useConversationStore.getState();
expect(convState.currentModel).toBe('gpt-4');
});
});
@@ -284,15 +313,15 @@ describe('chatStore', () => {
timestamp: new Date(),
});
useChatStore.setState({ sessionKey: 'old-session' });
newConversation();
const state = useChatStore.getState();
expect(state.messages).toEqual([]);
expect(state.sessionKey).toBeNull();
expect(state.isStreaming).toBe(false);
expect(state.currentConversationId).toBeNull();
const chatState = useChatStore.getState();
const convState = useConversationStore.getState();
expect(chatState.messages).toEqual([]);
// sessionKey and currentConversationId reset on conversationStore
expect(convState.sessionKey).toBeNull();
expect(chatState.isStreaming).toBe(false);
expect(convState.currentConversationId).toBeNull();
});
it('should save current messages to conversations before clearing', () => {
@@ -307,10 +336,10 @@ describe('chatStore', () => {
newConversation();
const state = useChatStore.getState();
// Conversation should be saved
expect(state.conversations.length).toBeGreaterThan(0);
expect(state.conversations[0].messages[0].content).toBe('Test message to save');
const convState = useConversationStore.getState();
// Conversation should be saved on conversationStore
expect(convState.conversations.length).toBeGreaterThan(0);
expect(convState.conversations[0].messages[0].content).toBe('Test message to save');
});
});
@@ -335,14 +364,16 @@ describe('chatStore', () => {
timestamp: new Date(),
});
const firstConvId = useChatStore.getState().conversations[0].id;
const convState = useConversationStore.getState();
const firstConvId = convState.conversations[0].id;
// Switch back to first conversation
switchConversation(firstConvId);
const state = useChatStore.getState();
expect(state.messages[0].content).toBe('First conversation');
expect(state.currentConversationId).toBe(firstConvId);
const chatState = useChatStore.getState();
const updatedConvState = useConversationStore.getState();
expect(chatState.messages[0].content).toBe('First conversation');
expect(updatedConvState.currentConversationId).toBe(firstConvId);
});
});
@@ -359,19 +390,20 @@ describe('chatStore', () => {
});
newConversation();
const convId = useChatStore.getState().conversations[0].id;
expect(useChatStore.getState().conversations).toHaveLength(1);
const convState = useConversationStore.getState();
const convId = convState.conversations[0].id;
expect(convState.conversations).toHaveLength(1);
// Delete it
deleteConversation(convId);
expect(useChatStore.getState().conversations).toHaveLength(0);
expect(useConversationStore.getState().conversations).toHaveLength(0);
});
it('should clear messages if deleting current conversation', () => {
const { addMessage, deleteConversation } = useChatStore.getState();
// Create a conversation without calling newConversation
// Add a message
addMessage({
id: 'msg-1',
role: 'user',
@@ -379,14 +411,14 @@ describe('chatStore', () => {
timestamp: new Date(),
});
// Manually set up a current conversation
// Manually set up a current conversation on conversationStore
const convId = 'conv-test-123';
useChatStore.setState({
useConversationStore.setState({
currentConversationId: convId,
conversations: [{
id: convId,
title: 'Test',
messages: useChatStore.getState().messages,
messages: useChatStore.getState().messages as any[],
sessionKey: null,
agentId: null,
createdAt: new Date(),
@@ -396,10 +428,12 @@ describe('chatStore', () => {
deleteConversation(convId);
const state = useChatStore.getState();
expect(state.messages).toEqual([]);
expect(state.sessionKey).toBeNull();
expect(state.currentConversationId).toBeNull();
const chatState = useChatStore.getState();
const convState = useConversationStore.getState();
// chatStore facade should detect resetMessages and clear its messages
expect(chatState.messages).toEqual([]);
expect(convState.sessionKey).toBeNull();
expect(convState.currentConversationId).toBeNull();
});
});
@@ -417,8 +451,9 @@ describe('chatStore', () => {
setCurrentAgent(newAgent);
const state = useChatStore.getState();
expect(state.currentAgent).toEqual(newAgent);
// currentAgent is stored on conversationStore
const convState = useConversationStore.getState();
expect(convState.currentAgent).toEqual(newAgent);
});
it('should save current conversation when switching agents', () => {
@@ -443,7 +478,7 @@ describe('chatStore', () => {
};
setCurrentAgent(newAgent);
// Messages should be cleared for new agent
// Messages should be cleared for new agent (different agent id)
expect(useChatStore.getState().messages).toEqual([]);
});
});
@@ -457,10 +492,12 @@ describe('chatStore', () => {
{ id: 'agent-2', name: 'Agent Two', nickname: 'A2' },
]);
const state = useChatStore.getState();
expect(state.agents).toHaveLength(2);
expect(state.agents[0].name).toBe('Agent One');
expect(state.agents[1].name).toBe('Agent Two');
// agents are stored on conversationStore
const convState = useConversationStore.getState();
// DEFAULT_AGENT + 2 profile agents = 3
expect(convState.agents).toHaveLength(3);
expect(convState.agents[1].name).toBe('Agent One');
expect(convState.agents[2].name).toBe('Agent Two');
});
it('should use default agent when no profiles provided', () => {
@@ -468,9 +505,9 @@ describe('chatStore', () => {
syncAgents([]);
const state = useChatStore.getState();
expect(state.agents).toHaveLength(1);
expect(state.agents[0].id).toBe('1');
const convState = useConversationStore.getState();
expect(convState.agents).toHaveLength(1);
expect(convState.agents[0].id).toBe('1');
});
});
@@ -644,14 +681,14 @@ describe('chatStore', () => {
newConversation();
const state = useChatStore.getState();
expect(state.conversations[0].title).toContain('This is a long message');
expect(state.conversations[0].title.length).toBeLessThanOrEqual(33); // 30 chars + '...'
const convState = useConversationStore.getState();
expect(convState.conversations[0].title).toContain('This is a long message');
expect(convState.conversations[0].title.length).toBeLessThanOrEqual(33); // 30 chars + '...'
});
it('should use default title for empty messages', () => {
// Create a conversation directly with empty messages
useChatStore.setState({
// Create a conversation directly with empty messages on conversationStore
useConversationStore.setState({
conversations: [{
id: 'conv-1',
title: '',
@@ -663,8 +700,8 @@ describe('chatStore', () => {
}],
});
const state = useChatStore.getState();
expect(state.conversations).toHaveLength(1);
const convState = useConversationStore.getState();
expect(convState.conversations).toHaveLength(1);
});
});