import { render } from '@testing-library/react'; import { describe, it, expect, vi } from 'vitest'; import { Code } from './code'; import { RevealContext } from '../reveal-context'; describe('Code', () => { it('renders pre/code and trims multiline template literals by default', () => { const { container } = render( {` function add(a, b) { return a + b; } `} ); const pre = container.querySelector('pre'); const code = container.querySelector('pre > code'); expect(pre).toBeInTheDocument(); expect(pre).toHaveClass('code-wrapper'); expect(code).toHaveClass('javascript'); expect(code?.textContent).toBe('function add(a, b) {\n\treturn a + b;\n}'); }); it('can disable trimming', () => { const source = '\n\tconst value = 1;\n'; const { container } = render({source}); const code = container.querySelector('pre > code'); expect(code?.textContent).toBe(source); }); it('maps line number props to reveal data attributes', () => { const { container } = render( {`console.log('hello')`} ); const code = container.querySelector('pre > code'); expect(code).toHaveAttribute('data-line-numbers', '|2,4-6|8'); expect(code).toHaveAttribute('data-ln-start-from', '10'); }); it('invokes the Reveal highlight plugin when registered on the deck', () => { const highlightBlock = vi.fn((block: HTMLElement) => { block.setAttribute('data-highlighted', 'yes'); }); const deck = { getPlugin: vi.fn().mockReturnValue({ highlightBlock }), syncFragments: vi.fn(), } as any; const { container } = render(
{`console.log('hello')`}
); const code = container.querySelector('pre > code'); expect(deck.getPlugin).toHaveBeenCalledWith('highlight'); expect(highlightBlock).toHaveBeenCalledWith(code); expect(deck.syncFragments).toHaveBeenCalledWith(expect.any(HTMLElement)); }); it('rehighlights updated code without accumulating generated fragments', () => { const highlightBlock = vi.fn((block: HTMLElement) => { block.setAttribute('data-highlighted', 'yes'); const fragment = block.cloneNode(true) as HTMLElement; fragment.classList.add('fragment'); block.parentElement?.appendChild(fragment); }); const deck = { getPlugin: vi.fn().mockReturnValue({ highlightBlock }), syncFragments: vi.fn(), } as any; const { container, rerender } = render(
{`console.log('one')`}
); expect(container.querySelectorAll('pre > code.fragment')).toHaveLength(1); rerender(
{`console.log('two')`}
); expect(highlightBlock).toHaveBeenCalledTimes(2); expect(container.querySelectorAll('pre > code.fragment')).toHaveLength(1); expect(container.querySelector('pre > code:not(.fragment)')).toHaveTextContent( "console.log('two')" ); }); it('restores full line-number steps before rehighlighting after plugin mutation', () => { const seenLineNumbers: string[] = []; const highlightBlock = vi.fn((block: HTMLElement) => { seenLineNumbers.push(block.getAttribute('data-line-numbers') || ''); block.setAttribute('data-highlighted', 'yes'); // Mimic RevealHighlight: original block is rewritten to the first step and // an extra fragment block is appended for following steps. block.setAttribute('data-line-numbers', '1'); const fragment = block.cloneNode(true) as HTMLElement; fragment.classList.add('fragment'); fragment.setAttribute('data-line-numbers', '3'); block.parentElement?.appendChild(fragment); }); const deck = { getPlugin: vi.fn().mockReturnValue({ highlightBlock }), syncFragments: vi.fn(), } as any; const { rerender } = render(
{`console.log('one')`}
); rerender(
{`console.log('one')`}
); expect(seenLineNumbers).toEqual(['1|3', '1|3']); }); });