返回 reveal.js
code.test.tsx
根目录 / react / src / components / code.test.tsx
1 import { render } from '@testing-library/react';
2 import { describe, it, expect, vi } from 'vitest';
3 import { Code } from './code';
4 import { RevealContext } from '../reveal-context';
5
6 describe('Code', () => {
7 it('renders pre/code and trims multiline template literals by default', () => {
8 const { container } = render(
9 <Code language="javascript">{`
10 function add(a, b) {
11 return a + b;
12 }
13 `}</Code>
14 );
15
16 const pre = container.querySelector('pre');
17 const code = container.querySelector('pre > code');
18
19 expect(pre).toBeInTheDocument();
20 expect(pre).toHaveClass('code-wrapper');
21 expect(code).toHaveClass('javascript');
22 expect(code?.textContent).toBe('function add(a, b) {\n\treturn a + b;\n}');
23 });
24
25 it('can disable trimming', () => {
26 const source = '\n\tconst value = 1;\n';
27 const { container } = render(<Code trim={false}>{source}</Code>);
28 const code = container.querySelector('pre > code');
29
30 expect(code?.textContent).toBe(source);
31 });
32
33 it('maps line number props to reveal data attributes', () => {
34 const { container } = render(
35 <Code language="js" lineNumbers="|2,4-6|8" startFrom={10}>
36 {`console.log('hello')`}
37 </Code>
38 );
39
40 const code = container.querySelector('pre > code');
41 expect(code).toHaveAttribute('data-line-numbers', '|2,4-6|8');
42 expect(code).toHaveAttribute('data-ln-start-from', '10');
43 });
44
45 it('invokes the Reveal highlight plugin when registered on the deck', () => {
46 const highlightBlock = vi.fn((block: HTMLElement) => {
47 block.setAttribute('data-highlighted', 'yes');
48 });
49 const deck = {
50 getPlugin: vi.fn().mockReturnValue({ highlightBlock }),
51 syncFragments: vi.fn(),
52 } as any;
53
54 const { container } = render(
55 <RevealContext.Provider value={deck}>
56 <section>
57 <Code language="javascript">{`console.log('hello')`}</Code>
58 </section>
59 </RevealContext.Provider>
60 );
61
62 const code = container.querySelector('pre > code');
63 expect(deck.getPlugin).toHaveBeenCalledWith('highlight');
64 expect(highlightBlock).toHaveBeenCalledWith(code);
65 expect(deck.syncFragments).toHaveBeenCalledWith(expect.any(HTMLElement));
66 });
67
68 it('rehighlights updated code without accumulating generated fragments', () => {
69 const highlightBlock = vi.fn((block: HTMLElement) => {
70 block.setAttribute('data-highlighted', 'yes');
71 const fragment = block.cloneNode(true) as HTMLElement;
72 fragment.classList.add('fragment');
73 block.parentElement?.appendChild(fragment);
74 });
75
76 const deck = {
77 getPlugin: vi.fn().mockReturnValue({ highlightBlock }),
78 syncFragments: vi.fn(),
79 } as any;
80
81 const { container, rerender } = render(
82 <RevealContext.Provider value={deck}>
83 <section>
84 <Code lineNumbers="|1|2">{`console.log('one')`}</Code>
85 </section>
86 </RevealContext.Provider>
87 );
88
89 expect(container.querySelectorAll('pre > code.fragment')).toHaveLength(1);
90
91 rerender(
92 <RevealContext.Provider value={deck}>
93 <section>
94 <Code lineNumbers="|1|2">{`console.log('two')`}</Code>
95 </section>
96 </RevealContext.Provider>
97 );
98
99 expect(highlightBlock).toHaveBeenCalledTimes(2);
100 expect(container.querySelectorAll('pre > code.fragment')).toHaveLength(1);
101 expect(container.querySelector('pre > code:not(.fragment)')).toHaveTextContent(
102 "console.log('two')"
103 );
104 });
105
106 it('restores full line-number steps before rehighlighting after plugin mutation', () => {
107 const seenLineNumbers: string[] = [];
108 const highlightBlock = vi.fn((block: HTMLElement) => {
109 seenLineNumbers.push(block.getAttribute('data-line-numbers') || '');
110 block.setAttribute('data-highlighted', 'yes');
111
112 // Mimic RevealHighlight: original block is rewritten to the first step and
113 // an extra fragment block is appended for following steps.
114 block.setAttribute('data-line-numbers', '1');
115 const fragment = block.cloneNode(true) as HTMLElement;
116 fragment.classList.add('fragment');
117 fragment.setAttribute('data-line-numbers', '3');
118 block.parentElement?.appendChild(fragment);
119 });
120
121 const deck = {
122 getPlugin: vi.fn().mockReturnValue({ highlightBlock }),
123 syncFragments: vi.fn(),
124 } as any;
125
126 const { rerender } = render(
127 <RevealContext.Provider value={deck}>
128 <section>
129 <Code language="javascript" lineNumbers="1|3">{`console.log('one')`}</Code>
130 </section>
131 </RevealContext.Provider>
132 );
133
134 rerender(
135 <RevealContext.Provider value={deck}>
136 <section>
137 <Code language="ts" lineNumbers="1|3">{`console.log('one')`}</Code>
138 </section>
139 </RevealContext.Provider>
140 );
141
142 expect(seenLineNumbers).toEqual(['1|3', '1|3']);
143 });
144 });
145
145 lines Plain Text