File size: 4,676 Bytes
921d377 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | /**
* 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(<CallEventRow durationSec={26} endedAt={1713456900000} transcript={SAMPLE_TRANSCRIPT}/>);
expect(screen.getByRole('region', { name: /call/i })).toBeTruthy();
expect(screen.getByText(/26s/)).toBeTruthy();
});
it('hides the transcript body in the default collapsed state', () => {
render(<CallEventRow durationSec={26} transcript={SAMPLE_TRANSCRIPT}/>);
expect(screen.queryByText(/hello how are you going/)).toBeNull();
});
it('expands the transcript when the label button is clicked', () => {
render(<CallEventRow durationSec={26} transcript={SAMPLE_TRANSCRIPT}/>);
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(<CallEventRow durationSec={26} personaName="Secretary" transcript={SAMPLE_TRANSCRIPT} defaultExpanded/>);
// 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(<CallEventRow durationSec={26} defaultExpanded transcript={[
{
who: 'assistant',
text: 'hello  there',
},
]}/>);
// 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(<CallEventRow durationSec={26} onResume={vi.fn()}/>);
expect(screen.queryByText(/Transcript/i)).toBeNull();
expect(screen.queryByText(/Collapse/i)).toBeNull();
});
it('renders Resume link only when onResume is provided', () => {
const { rerender } = render(<CallEventRow durationSec={26} transcript={SAMPLE_TRANSCRIPT}/>);
expect(screen.queryByRole('button', { name: /resume call/i })).toBeNull();
const onResume = vi.fn();
rerender(<CallEventRow durationSec={26} transcript={SAMPLE_TRANSCRIPT} onResume={onResume}/>);
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(<CallEventRow durationSec={26} transcript={SAMPLE_TRANSCRIPT} onResume={onResume}/>);
// 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(<CallEventRow durationSec={26} transcript={SAMPLE_TRANSCRIPT} defaultExpanded/>);
expect(screen.getByText(/hello how are you going/)).toBeTruthy();
});
it('formats durations as Ns / Nm / Nm Ss', () => {
const { rerender } = render(<CallEventRow durationSec={42}/>);
expect(screen.getByText(/42s/)).toBeTruthy();
rerender(<CallEventRow durationSec={180}/>);
expect(screen.getByText(/3m/)).toBeTruthy();
rerender(<CallEventRow durationSec={192}/>);
expect(screen.getByText(/3m 12s/)).toBeTruthy();
});
});
|