import { createMessageElement } from '../../public/call/chat/renderer-chat.js'; import { createParticipantTile, getParticipantTile } from '../../public/call/participants/renderer-participant-grid.js'; import { createUserEntryElement } from '../../public/call/renderers/renderer-ui.js'; import { renderOnlineUsers } from '../../public/call/signaling/connect-directory.js'; const formatTimestamp = value => value; const unsafeText = 'Alice'; function mediaState(overrides = {}) { return { audio: true, video: true, isSpeaking: false, ...overrides }; } describe('safe dynamic rendering', () => { afterEach(() => { document.body.innerHTML = ''; }); test('renders chat text as text, not markup', () => { const element = createMessageElement({ id: 'msg-1', type: 'text', isSelf: false, senderName: unsafeText, senderAvatar: '/images/p1.png', content: unsafeText, timestamp: 'now' }, formatTimestamp); expect(element.querySelector('.message-text').textContent).toBe(unsafeText); expect(element.querySelector('.message-content img')).toBeNull(); expect(element.querySelector('.message-sender').textContent).toBe(unsafeText); }); test('renders participant names safely and finds ids without selector injection', () => { const participantId = 'room"] [data-bad="1'; const tile = createParticipantTile(participantId, unsafeText); const grid = document.createElement('div'); grid.appendChild(tile); expect(tile.querySelector('.absolute.bottom-3 span').textContent).toBe(unsafeText); expect(tile.querySelector('.absolute.bottom-3 img')).toBeNull(); expect(getParticipantTile(grid, participantId)).toBe(tile); }); test('renders user list entries without interpreting user profile fields as HTML', () => { const entry = createUserEntryElement({ role: 'participant', id: 'participant-1', user: { name: unsafeText, avatar: '/images/p2.png', mediaState: mediaState({ audio: false }) } }); expect(entry.textContent).toContain(unsafeText); expect(entry.querySelectorAll('img')).toHaveLength(1); }); test('renders online users without injecting markup from directory data', () => { const onlineUsersList = document.createElement('div'); const usersContainer = document.createElement('div'); const onlineUsersSummary = document.createElement('div'); renderOnlineUsers({ users: [{ name: unsafeText, userId: unsafeText, avatar: '/images/p1.png', role: 'participant', connectionId: 'room-1' }], currentUserId: 'other-user', onlineUsersList, usersContainer, onlineUsersSummary }); expect(usersContainer.textContent).toContain(unsafeText); expect(usersContainer.querySelector('button')).toBeNull(); expect(usersContainer.querySelectorAll('img')).toHaveLength(1); }); });