threadStatus.test.tsx2.7 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 1 (design: chat-thread-store) — per-thread status metadata.
* Exercises the real store slice headlessly: setThreadStatus / pin / unpin /
* createdThisSession, with no UI in the loop.
*/
describe('agentThreadsSlice — thread status metadata', () => {
beforeEach(() => {
useCedarStore.setState((state) => ({
...state,
threadMap: {
[DEFAULT_THREAD_ID]: {
id: DEFAULT_THREAD_ID,
lastLoaded: new Date().toISOString(),
messages: [],
},
},
mainThreadId: DEFAULT_THREAD_ID,
messages: [],
}));
});
it('setThreadStatus writes status and bumps lastActiveAt on streaming', () => {
const before = useCedarStore.getState().threadMap[DEFAULT_THREAD_ID].lastActiveAt;
expect(before).toBeUndefined();
useCedarStore.getState().setThreadStatus(DEFAULT_THREAD_ID, 'streaming');
const streaming = useCedarStore.getState().threadMap[DEFAULT_THREAD_ID];
expect(streaming.status).toBe('streaming');
expect(typeof streaming.lastActiveAt).toBe('string');
expect(Date.parse(streaming.lastActiveAt!)).not.toBeNaN();
});
it('setThreadStatus does not bump lastActiveAt for non-streaming transitions', () => {
useCedarStore.getState().setThreadStatus(DEFAULT_THREAD_ID, 'streaming');
const stamp = useCedarStore.getState().threadMap[DEFAULT_THREAD_ID].lastActiveAt;
useCedarStore.getState().setThreadStatus(DEFAULT_THREAD_ID, 'finished');
const finished = useCedarStore.getState().threadMap[DEFAULT_THREAD_ID];
expect(finished.status).toBe('finished');
// lastActiveAt preserved from the streaming transition, not re-stamped.
expect(finished.lastActiveAt).toBe(stamp);
});
it('setThreadStatus is a no-op for an unknown thread (no throw)', () => {
expect(() =>
useCedarStore.getState().setThreadStatus('missing-thread', 'streaming'),
).not.toThrow();
});
it('pinThread / unpinThread toggle pinned', () => {
expect(useCedarStore.getState().threadMap[DEFAULT_THREAD_ID].pinned).toBeUndefined();
useCedarStore.getState().pinThread(DEFAULT_THREAD_ID);
expect(useCedarStore.getState().threadMap[DEFAULT_THREAD_ID].pinned).toBe(true);
useCedarStore.getState().unpinThread(DEFAULT_THREAD_ID);
expect(useCedarStore.getState().threadMap[DEFAULT_THREAD_ID].pinned).toBe(false);
});
it('createThread stamps createdThisSession', () => {
const id = useCedarStore.getState().createThread(undefined, 'Fresh');
expect(useCedarStore.getState().threadMap[id].createdThisSession).toBe(true);
});
});