11import { shallowMount , flushPromises } from '@vue/test-utils'
22import App from '../../src/App.vue'
33
4+ // mock XMLHttpRequest for templates loading
5+ global . XMLHttpRequest = class XMLHttpRequest {
6+ private responseText : string
7+ private status : number
8+
9+ open ( method , templatePath ) {
10+ const templateName = templatePath . split ( '/' ) . pop ( )
11+
12+ switch ( templateName ) {
13+ case 'cover-template.html' :
14+ this . status = 200
15+ this . responseText = `<script type="x-tmpl-mustache">
16+ <div class="content-container">
17+ <div class="logo">
18+ <img src="{{{ metadata.logo }}}" alt="Logo">
19+ </div>
20+
21+ <div class="content">
22+ <h1>{{{ title }}}</h1>
23+
24+ <p>
25+ By: {{{ metadata.presenter }}}
26+ </p>
27+
28+ </div>
29+ </div>
30+ </script>
31+ `
32+ break
33+ case 'title-content-template.html' :
34+ this . status = 200
35+ this . responseText = `<script type="x-tmpl-mustache">
36+ <div class="content-container">
37+ <div class="title">
38+ <h1>
39+
40+ {{{ title }}}
41+
42+ </h1>
43+ <div class="logo">
44+ <img src="{{{ metadata.logo }}}" alt="Logo">
45+ </div>
46+ </div>
47+
48+ <div class="content-wrapper">
49+ <div class="content">
50+
51+ {{{ content }}}
52+
53+ </div>
54+ </div>
55+ </div>
56+ <footer>
57+ <div class="footer-content">{{{ metadata.footer }}}</div>
58+ <div class="custom-slide-number"></div>
59+ </footer>
60+ </script>
61+ `
62+ break
63+ case 'title-content-image-template.html' :
64+ this . status = 200
65+ this . responseText = `<script type="x-tmpl-mustache">
66+ <div class="content-container">
67+ <div class="title">
68+ <h1>
69+
70+ {{{ title }}}
71+
72+ </h1>
73+ <div class="logo">
74+ <img src="{{{ metadata.logo }}}" alt="Logo">
75+ </div>
76+ </div>
77+
78+ <div class="content-wrapper">
79+ <div class="content">
80+
81+ {{{ content }}}
82+
83+ </div>
84+ </div>
85+ </div>
86+ <footer>
87+ <div class="footer-content">{{{ metadata.footer }}}</div>
88+ <div class="custom-slide-number"></div>
89+ </footer>
90+ </script>
91+ `
92+ break
93+ case 'about-us-template.html' :
94+ this . status = 200
95+ this . responseText = `<script type="x-tmpl-mustache">
96+ <div class="content-container">
97+ <div class="title">
98+ <h1>
99+
100+ {{{ title }}}
101+
102+ </h1>
103+ <div class="logo">
104+ <img src="{{{ metadata.logo }}}" alt="Logo">
105+ </div>
106+ </div>
107+
108+ <div class="content-wrapper">
109+ <div class="content">
110+ <div class="about-us-text">
111+
112+ {{{ content }}}
113+
114+ </div>
115+ <div class="info-section">
116+
117+ {{#metadata.aboutUs}}
118+ <div class="info-box">
119+ <h3>{{ title }}</h3>
120+ <p>{{ text }}</p>
121+ </div>
122+ <div class="divider"></div>
123+ {{/metadata.aboutUs}}
124+
125+ </div>
126+
127+ </div>
128+ </div>
129+ </div>
130+ <footer>
131+ <div class="footer-content">{{{ metadata.footer }}}</div>
132+ <div class="custom-slide-number"></div>
133+ </footer>
134+ </script>
135+ `
136+ break
137+ default :
138+ this . status = 404
139+ return '<p>Template for slide "' + templateName + '" not found.</p>'
140+ }
141+ }
142+
143+ send ( ) {
144+ return
145+ }
146+ }
147+
4148// mock modules
5149vi . mock ( '@ownclouders/web-pkg' , ( ) => ( {
6150 useAppDefaults : vi . fn ( ) . mockImplementation ( ( ) => ( {
@@ -35,7 +179,7 @@ vi.mock('@ownclouders/web-pkg', () => ({
35179 AppLoadingSpinner : vi . fn ( )
36180} ) )
37181// global mocks
38- global . fetch = vi . fn ( ) . mockImplementation ( ( ) =>
182+ const defaultFetchMock = vi . fn ( ) . mockImplementation ( ( ) =>
39183 Promise . resolve ( {
40184 text : ( ) =>
41185 Promise . resolve ( `### Slide 1
@@ -96,6 +240,7 @@ code block
96240 )
97241 } )
98242)
243+ global . fetch = defaultFetchMock
99244URL . createObjectURL = vi
100245 . fn ( )
101246 . mockImplementation ( ( ) => 'blob:nodedata:0295bafb-5976-468a-a263-685a8872cb96' )
@@ -113,3 +258,176 @@ function getWrapper() {
113258 propsData : { url : 'https://localhost:9200/slides.md' }
114259 } )
115260}
261+
262+ // eslint-disable-next-line require-await
263+ describe ( 'Template Features' , async ( ) => {
264+ beforeEach ( ( ) => {
265+ global . fetch = defaultFetchMock
266+ } )
267+
268+ it ( 'should return template not found error message' , async ( ) => {
269+ global . fetch = vi . fn ( ) . mockImplementation ( ( ) => {
270+ return Promise . resolve ( {
271+ text : ( ) =>
272+ Promise . resolve ( `---
273+ slide: non-existent
274+ ---
275+ ` ) ,
276+ blob : ( ) => Promise . resolve ( new Blob ( [ ] , { type : 'text/markdown' } ) )
277+ } )
278+ } )
279+ const vm = getWrapper ( )
280+ await flushPromises ( )
281+ expect ( vm . html ( ) ) . toContain ( 'Template for slide "non-existent" not found.' )
282+ } )
283+
284+ it ( 'should return yaml parsing error' , async ( ) => {
285+ const errorSpy = vi . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } )
286+ global . fetch = vi . fn ( ) . mockImplementation ( ( ) => {
287+ return Promise . resolve ( {
288+ text : ( ) =>
289+ Promise . resolve ( `---
290+ slide: title-content
291+ logo: [invalid yaml
292+ ---
293+ ` ) ,
294+ blob : ( ) => Promise . resolve ( new Blob ( [ ] , { type : 'text/markdown' } ) )
295+ } )
296+ } )
297+
298+ const vm = getWrapper ( )
299+ await flushPromises ( )
300+ expect ( errorSpy ) . toHaveBeenCalled ( )
301+ expect ( vm . html ( ) ) . toContain (
302+ 'YAMLException: unexpected end of the stream within a flow collection at line 3, column 1'
303+ )
304+ } )
305+
306+ it ( 'should render cover template' , async ( ) => {
307+ global . fetch = vi . fn ( ) . mockImplementation ( ( ) => {
308+ return Promise . resolve ( {
309+ text : ( ) =>
310+ Promise . resolve ( `---
311+ slide: title-content
312+ presenter: John Doe
313+ logo: https://external:9200/cat.jpg
314+ ---
315+ # Reveal Js Templates in Web App Presentation Viewer ::slide:cover
316+ ` ) ,
317+ blob : ( ) => Promise . resolve ( new Blob ( [ ] , { type : 'text/markdown' } ) )
318+ } )
319+ } )
320+ const vm = getWrapper ( )
321+ await flushPromises ( )
322+ await vi . waitFor (
323+ ( ) => {
324+ expect ( vm . classes ( 'md-template' ) ) . toBe ( true )
325+ } ,
326+ { timeout : 1000 }
327+ )
328+ expect ( vm . find ( '.reveal .slides' ) . html ( ) ) . toMatchSnapshot ( )
329+ } )
330+
331+ it ( 'should render title content template' , async ( ) => {
332+ global . fetch = vi . fn ( ) . mockImplementation ( ( ) => {
333+ return Promise . resolve ( {
334+ text : ( ) =>
335+ Promise . resolve ( `---
336+ slide: title-content
337+ presenter: John Doe
338+ logo: https://external:9200/cat.jpg
339+ ---
340+ # Title Content Slide
341+
342+ - Introduction to mountain ecosystems
343+ - Basic concepts of quantum encryption
344+ - Exploring culinary traditions in Southeast Asia
345+ - Overview of blockchain consensus mechanisms
346+ - Setting up a personal productivity system
347+ - Writing clean, maintainable JavaScript code
348+ - Understanding modern art movements
349+ - History of aviation and early flight experiments
350+ - Managing team dynamics in remote work
351+ ` ) ,
352+ blob : ( ) => Promise . resolve ( new Blob ( [ ] , { type : 'text/markdown' } ) )
353+ } )
354+ } )
355+ const vm = getWrapper ( )
356+ await flushPromises ( )
357+ await vi . waitFor (
358+ ( ) => {
359+ expect ( vm . classes ( 'md-template' ) ) . toBe ( true )
360+ } ,
361+ { timeout : 1000 }
362+ )
363+ expect ( vm . find ( '.reveal .slides' ) . html ( ) ) . toMatchSnapshot ( )
364+ } )
365+
366+ it ( 'should render title content image template' , async ( ) => {
367+ global . fetch = vi . fn ( ) . mockImplementation ( ( ) => {
368+ return Promise . resolve ( {
369+ text : ( ) =>
370+ Promise . resolve ( `---
371+ slide: title-content
372+ presenter: John Doe
373+ logo: https://external:9200/cat.jpg
374+ ---
375+ # Title Content Image Slide ::slide:title-content-image
376+
377+ - Introduction to mountain ecosystems
378+ - Basic concepts of quantum encryption
379+ - Exploring culinary traditions in Southeast Asia
380+ - Overview of blockchain consensus mechanisms
381+
382+ 
383+ ` ) ,
384+ blob : ( ) => Promise . resolve ( new Blob ( [ ] , { type : 'text/markdown' } ) )
385+ } )
386+ } )
387+ const vm = getWrapper ( )
388+ await flushPromises ( )
389+ await vi . waitFor (
390+ ( ) => {
391+ expect ( vm . classes ( 'md-template' ) ) . toBe ( true )
392+ } ,
393+ { timeout : 1000 }
394+ )
395+ expect ( vm . find ( '.reveal .slides' ) . html ( ) ) . toMatchSnapshot ( )
396+ } )
397+
398+ it ( 'should render about us template' , async ( ) => {
399+ global . fetch = vi . fn ( ) . mockImplementation ( ( ) => {
400+ return Promise . resolve ( {
401+ text : ( ) =>
402+ Promise . resolve ( `---
403+ slide: title-content
404+ presenter: John Doe
405+ logo: https://external:9200/cat.jpg
406+ aboutUs:
407+ - title: WWW
408+ text: www.example.com
409+ - title: LINKEDIN
410+ text: www.linkedin.com/company/example
411+ - title: FACEBOOK
412+ text: www.facebook.com/example
413+ - title: X
414+ text: www.x.com/example
415+ ---
416+ # About Us ::slide:about-us
417+
418+ Some content about us.
419+ ` ) ,
420+ blob : ( ) => Promise . resolve ( new Blob ( [ ] , { type : 'text/markdown' } ) )
421+ } )
422+ } )
423+ const vm = getWrapper ( )
424+ await flushPromises ( )
425+ await vi . waitFor (
426+ ( ) => {
427+ expect ( vm . classes ( 'md-template' ) ) . toBe ( true )
428+ } ,
429+ { timeout : 1000 }
430+ )
431+ expect ( vm . find ( '.reveal .slides' ) . html ( ) ) . toMatchSnapshot ( )
432+ } )
433+ } )
0 commit comments