provisionalPrimaryContext.test.ts2.3 KBView on GitHub
import { shouldDropProvisionalPrimary } from '@/modules/cedar-os/src/cedar-os-components/chatComponents/provisionalPrimaryContext';

/**
 * A chat's `primaryConversation` is committed automatically the moment a conversation is on
 * screen, so on an unused chat it is provisional: closing the conversation without ever asking
 * anything must take the chip with it.
 */
const base = {
  threadId: 'thread-1',
  openArtifact: null,
  previous: { threadId: 'thread-1', kind: 'conversation', id: 'conv-1' },
  messageCount: 0,
  primaryConversationId: 'conv-1',
} as const;

describe('shouldDropProvisionalPrimary', () => {
  it('drops it when the conversation view closes on an empty chat', () => {
    expect(shouldDropProvisionalPrimary({ ...base })).toBe(true);
  });

  it('keeps it once the chat has been used', () => {
    expect(shouldDropProvisionalPrimary({ ...base, messageCount: 1 })).toBe(false);
  });

  it('keeps it while something is still open', () => {
    expect(
      shouldDropProvisionalPrimary({
        ...base,
        openArtifact: { kind: 'conversation', id: 'conv-1' },
      }),
    ).toBe(false);
  });

  it('does not fire on mount, when nothing was displayed yet', () => {
    // Entering a thread renders with a null artifact for a beat before the landing effect
    // restores it — treating that as a close would wipe every chat the user opens.
    expect(shouldDropProvisionalPrimary({ ...base, previous: null })).toBe(false);
  });

  it('does not treat a thread switch as a close', () => {
    expect(
      shouldDropProvisionalPrimary({
        ...base,
        previous: { threadId: 'other-thread', kind: 'conversation', id: 'conv-1' },
      }),
    ).toBe(false);
  });

  it('ignores non-conversation artifacts — only the primary slot is auto-committed', () => {
    expect(
      shouldDropProvisionalPrimary({
        ...base,
        previous: { threadId: 'thread-1', kind: 'email_thread', id: 'thr-1' },
      }),
    ).toBe(false);
  });

  it('only drops the conversation that was actually closed', () => {
    expect(
      shouldDropProvisionalPrimary({ ...base, primaryConversationId: 'conv-other' }),
    ).toBe(false);
  });

  it('is a no-op when there is no committed primary', () => {
    expect(shouldDropProvisionalPrimary({ ...base, primaryConversationId: null })).toBe(false);
  });
});