fcad-core-dragon 2.1.2 → 2.2.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitlab-ci.yml +24 -42
- package/.vscode/settings.json +0 -30
- package/CHANGELOG +9 -0
- package/artifacts/playwright-report/index.html +85 -0
- package/package.json +29 -26
- package/src/components/AppBasePage.vue +3 -8
- package/src/components/AppCompAudio.vue +3 -3
- package/src/components/AppCompInputCheckBoxNx.vue +2 -1
- package/src/components/AppCompInputDropdownNx.vue +5 -5
- package/src/components/AppCompInputRadioNx.vue +2 -1
- package/src/components/AppCompInputTextNx.vue +0 -2
- package/src/components/AppCompInputTextTableNx.vue +4 -4
- package/src/components/AppCompInputTextToFillDropdownNx.vue +4 -6
- package/src/components/AppCompInputTextToFillNx.vue +1 -24
- package/src/components/AppCompPlayBarNext.vue +6 -8
- package/src/components/AppCompQuizRecall.vue +12 -2
- package/src/components/AppCompVideoPlayer.vue +2 -1
- package/src/main.js +18 -5
- package/src/plugins/i18n.js +8 -6
- package/tests/unit/AppCompAudio.spec.js +134 -0
- package/tests/unit/AppCompCarousel.spec.js +54 -0
- package/tests/unit/AppCompNoteCredit.spec.js +58 -0
- package/tests/unit/AppCompQuizNext.spec.js +1 -3
- package/tests/unit/AppCompVideoPlayer.spec.js +92 -100
- package/tests/unit/useQuiz.spec.js +72 -0
- package/vitest.config.js +36 -22
- package/vitest.setup.js +68 -0
- package/junit-report.xml +0 -182
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils'
|
|
2
|
+
import AppCompCarousel from '@/components/AppCompCarousel.vue'
|
|
3
|
+
import AppBaseButton from '@/components/AppBaseButton.vue'
|
|
4
|
+
import { beforeEach, describe, expect, it } from 'vitest'
|
|
5
|
+
|
|
6
|
+
const dummyProps = {
|
|
7
|
+
slides: [
|
|
8
|
+
{
|
|
9
|
+
imgSrc: 'https://loremflickr.com/500/500/kitten?random=1',
|
|
10
|
+
imgAlt: 'ceci est un chat',
|
|
11
|
+
title: 'Mon premier chat',
|
|
12
|
+
hypertext:
|
|
13
|
+
'<h3>Test</h3><p>Voici un texte de test pour le premier chat.</p>'
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
imgSrc: 'https://loremflickr.com/500/500/kitten?random=10',
|
|
17
|
+
imgAlt: 'ceci est un autre chat',
|
|
18
|
+
title: 'Le deuxième chat',
|
|
19
|
+
hypertext: ''
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
imgSrc: 'https://loremflickr.com/500/500/kitten?random=100',
|
|
23
|
+
imgAlt: 'ceci est un encore chat',
|
|
24
|
+
title: 'Le troisième chat',
|
|
25
|
+
hypertext: ''
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
name: 'Mon super carousel'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe('AppCompCarousel.vue', () => {
|
|
32
|
+
let wrapper = null
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
wrapper = mount(AppCompCarousel, {
|
|
35
|
+
props: dummyProps
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it(`displays the good amount of images`, () => {
|
|
40
|
+
expect(wrapper.findAll('img').length).toBe(dummyProps.slides.length)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('renders two appBaseButton components as controls', () => {
|
|
44
|
+
const btnComponents = wrapper.findAllComponents(AppBaseButton)
|
|
45
|
+
expect(btnComponents.length).toBe(2)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('updates the slide counter after nextSlide click', async () => {
|
|
49
|
+
const btnNext = wrapper.findAllComponents(AppBaseButton)[1]
|
|
50
|
+
await btnNext.trigger('click')
|
|
51
|
+
const counterTxt = wrapper.get('.carousel-index').text()
|
|
52
|
+
expect(counterTxt).toBe('2 / 3')
|
|
53
|
+
})
|
|
54
|
+
})
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils'
|
|
2
|
+
import AppCompNoteCredit from '../../src/components/AppCompNoteCredit.vue'
|
|
3
|
+
import { beforeEach, describe, expect, vi, test } from 'vitest'
|
|
4
|
+
|
|
5
|
+
const dummyProps = [
|
|
6
|
+
{
|
|
7
|
+
id: 'nt_1',
|
|
8
|
+
text: `note 1`
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: 'nt_2',
|
|
12
|
+
text: `note 2`
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
describe('AppCompNoteCredit', () => {
|
|
17
|
+
let wrapper = null
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
vi.mock('@/shared/generalfuncs.js', () => ({
|
|
21
|
+
fileAssets: { getActivities: () => [] }
|
|
22
|
+
}))
|
|
23
|
+
|
|
24
|
+
vi.mock('@/router/routes.js', () => ({
|
|
25
|
+
mappedFiles: []
|
|
26
|
+
}))
|
|
27
|
+
|
|
28
|
+
vi.mock('@/stores/myStore', () => ({
|
|
29
|
+
useMyStore: vi.fn(() => ({
|
|
30
|
+
getDataNoteCredit: dummyProps,
|
|
31
|
+
getAllActivities: 'A01',
|
|
32
|
+
getCurrentPage: 'P01'
|
|
33
|
+
}))
|
|
34
|
+
}))
|
|
35
|
+
|
|
36
|
+
wrapper = mount(AppCompNoteCredit, {
|
|
37
|
+
global: {
|
|
38
|
+
stubs: {
|
|
39
|
+
'app-base-button': true,
|
|
40
|
+
'app-base-error-display': true
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('It renders a the pop-up', () => {
|
|
47
|
+
const wrapper = mount(AppCompNoteCredit)
|
|
48
|
+
|
|
49
|
+
expect(wrapper.exists()).toBe(true)
|
|
50
|
+
|
|
51
|
+
const div = wrapper.find('#noteCredit')
|
|
52
|
+
expect(div.exists()).toBe(true)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('It renders a list of ${dummyProps.length}', () => {
|
|
56
|
+
expect(wrapper.findAll('div').length).toBe(dummyProps.length)
|
|
57
|
+
})
|
|
58
|
+
})
|
|
@@ -77,7 +77,7 @@ describe('AppCompQuizNext', () => {
|
|
|
77
77
|
expect(wrapper.find('.stub-radio').exists()).toBe(true)
|
|
78
78
|
})
|
|
79
79
|
|
|
80
|
-
// it('rend un input texte si la question est de type text', () => {
|
|
80
|
+
// it('rend un input texte si la question est de type text', async() => {
|
|
81
81
|
// const wrapper = mount(AppCompQuizNext, {
|
|
82
82
|
// props: {
|
|
83
83
|
// question: {
|
|
@@ -88,7 +88,6 @@ describe('AppCompQuizNext', () => {
|
|
|
88
88
|
// },
|
|
89
89
|
// global: { stubs }
|
|
90
90
|
// })
|
|
91
|
-
|
|
92
91
|
// expect(wrapper.find('.stub-text').exists()).toBe(true)
|
|
93
92
|
// })
|
|
94
93
|
|
|
@@ -106,7 +105,6 @@ describe('AppCompQuizNext', () => {
|
|
|
106
105
|
// }
|
|
107
106
|
// }
|
|
108
107
|
// })
|
|
109
|
-
|
|
110
108
|
// await wrapper.find('input').trigger('input')
|
|
111
109
|
|
|
112
110
|
// expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['hello'])
|
|
@@ -1,104 +1,37 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
],
|
|
29
|
-
mSubtitles: [
|
|
30
|
-
{
|
|
31
|
-
label: 'Français',
|
|
32
|
-
src: 'exemple_soustitres.vtt',
|
|
33
|
-
srclang: 'fr'
|
|
34
|
-
}
|
|
35
|
-
],
|
|
36
|
-
mPoster: 'video_poster.jpg',
|
|
37
|
-
mTranscript: 'exemple_transcript.html' // The file MUST be host in the public folder of the project
|
|
38
|
-
}
|
|
39
|
-
]
|
|
40
|
-
}
|
|
41
|
-
vi.mock('@/shared/generalfuncs.js', () => ({
|
|
42
|
-
fileAssets: { getActivities: () => [] }
|
|
43
|
-
}))
|
|
44
|
-
|
|
45
|
-
vi.mock('@/shared/validators.js', () => ({
|
|
46
|
-
validateObjType: () => true,
|
|
47
|
-
validateString: () => true,
|
|
48
|
-
validateVideoData: vi.fn(),
|
|
49
|
-
validateNumber: () => true
|
|
50
|
-
}))
|
|
51
|
-
|
|
52
|
-
vi.mock('@/module/stores/appStore', () => {
|
|
53
|
-
return {
|
|
54
|
-
useAppStore: () => ({
|
|
55
|
-
getCurrentPage: {
|
|
56
|
-
id: 'P01',
|
|
57
|
-
activityRef: 'A01',
|
|
58
|
-
videosData: [
|
|
59
|
-
{
|
|
60
|
-
id: 'vid1',
|
|
61
|
-
mSources: [
|
|
62
|
-
{
|
|
63
|
-
type: 'mp4',
|
|
64
|
-
src: ''
|
|
65
|
-
}
|
|
66
|
-
],
|
|
67
|
-
mSubtitles: [
|
|
68
|
-
{
|
|
69
|
-
label: 'Français',
|
|
70
|
-
src: '',
|
|
71
|
-
srclang: 'fr'
|
|
72
|
-
}
|
|
73
|
-
],
|
|
74
|
-
mPoster: '',
|
|
75
|
-
mTranscript: 'exemple_transcript.html' // The file MUST be host in the public folder of the project
|
|
76
|
-
}
|
|
77
|
-
]
|
|
78
|
-
},
|
|
79
|
-
getPageInteraction: () => ({ ...dummyProps }),
|
|
80
|
-
getUserInteraction: () => ({ ...dummyProps })
|
|
81
|
-
})
|
|
2
|
+
import { describe, it, test, expect } from 'vitest'
|
|
3
|
+
|
|
4
|
+
let dummyProps = {
|
|
5
|
+
id: 'P01',
|
|
6
|
+
activityRef: 'A03',
|
|
7
|
+
title: 'Lecteurs médias',
|
|
8
|
+
type: 'pg_normal',
|
|
9
|
+
videosData: [
|
|
10
|
+
{
|
|
11
|
+
id: 'vid1',
|
|
12
|
+
mSources: [
|
|
13
|
+
{
|
|
14
|
+
type: 'mp4',
|
|
15
|
+
src: 'exemple_video.mp4'
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
mSubtitles: [
|
|
19
|
+
{
|
|
20
|
+
label: 'Français',
|
|
21
|
+
src: 'exemple_soustitres.vtt',
|
|
22
|
+
srclang: 'fr'
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
mPoster: 'video_poster.jpg',
|
|
26
|
+
mTranscript: 'exemple_transcript.html' // The file MUST be host in the public folder of the project
|
|
82
27
|
}
|
|
83
|
-
|
|
84
|
-
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
85
30
|
|
|
86
31
|
import AppCompVideoPlayer from '@/components/AppCompVideoPlayer.vue'
|
|
87
|
-
// import AppBaseErrorDisplay from '@/components/AppBaseErrorDisplay.vue'
|
|
88
32
|
import { validateVideoData } from '@/shared/validators.js'
|
|
89
33
|
|
|
90
34
|
describe('AppCompVideoPlayer', () => {
|
|
91
|
-
const stubs = {
|
|
92
|
-
AppBaseErrorDisplay: {
|
|
93
|
-
name: 'AppBaseErrorDisplay',
|
|
94
|
-
template: '<div class="stub-error"></div>',
|
|
95
|
-
props: {
|
|
96
|
-
/* ... (props omises pour la clarté) ... */
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
AppBaseSkeleton: { template: '<div class="stub-skeleton"></div>' },
|
|
100
|
-
AppBaseButton: { template: '<button class="stub-button"></button>' }
|
|
101
|
-
}
|
|
102
35
|
test('Validate received props', () => {
|
|
103
36
|
validateVideoData.mockReturnValue([])
|
|
104
37
|
const { videosData } = dummyProps
|
|
@@ -133,8 +66,7 @@ describe('AppCompVideoPlayer', () => {
|
|
|
133
66
|
])
|
|
134
67
|
|
|
135
68
|
const wrapper = mount(AppCompVideoPlayer, {
|
|
136
|
-
props: { vidData: { id: null } }
|
|
137
|
-
global: { stubs, plugins: [createTestingPinia({ createSpy: vi.fn })] }
|
|
69
|
+
props: { vidData: { id: null } }
|
|
138
70
|
})
|
|
139
71
|
|
|
140
72
|
expect(
|
|
@@ -146,8 +78,7 @@ describe('AppCompVideoPlayer', () => {
|
|
|
146
78
|
it('It renders HTML video Element', () => {
|
|
147
79
|
validateVideoData.mockReturnValue([]) // no Error
|
|
148
80
|
const wrapper = mount(AppCompVideoPlayer, {
|
|
149
|
-
props: { vidData: { id: null } }
|
|
150
|
-
global: { stubs }
|
|
81
|
+
props: { vidData: { id: null } }
|
|
151
82
|
})
|
|
152
83
|
expect(
|
|
153
84
|
wrapper.findComponent({ name: 'AppBaseErrorDisplay' }).exists()
|
|
@@ -159,8 +90,7 @@ describe('AppCompVideoPlayer', () => {
|
|
|
159
90
|
const { videosData } = dummyProps
|
|
160
91
|
validateVideoData.mockReturnValue([]) // no Error
|
|
161
92
|
const wrapper = mount(AppCompVideoPlayer, {
|
|
162
|
-
props: { vidData: videosData[0] }
|
|
163
|
-
global: { stubs }
|
|
93
|
+
props: { vidData: videosData[0] }
|
|
164
94
|
})
|
|
165
95
|
|
|
166
96
|
expect(wrapper.vm.vidSources).toEqual(videosData[0].mSources)
|
|
@@ -174,4 +104,66 @@ describe('AppCompVideoPlayer', () => {
|
|
|
174
104
|
expect(sources[0].attributes().src).toBe(videosData[0].mSources[0].src)
|
|
175
105
|
expect(sources[0].attributes().type).toBe('video/mp4')
|
|
176
106
|
})
|
|
107
|
+
|
|
108
|
+
it('computed $vidElement returns correct data structure', async () => {
|
|
109
|
+
const { videosData } = dummyProps
|
|
110
|
+
validateVideoData.mockReturnValue([])
|
|
111
|
+
|
|
112
|
+
const wrapper = mount(AppCompVideoPlayer, {
|
|
113
|
+
props: { vidData: videosData[0] }
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
// Simulate refs
|
|
117
|
+
const mockVideoRef = { tagName: 'VIDEO' }
|
|
118
|
+
const mockContainerRef = { className: '__media-container' }
|
|
119
|
+
|
|
120
|
+
wrapper.vm.$refs['m-video'] = mockVideoRef
|
|
121
|
+
wrapper.vm.$refs['$media-container'] = mockContainerRef
|
|
122
|
+
|
|
123
|
+
// Simulate refs isSet (video ready) to true
|
|
124
|
+
wrapper.vm.isSet = true
|
|
125
|
+
await wrapper.vm.$nextTick()
|
|
126
|
+
|
|
127
|
+
// get vidElement object
|
|
128
|
+
const obj = wrapper.vm.$vidElement
|
|
129
|
+
const id = wrapper.vm.$props.vidData.id
|
|
130
|
+
|
|
131
|
+
// expected data structure to be returned
|
|
132
|
+
const vidElement = {
|
|
133
|
+
id,
|
|
134
|
+
mType: 'video',
|
|
135
|
+
mElement: { id, localName: 'video' },
|
|
136
|
+
mMediaContainer: {
|
|
137
|
+
id: `video_${id}`,
|
|
138
|
+
...mockContainerRef,
|
|
139
|
+
localName: 'section'
|
|
140
|
+
},
|
|
141
|
+
mTranscript: 'exemple_transcript.html',
|
|
142
|
+
mSubtitles: [
|
|
143
|
+
{
|
|
144
|
+
label: 'Français',
|
|
145
|
+
src: 'exemple_soustitres.vtt',
|
|
146
|
+
srclang: 'fr'
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
// validate returned object
|
|
151
|
+
expect(obj.id).toEqual(vidElement.id)
|
|
152
|
+
expect(obj.mType).toBe(vidElement.mType)
|
|
153
|
+
expect(obj.mElement.id).toBe(vidElement.mElement.id)
|
|
154
|
+
expect(obj.mElement.tagName.toLowerCase()).toBe(
|
|
155
|
+
vidElement.mElement.localName
|
|
156
|
+
)
|
|
157
|
+
expect(obj.mMediaContainer.tagName.toLowerCase()).toBe(
|
|
158
|
+
vidElement.mMediaContainer.localName
|
|
159
|
+
)
|
|
160
|
+
expect(obj.mMediaContainer.id).toBe(vidElement.mMediaContainer.id)
|
|
161
|
+
expect(
|
|
162
|
+
obj.mMediaContainer.classList.contains(
|
|
163
|
+
vidElement.mMediaContainer.className
|
|
164
|
+
)
|
|
165
|
+
).toBe(true)
|
|
166
|
+
expect(obj.mTranscript).toBe(vidElement.mTranscript)
|
|
167
|
+
expect(obj.mSubtitles).toEqual(vidElement.mSubtitles)
|
|
168
|
+
})
|
|
177
169
|
})
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { useQuiz } from '../../src/composables/useQuiz.js'
|
|
3
|
+
|
|
4
|
+
// Mock de useI18n pour éviter les erreurs liées à $t()
|
|
5
|
+
vi.mock('vue-i18n', () => ({
|
|
6
|
+
useI18n: () => ({ t: (key) => key })
|
|
7
|
+
}))
|
|
8
|
+
|
|
9
|
+
describe('useQuiz composable', () => {
|
|
10
|
+
const { shuffleArray, addRetroStyle, resetRetroStyle, retroType } = useQuiz()
|
|
11
|
+
|
|
12
|
+
it('shuffleArray should shuffle array without losing elements', () => {
|
|
13
|
+
const arr = [1, 2, 3, 4]
|
|
14
|
+
const shuffled = shuffleArray(arr)
|
|
15
|
+
expect(shuffled).toHaveLength(arr.length)
|
|
16
|
+
expect(shuffled.sort()).toEqual(arr.sort())
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('addRetroStyle should return correct classes and messages for correct answers', () => {
|
|
20
|
+
const solution = [{ id: 1 }, { id: 2 }]
|
|
21
|
+
const reponse = [{ correct: true }, { correct: true }]
|
|
22
|
+
const result = addRetroStyle(solution, reponse, reponse.length)
|
|
23
|
+
expect(result.classRetro).toEqual(['goodAnswer', 'goodAnswer'])
|
|
24
|
+
expect(result.mesA11y).toEqual([
|
|
25
|
+
'quizState.goodAnswer',
|
|
26
|
+
'quizState.goodAnswer'
|
|
27
|
+
])
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('addRetroStyle should return neutral style when solution is null', () => {
|
|
31
|
+
const result = addRetroStyle(null, [], 0)
|
|
32
|
+
expect(result.classRetro).toEqual(['NeutralAnswer'])
|
|
33
|
+
expect(result.mesA11y).toEqual(['quizState.neutralAnswer'])
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('retroType should return retro_positive when all answers are correct', () => {
|
|
37
|
+
const solution = [{ id: 1 }, { id: 2 }]
|
|
38
|
+
const reponse = [{ correct: true }, { correct: true }]
|
|
39
|
+
expect(retroType(solution, reponse)).toBe('retro_positive')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('retroType should return retro_negative when some answers are wrong', () => {
|
|
43
|
+
const solution = ['Données primaires', 'Données secondaires']
|
|
44
|
+
const reponse = [
|
|
45
|
+
{
|
|
46
|
+
selected: 'Données primaires',
|
|
47
|
+
correct: true
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
selected: 'Données primaires',
|
|
51
|
+
correct: false
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
expect(retroType(solution, reponse)).toBe('retro_negative')
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('retroType should return retro_neutre when solution is null', () => {
|
|
58
|
+
expect(retroType(null, [])).toBe('retro_neutre')
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('resetRetroStyle should clear arrays and emit event', () => {
|
|
62
|
+
const fakeBus = { $emit: vi.fn() }
|
|
63
|
+
const fakeEl = {}
|
|
64
|
+
const context = { $bus: fakeBus, $el: fakeEl }
|
|
65
|
+
const arr1 = [1, 2]
|
|
66
|
+
const arr2 = ['a']
|
|
67
|
+
resetRetroStyle.call(context, [arr1, arr2])
|
|
68
|
+
expect(arr1.length).toBe(0)
|
|
69
|
+
expect(arr2.length).toBe(0)
|
|
70
|
+
expect(fakeBus.$emit).toHaveBeenCalledWith('hide-retro', fakeEl, false)
|
|
71
|
+
})
|
|
72
|
+
})
|
package/vitest.config.js
CHANGED
|
@@ -1,28 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @vitest-environment
|
|
2
|
+
* @vitest-environment happy-dom
|
|
3
3
|
*/
|
|
4
4
|
import { fileURLToPath, URL } from 'node:url'
|
|
5
|
-
import {
|
|
5
|
+
import { defineConfig, configDefaults } from 'vitest/config'
|
|
6
6
|
import vue from '@vitejs/plugin-vue'
|
|
7
|
-
import viteConfig from './vitest.config'
|
|
8
7
|
|
|
9
|
-
export default
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
},
|
|
22
|
-
environment: 'jsdom',
|
|
23
|
-
exclude: [...configDefaults.exclude, 'tests/component/**', '**/_*.spec.js'],
|
|
24
|
-
root: fileURLToPath(new URL('./', import.meta.url))
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
css: {
|
|
10
|
+
preprocessorOptions: {
|
|
11
|
+
scss: {
|
|
12
|
+
api: 'modern'
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
test: {
|
|
17
|
+
setupFiles: ['vitest.setup.js'],
|
|
18
|
+
alias: {
|
|
19
|
+
'@': fileURLToPath(new URL('./src', import.meta.url))
|
|
25
20
|
},
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
server: {
|
|
22
|
+
deps: {
|
|
23
|
+
inline: ['vuetify']
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
environment: 'happy-dom',
|
|
27
|
+
exclude: [...configDefaults.exclude, 'tests/component/**', '**/_*.spec.js'],
|
|
28
|
+
root: fileURLToPath(new URL('./', import.meta.url)),
|
|
29
|
+
coverage: {
|
|
30
|
+
provider: 'v8',
|
|
31
|
+
reporter: ['text', 'json', 'cobertura'],
|
|
32
|
+
reportsDirectory: './coverage',
|
|
33
|
+
include: ['src/**/*.{js,vue}'],
|
|
34
|
+
exclude: ['tests/**/*'],
|
|
35
|
+
lines: 0, // test must cover at least 80% of lines
|
|
36
|
+
branches: 0, // test must cover at least 80% of branches (if, else, switch, case...)
|
|
37
|
+
functions: 0, // test must cover at least 80% of functions
|
|
38
|
+
statements: 0 // test must cover at least 80% of statements/instructions
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
plugins: [vue()]
|
|
42
|
+
})
|
package/vitest.setup.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
//Mock Vuetify, vue-i18n and event bus
|
|
2
|
+
import { vi } from 'vitest'
|
|
2
3
|
import { config } from '@vue/test-utils'
|
|
3
4
|
import { createI18n } from 'vue-i18n'
|
|
4
5
|
import { createVuetify } from 'vuetify'
|
|
@@ -24,5 +25,72 @@ const i18n = createI18n({
|
|
|
24
25
|
}
|
|
25
26
|
})
|
|
26
27
|
|
|
28
|
+
// Suppress console warnings and errors during tests
|
|
29
|
+
vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
30
|
+
vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
31
|
+
|
|
32
|
+
// Global mock of Router
|
|
33
|
+
// =========================================
|
|
34
|
+
vi.mock('@/router/index.js', () => ({
|
|
35
|
+
default: {
|
|
36
|
+
push: vi.fn(),
|
|
37
|
+
back: vi.fn(),
|
|
38
|
+
currentRoute: { value: { meta: {}, params: {}, query: {} } }
|
|
39
|
+
}
|
|
40
|
+
}))
|
|
41
|
+
|
|
42
|
+
// Global mock of Pinia store
|
|
43
|
+
// =========================================
|
|
44
|
+
vi.mock('@/module/stores/appStore', () => ({
|
|
45
|
+
useAppStore: () => ({
|
|
46
|
+
getAppConfigs: {
|
|
47
|
+
lang: 'fr'
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
getCurrentBrowser: 'Chrome',
|
|
51
|
+
|
|
52
|
+
getCurrentPage: {
|
|
53
|
+
id: 'P01',
|
|
54
|
+
activityRef: 'A03'
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
updateCurrentMediaElements: vi.fn(() => Promise.resolve()),
|
|
58
|
+
getPageInteraction: {},
|
|
59
|
+
getUserInteraction: {}
|
|
60
|
+
})
|
|
61
|
+
}))
|
|
62
|
+
|
|
63
|
+
// Global mock of validators
|
|
64
|
+
// =========================================
|
|
65
|
+
vi.mock('@/shared/validators.js', () => ({
|
|
66
|
+
validateObjType: vi.fn(() => true),
|
|
67
|
+
validateString: vi.fn(() => true),
|
|
68
|
+
validateNumber: vi.fn(() => true),
|
|
69
|
+
validateVideoData: vi.fn(() => []),
|
|
70
|
+
validateAudioData: vi.fn(() => [])
|
|
71
|
+
}))
|
|
72
|
+
|
|
27
73
|
//setup as global plugins used by all tests
|
|
28
74
|
config.global.plugins = [i18n, vuetify, bus]
|
|
75
|
+
|
|
76
|
+
// Global mock of components
|
|
77
|
+
config.global.stubs = {
|
|
78
|
+
AppBaseErrorDisplay: true,
|
|
79
|
+
AppBaseSkeleton: true,
|
|
80
|
+
AppBaseButton: true,
|
|
81
|
+
AppCompPlayBarNext: true
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
config.global.mocks = {
|
|
85
|
+
$route: {
|
|
86
|
+
meta: {
|
|
87
|
+
activity_ref: 'A03',
|
|
88
|
+
id: 'P01'
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
$bus: {
|
|
92
|
+
$on: vi.fn(),
|
|
93
|
+
$emit: vi.fn(),
|
|
94
|
+
$off: vi.fn()
|
|
95
|
+
}
|
|
96
|
+
}
|