Skip to content

Commit 4ff7e03

Browse files
committed
add tests
Signed-off-by: Prajwol Amatya <prajwolamatya11@gmail.com>
1 parent eb5f5ee commit 4ff7e03

File tree

3 files changed

+466
-1
lines changed

3 files changed

+466
-1
lines changed

package.json

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"name": "mdpresentation-viewer",
3+
"version": "2.1.0",
4+
"description": "Markdown Presentation Viewer for OpenCloud and ownCloud Web",
5+
"license": "Apache-2.0",
6+
"private": true,
7+
"type": "module",
8+
"scripts": {
9+
"build": "pnpm vite build",
10+
"build:w": "pnpm vite build --watch --mode development",
11+
"lint": "eslint './*.{js,cjs,mjs,ts}' '{src,tests}/**/*.{js,cjs,mjs,ts,vue}' --color",
12+
"lint:fix": "pnpm lint --fix",
13+
"test:unit": "vitest",
14+
"test:e2e": "NODE_TLS_REJECT_UNAUTHORIZED=0 cucumber-js"
15+
},
16+
"dependencies": {
17+
"@types/reveal.js": "^4.4.8",
18+
"reveal.js": "^5.1.0",
19+
"reveal.js-mermaid-plugin": "^11.4.1",
20+
"revealjs-awesomd": "github:opf/revealjs-awesoMD#handle-yaml-error"
21+
},
22+
"devDependencies": {
23+
"@babel/eslint-parser": "^7.24.5",
24+
"@cucumber/cucumber": "^10.6.0",
25+
"@cucumber/pretty-formatter": "^1.0.1",
26+
"@ownclouders/extension-sdk": "^11.3.1",
27+
"@ownclouders/prettier-config": "0.0.1",
28+
"@playwright/test": "^1.44.0",
29+
"@types/node": "^20.12.10",
30+
"@typescript-eslint/eslint-plugin": "^7.8.0",
31+
"@vitejs/plugin-vue": "^5.0.5",
32+
"@vitest/coverage-v8": "1.6.1",
33+
"@vue/test-utils": "^2.4.6",
34+
"axios": "^1.8.2",
35+
"eslint": "^8.57.0",
36+
"eslint-config-prettier": "^9.1.0",
37+
"eslint-plugin-prettier-vue": "^5.0.0",
38+
"eslint-plugin-unused-imports": "^3.2.0",
39+
"eslint-plugin-vue": "^9.25.0",
40+
"happy-dom": "^15.10.2",
41+
"typescript": "^5.4.5",
42+
"vite": "^5.2.11",
43+
"vitest": "^1.6.1",
44+
"vue": "^3.5.11"
45+
},
46+
"pnpm": {
47+
"peerDependencyRules": {
48+
"ignoreMissing": [
49+
"design-system"
50+
]
51+
}
52+
},
53+
"packageManager": "pnpm@8.15.1",
54+
"peerDependencies": {
55+
"@ownclouders/web-client": "^11.3.1",
56+
"@ownclouders/web-pkg": "^11.3.1"
57+
}
58+
}

tests/unit/App.spec.ts

Lines changed: 231 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,150 @@
11
import { shallowMount, flushPromises } from '@vue/test-utils'
22
import 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
5149
vi.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
99244
URL.createObjectURL = vi
100245
.fn()
101246
.mockImplementation(() => 'blob:nodedata:0295bafb-5976-468a-a263-685a8872cb96')
@@ -113,3 +258,88 @@ 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 render slides with templates', async () => {
269+
global.fetch = vi.fn().mockImplementation(() => {
270+
return Promise.resolve({
271+
text: () =>
272+
Promise.resolve(`---
273+
slide: title-content
274+
presenter: John Doe
275+
logo: https://external:9200/cat.jpg
276+
aboutUs:
277+
- title: WWW
278+
text: www.example.com
279+
- title: LINKEDIN
280+
text: www.linkedin.com/company/example
281+
- title: FACEBOOK
282+
text: www.facebook.com/example
283+
- title: X
284+
text: www.x.com/example
285+
color: "#000"
286+
---
287+
# Reveal js Templates in Web App Presentation Viewer ::slide:cover
288+
289+
---
290+
291+
# Title Content Slide
292+
293+
- Introduction to mountain ecosystems
294+
- Basic concepts of quantum encryption
295+
- Exploring culinary traditions in Southeast Asia
296+
- Overview of blockchain consensus mechanisms
297+
- Setting up a personal productivity system
298+
- Writing clean, maintainable JavaScript code
299+
- Understanding modern art movements
300+
- History of aviation and early flight experiments
301+
- Managing team dynamics in remote work
302+
303+
---
304+
305+
# Title Content Image Slide ::slide:title-content-image
306+
307+
- Introduction to mountain ecosystems
308+
- Basic concepts of quantum encryption
309+
- Exploring culinary traditions in Southeast Asia
310+
- Overview of blockchain consensus mechanisms
311+
312+
![cat](https://external:9200/cat.jpg)
313+
314+
---
315+
316+
# About Us ::slide:about-us
317+
318+
Some content about us.
319+
`),
320+
blob: () => Promise.resolve(new Blob([], { type: 'text/markdown' }))
321+
})
322+
})
323+
324+
const vm = getWrapper()
325+
await flushPromises()
326+
await new Promise((resolve) => setTimeout(resolve, 100))
327+
expect(vm.html()).toMatchSnapshot()
328+
})
329+
330+
it('should return template not found error message', async () => {
331+
global.fetch = vi.fn().mockImplementation(() => {
332+
return Promise.resolve({
333+
text: () =>
334+
Promise.resolve(`---
335+
slide: non-existent
336+
---
337+
`),
338+
blob: () => Promise.resolve(new Blob([], { type: 'text/markdown' }))
339+
})
340+
})
341+
const vm = getWrapper()
342+
await flushPromises()
343+
expect(vm.html()).toContain('Template for slide "non-existent" not found.')
344+
})
345+
})

0 commit comments

Comments
 (0)