11import { describe , expect , test } from 'vitest' ;
22
3- import { getSlideTitle , splitBlocksIntoSlides } from '../hooks/useSlides' ;
3+ import {
4+ getContentSlideIndexForBlock ,
5+ getSlideTitle ,
6+ splitBlocksIntoSlides ,
7+ } from '../hooks/useSlides' ;
48import type { PresenterBlock } from '../types' ;
59
610type TestBlock = PresenterBlock ;
@@ -23,13 +27,14 @@ const textContent = (text: string) => ({
2327 type : 'text' as const ,
2428} ) ;
2529
26- const para = ( text = 'hello' ) : TestBlock =>
30+ const para = ( text = 'hello' , id ?: string ) : TestBlock =>
2731 block ( 'paragraph' , {
2832 content : text === '' ? [ ] : [ textContent ( text ) ] ,
33+ ...( id ? { id } : { } ) ,
2934 } ) ;
3035
31- const divider = ( children : TestBlock [ ] = [ ] ) : TestBlock =>
32- block ( 'divider' , { children } ) ;
36+ const divider = ( children : TestBlock [ ] = [ ] , id ?: string ) : TestBlock =>
37+ block ( 'divider' , { children, ... ( id ? { id } : { } ) } ) ;
3338
3439const image = ( ) : TestBlock => block ( 'image' , { props : { url : 'x' } } ) ;
3540
@@ -201,6 +206,134 @@ describe('splitBlocksIntoSlides', () => {
201206 } ) ;
202207} ) ;
203208
209+ describe ( 'getContentSlideIndexForBlock' , ( ) => {
210+ test ( 'returns the slide containing a regular block' , ( ) => {
211+ expect (
212+ getContentSlideIndexForBlock (
213+ [ para ( 'a' , 'a' ) , divider ( ) , para ( 'b' , 'b' ) , para ( 'c' , 'c' ) ] ,
214+ 'c' ,
215+ ) ,
216+ ) . toBe ( 1 ) ;
217+ } ) ;
218+
219+ test ( 'returns the following slide for a divider' , ( ) => {
220+ expect (
221+ getContentSlideIndexForBlock (
222+ [ para ( 'a' , 'a' ) , divider ( undefined , 'divider' ) , para ( 'b' , 'b' ) ] ,
223+ 'divider' ,
224+ ) ,
225+ ) . toBe ( 1 ) ;
226+ } ) ;
227+
228+ test ( 'returns the first non-empty following slide for consecutive dividers' , ( ) => {
229+ expect (
230+ getContentSlideIndexForBlock (
231+ [
232+ para ( 'a' , 'a' ) ,
233+ divider ( undefined , 'first-divider' ) ,
234+ divider ( undefined , 'second-divider' ) ,
235+ para ( 'b' , 'b' ) ,
236+ ] ,
237+ 'first-divider' ,
238+ ) ,
239+ ) . toBe ( 1 ) ;
240+ } ) ;
241+
242+ test ( 'skips empty-only slides after dividers when mapping divider links' , ( ) => {
243+ expect (
244+ getContentSlideIndexForBlock (
245+ [
246+ para ( 'a' , 'a' ) ,
247+ divider ( undefined , 'first-divider' ) ,
248+ para ( '' , 'empty-after-divider' ) ,
249+ divider ( undefined , 'second-divider' ) ,
250+ para ( 'b' , 'b' ) ,
251+ ] ,
252+ 'first-divider' ,
253+ ) ,
254+ ) . toBe ( 1 ) ;
255+ } ) ;
256+
257+ test ( 'maps a stripped empty block after a divider to the following content slide' , ( ) => {
258+ expect (
259+ getContentSlideIndexForBlock (
260+ [
261+ para ( 'a' , 'a' ) ,
262+ divider ( undefined , 'divider' ) ,
263+ para ( '' , 'empty-after-divider' ) ,
264+ para ( 'b' , 'b' ) ,
265+ ] ,
266+ 'empty-after-divider' ,
267+ ) ,
268+ ) . toBe ( 1 ) ;
269+ } ) ;
270+
271+ test ( 'maps a stripped empty block before a divider to the previous content slide' , ( ) => {
272+ expect (
273+ getContentSlideIndexForBlock (
274+ [
275+ para ( 'a' , 'a' ) ,
276+ para ( '' , 'empty-before-divider' ) ,
277+ divider ( undefined , 'divider' ) ,
278+ para ( 'b' , 'b' ) ,
279+ ] ,
280+ 'empty-before-divider' ,
281+ ) ,
282+ ) . toBe ( 0 ) ;
283+ } ) ;
284+
285+ test ( 'maps a stripped empty-only slide to the next rendered content slide' , ( ) => {
286+ expect (
287+ getContentSlideIndexForBlock (
288+ [
289+ para ( 'a' , 'a' ) ,
290+ divider ( undefined , 'first-divider' ) ,
291+ para ( '' , 'empty-between-dividers' ) ,
292+ divider ( undefined , 'second-divider' ) ,
293+ para ( 'b' , 'b' ) ,
294+ ] ,
295+ 'empty-between-dividers' ,
296+ ) ,
297+ ) . toBe ( 1 ) ;
298+ } ) ;
299+
300+ test ( 'maps a leading divider to the first content slide' , ( ) => {
301+ expect (
302+ getContentSlideIndexForBlock (
303+ [ divider ( undefined , 'divider' ) , para ( 'a' , 'a' ) ] ,
304+ 'divider' ,
305+ ) ,
306+ ) . toBe ( 0 ) ;
307+ } ) ;
308+
309+ test ( 'maps a trailing divider to the last rendered content slide' , ( ) => {
310+ expect (
311+ getContentSlideIndexForBlock (
312+ [ para ( 'a' , 'a' ) , divider ( undefined , 'divider' ) ] ,
313+ 'divider' ,
314+ ) ,
315+ ) . toBe ( 0 ) ;
316+ } ) ;
317+
318+ test ( 'finds blocks nested under a structural divider' , ( ) => {
319+ expect (
320+ getContentSlideIndexForBlock (
321+ [ para ( 'a' , 'a' ) , divider ( [ para ( 'nested' , 'nested' ) ] , 'divider' ) ] ,
322+ 'nested' ,
323+ ) ,
324+ ) . toBe ( 1 ) ;
325+ } ) ;
326+
327+ test ( 'returns the first content slide when the block is missing' , ( ) => {
328+ expect (
329+ getContentSlideIndexForBlock (
330+ [ para ( 'a' , 'a' ) , divider ( ) , para ( 'b' , 'b' ) ] ,
331+ 'x' ,
332+ ) ,
333+ ) . toBe ( 0 ) ;
334+ } ) ;
335+ } ) ;
336+
204337const heading = ( text : string ) : TestBlock =>
205338 block ( 'heading' , { content : [ textContent ( text ) ] } ) ;
206339
0 commit comments