/** * Unit tests for CallEventRow — enterprise chat renderer for phone * calls. Covers the three-state UX: * * - Collapsed default, clickable label, hidden action cluster * - Expanded after click, transcript visible, Collapse link exposed * - Resume handler wired, Resume action visible when provided * * jsdom caveat: group-hover CSS is not actually evaluated, so the * hover-reveal is tested by asserting the hover CSS class is present * on the action cluster, rather than by simulating mouseenter. */ import React from 'react'; import { describe, it, expect, vi } from 'vitest'; import { render, screen, fireEvent } from '@testing-library/react'; import CallEventRow from './CallEventRow'; const SAMPLE_TRANSCRIPT = [ { who: 'user', text: 'hello how are you going' }, { who: 'assistant', text: 'I am well, thank you.' }, ]; describe('CallEventRow', () => { it('renders the collapsed divider with duration + time summary', () => { render(); expect(screen.getByRole('region', { name: /call/i })).toBeTruthy(); expect(screen.getByText(/26s/)).toBeTruthy(); }); it('hides the transcript body in the default collapsed state', () => { render(); expect(screen.queryByText(/hello how are you going/)).toBeNull(); }); it('expands the transcript when the label button is clicked', () => { render(); const expandBtn = screen.getByRole('button', { name: /expand call row/i }); fireEvent.click(expandBtn); expect(screen.getByText(/hello how are you going/)).toBeTruthy(); expect(screen.getByText(/I am well, thank you\./)).toBeTruthy(); }); it('uses personaName as the label column for assistant lines', () => { render(); // User label + persona label both appear in the expanded body. expect(screen.getByText('You')).toBeTruthy(); expect(screen.getByText('Secretary')).toBeTruthy(); }); it('strips markdown image syntax from transcript lines', () => { render(); // Stripped text has the middle removed; renders as "hello there". expect(screen.getByText(/^hello\s+there$/)).toBeTruthy(); }); it('hides the Transcript / Collapse affordance when transcript is empty', () => { render(); expect(screen.queryByText(/Transcript/i)).toBeNull(); expect(screen.queryByText(/Collapse/i)).toBeNull(); }); it('renders Resume link only when onResume is provided', () => { const { rerender } = render(); expect(screen.queryByRole('button', { name: /resume call/i })).toBeNull(); const onResume = vi.fn(); rerender(); expect(screen.getByRole('button', { name: /resume call/i })).toBeTruthy(); }); it('fires onResume when Resume is clicked, does not expand/collapse', () => { const onResume = vi.fn(); render(); // Transcript stays hidden since we clicked Resume, not the label. fireEvent.click(screen.getByRole('button', { name: /resume call/i })); expect(onResume).toHaveBeenCalledTimes(1); expect(screen.queryByText(/hello how are you going/)).toBeNull(); }); it('renders with defaultExpanded=true showing transcript immediately', () => { render(); expect(screen.getByText(/hello how are you going/)).toBeTruthy(); }); it('formats durations as Ns / Nm / Nm Ss', () => { const { rerender } = render(); expect(screen.getByText(/42s/)).toBeTruthy(); rerender(); expect(screen.getByText(/3m/)).toBeTruthy(); rerender(); expect(screen.getByText(/3m 12s/)).toBeTruthy(); }); });