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');
  });
});