import { TranscriptView } from '../../js/components/transcript-view.js'; function makeContainer() { // jsdom provides a real DOM — use a real div for simplicity const div = document.createElement('div'); div.scrollTop = 0; Object.defineProperty(div, 'scrollHeight', { value: 200, writable: true }); return div; } describe('TranscriptView', () => { let view, container; beforeEach(() => { container = makeContainer(); view = new TranscriptView(container); }); test('addMessage creates a new bubble for the first message', () => { view.addMessage('user', 'Hello'); expect(container.children.length).toBe(1); expect(container.querySelector('.user-message')).not.toBeNull(); expect(container.querySelector('.message-text').textContent).toBe('Hello'); }); test('addMessage appends text for consecutive same-speaker messages', () => { view.addMessage('agent', 'Hello'); view.addMessage('agent', ' world'); expect(container.children.length).toBe(1); expect(container.querySelector('.message-text').textContent).toBe('Hello world'); }); test('addMessage creates a new bubble for a different speaker', () => { view.addMessage('user', 'Hi'); view.addMessage('agent', 'Hey'); expect(container.children.length).toBe(2); }); test('addMessage ignores empty or whitespace-only text', () => { view.addMessage('user', ''); view.addMessage('user', ' '); expect(container.children.length).toBe(0); }); test('system message has no avatar element', () => { view.addMessage('system', 'Error occurred'); expect(container.querySelector('.system-message .message-avatar')).toBeNull(); }); test('clear removes all messages and resets state', () => { view.addMessage('user', 'Hi'); view.addMessage('agent', 'Hey'); view.clear(); expect(container.innerHTML).toBe(''); expect(view.lastSpeaker).toBeNull(); expect(view.lastBubble).toBeNull(); }); test('after clear, a new message creates a fresh bubble', () => { view.addMessage('user', 'Before'); view.clear(); view.addMessage('user', 'After'); expect(container.children.length).toBe(1); expect(container.querySelector('.message-text').textContent).toBe('After'); }); });