import React from 'react'; import { act } from 'react'; import { createRoot } from 'react-dom/client'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import type { InboxMessage } from '@shared/types'; vi.mock('@renderer/components/team/activity/ActivityItem', () => ({ ActivityItem: ({ message }: { message: InboxMessage }) => React.createElement('div', { 'data-testid': 'activity-item' }, message.text), isNoiseMessage: () => false, })); vi.mock('@renderer/components/team/activity/AnimatedHeightReveal', () => ({ ENTRY_REVEAL_ANIMATION_MS: 220, AnimatedHeightReveal: ({ children }: { children: React.ReactNode }) => React.createElement(React.Fragment, null, children), })); vi.mock('@renderer/components/team/activity/useNewItemKeys', () => ({ useNewItemKeys: () => new Set(), })); import { ActivityTimeline } from '@renderer/components/team/activity/ActivityTimeline'; function makeMessage(overrides: Partial = {}): InboxMessage { return { from: 'team-lead', text: 'message', timestamp: '2026-04-18T13:00:00.000Z', read: true, source: 'inbox', messageId: 'message-id', leadSessionId: 'lead-session-1', ...overrides, }; } describe('ActivityTimeline session separators', () => { let container: HTMLDivElement; beforeEach(() => { vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true); container = document.createElement('div'); document.body.appendChild(container); }); afterEach(() => { container.remove(); document.body.innerHTML = ''; vi.unstubAllGlobals(); }); it('does not render New session for regular message rows even when their session ids differ', async () => { const root = createRoot(container); const messages: InboxMessage[] = [ makeMessage({ messageId: 'member-newest', text: 'member newest', leadSessionId: 'member-session-2', from: 'alice', source: 'inbox', }), makeMessage({ messageId: 'member-older', text: 'member older', leadSessionId: 'member-session-1', from: 'alice', source: 'inbox', }), ]; await act(async () => { root.render(React.createElement(ActivityTimeline, { messages, teamName: 'demo-team' })); }); expect(container.textContent).not.toContain('New session'); await act(async () => { root.unmount(); }); }); it('renders New session between lead thought groups from different sessions', async () => { const root = createRoot(container); const messages: InboxMessage[] = [ makeMessage({ messageId: 'thought-newest', text: 'lead thought newest', leadSessionId: 'lead-session-2', from: 'team-lead', source: 'lead_session', }), makeMessage({ messageId: 'regular-between', text: 'regular message between sessions', leadSessionId: 'member-session-1', from: 'alice', source: 'inbox', }), makeMessage({ messageId: 'thought-older', text: 'lead thought older', leadSessionId: 'lead-session-1', from: 'team-lead', source: 'lead_session', }), ]; await act(async () => { root.render(React.createElement(ActivityTimeline, { messages, teamName: 'demo-team' })); }); expect(container.textContent).toContain('New session'); await act(async () => { root.unmount(); }); }); it('still renders New session when the newest thought belongs to currentLeadSessionId', async () => { const root = createRoot(container); const messages: InboxMessage[] = [ makeMessage({ messageId: 'thought-current', text: 'current lead thought', leadSessionId: 'lead-session-current', from: 'team-lead', source: 'lead_session', }), makeMessage({ messageId: 'thought-history', text: 'historical lead thought', leadSessionId: 'lead-session-history', from: 'team-lead', source: 'lead_session', }), ]; await act(async () => { root.render( React.createElement(ActivityTimeline, { messages, teamName: 'demo-team', currentLeadSessionId: 'lead-session-current', }) ); }); expect(container.textContent).toContain('New session'); await act(async () => { root.unmount(); }); }); });