threadStatusLifecycle.test.tsx1.9 KBView on GitHub import { DEFAULT_THREAD_ID } from '@/modules/cedar-os/src/store/messages/MessageTypes';
import { useCedarStore } from '@/modules/cedar-os/src/store/CedarStore';
/**
* Phase 3 (design: chat-thread-store) — status is driven by the send/finish lifecycle.
* We drive the same store transitions the connection slice performs (setThreadStatus
* 'streaming' on send, 'finished' on finish) and assert the derived reads follow.
*/
describe('agentThreadsSlice — status lifecycle', () => {
beforeEach(() => {
useCedarStore.setState((state) => ({
...state,
threadMap: {
[DEFAULT_THREAD_ID]: {
id: DEFAULT_THREAD_ID,
name: 'Live',
lastLoaded: new Date().toISOString(),
messages: [{ id: 'm1', role: 'user', type: 'text', content: 'hi' }],
},
},
mainThreadId: DEFAULT_THREAD_ID,
activeThreadId: DEFAULT_THREAD_ID,
messages: [],
}));
});
it('streaming → finished transition drives status, active view, and isThreadProcessing', () => {
const store = () => useCedarStore.getState();
// --- send ---
store().setThreadStatus(DEFAULT_THREAD_ID, 'streaming');
expect(store().threadMap[DEFAULT_THREAD_ID].status).toBe('streaming');
expect(store().isThreadProcessing(DEFAULT_THREAD_ID)).toBe(true);
expect(store().getThreadsByView('active').map((t) => t.id)).toEqual([DEFAULT_THREAD_ID]);
// --- finish ---
store().setThreadStatus(DEFAULT_THREAD_ID, 'finished');
expect(store().threadMap[DEFAULT_THREAD_ID].status).toBe('finished');
expect(store().isThreadProcessing(DEFAULT_THREAD_ID)).toBe(false);
expect(store().getThreadsByView('active')).toHaveLength(0);
});
it('isThreadProcessing is false for idle/unknown threads', () => {
expect(useCedarStore.getState().isThreadProcessing(DEFAULT_THREAD_ID)).toBe(false);
expect(useCedarStore.getState().isThreadProcessing('nope')).toBe(false);
});
});