hydrateThreads.test.tsx2.2 KBView on GitHub import { useCedarStore } from '@/modules/cedar-os/src/store/CedarStore';
/**
* Phase 5 (design: chat-thread-store) — hydrateThreadsFromServer upserts persisted
* threads into threadMap without clobbering in-memory messages/status/pins, so the
* 'recent' view reflects the backend list.
*/
describe('agentThreadsSlice — hydrateThreadsFromServer', () => {
beforeEach(() => {
useCedarStore.setState((state) => ({
...state,
threadMap: {
// A live thread with messages + streaming status that must be preserved.
live: {
id: 'live',
name: 'Live thread',
messages: [{ id: 'm1', role: 'user', type: 'text', content: 'hi' }],
status: 'streaming',
pinned: true,
},
},
mainThreadId: 'live',
activeThreadId: 'live',
messages: [],
}));
});
it('adds new server threads and refreshes existing metadata, preserving messages/status/pins', () => {
useCedarStore.getState().hydrateThreadsFromServer([
{ id: 'srv', name: 'Adobe QBR', color: '#f97316', context: { items: [] }, updatedAt: '2026-07-05T10:00:00Z' },
{ id: 'live', name: 'Live renamed', color: '#000', updatedAt: new Date('2026-07-06T00:00:00Z') },
]);
const map = useCedarStore.getState().threadMap;
// New thread added
expect(map['srv'].name).toBe('Adobe QBR');
expect(map['srv'].updatedAt).toBe('2026-07-05T10:00:00Z');
// Existing thread: metadata refreshed…
expect(map['live'].name).toBe('Live renamed');
expect(map['live'].updatedAt).toBe('2026-07-06T00:00:00.000Z'); // Date coerced to ISO
// …but live message/status/pin state preserved
expect(map['live'].messages).toHaveLength(1);
expect(map['live'].status).toBe('streaming');
expect(map['live'].pinned).toBe(true);
});
it('surfaces hydrated threads through the recent view', () => {
useCedarStore.getState().hydrateThreadsFromServer([
{ id: 'srv', name: 'Adobe QBR', updatedAt: '2026-07-05T10:00:00Z' },
]);
const recentIds = useCedarStore.getState().getThreadsByView('recent').map((t) => t.id);
expect(recentIds).toContain('srv');
expect(recentIds).toContain('live');
});
});