fcad-core-dragon 2.2.0-beta.1 → 2.2.0

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/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ 2.2.0(21 janvier 2026)
2
+ Voir corrections des versions 2.2.0-beta
3
+
4
+ 2.2.0-beta.2(8 janvier 2026)
5
+ Correction du comportement de la playbar du lecteur vidéo (elle reste toujours visible, sauf en plein écran)
6
+
7
+ Correction de l’affichage du contenu de la section info (notes et sources) quand il n’y a que des notes ou que des sources
8
+
9
+ Correction du rappel de réponse ("skeleton" qui restait bloqué)
10
+
1
11
  2.2.0-beta.1(19 décembre 2025) ***Changements majeurs*** main.js et i18n.js doivent être remplacés dans vos cours
2
12
  Correction texte troué et texte troué listes déroulantes (fin de texte manquante)
3
13
 
@@ -82,4 +82,4 @@ Error generating stack: `+n.message+`
82
82
  <div id='root'></div>
83
83
  </body>
84
84
  </html>
85
- <script id="playwrightReportBase64" type="application/zip">data:application/zip;base64,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</script>
85
+ <script id="playwrightReportBase64" type="application/zip">data:application/zip;base64,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</script>
package/package.json CHANGED
@@ -21,6 +21,7 @@
21
21
  "@pinia/testing": "^1.0.3",
22
22
  "@playwright/experimental-ct-vue": "^1.56.1",
23
23
  "@playwright/test": "^1.56.1",
24
+ "@testing-library/jest-dom": "^6.9.1",
24
25
  "@types/node": "^24.10.0",
25
26
  "@vitejs/plugin-vue": "^6.0.1",
26
27
  "@vitest/coverage-v8": "^4.0.15",
@@ -65,5 +66,5 @@
65
66
  "watch": "nodemon -e js,vue,html,json -x yalc publish --push"
66
67
  },
67
68
  "type": "module",
68
- "version": "2.2.0-beta.1"
69
+ "version": "2.2.0"
69
70
  }
@@ -250,6 +250,7 @@ export default {
250
250
  this.isCard = this.cards && Object.keys(this.cards).length != 0
251
251
  this.idActivity = this.$router.currentRoute.value.meta.activity_ref
252
252
  this.branchs = this.$router.currentRoute.value.meta.children
253
+
253
254
  this.getbranchsData()
254
255
  },
255
256
  methods: {
@@ -271,7 +272,7 @@ export default {
271
272
  branchData.progression = progression
272
273
  if (isNaN(branchData.progression)) branchData.progression = 0
273
274
 
274
- if (this.isCard) {
275
+ if (this.isCard && this.getMatchingElement(branchData.id)) {
275
276
  const { title, text, imgFile, imgAlt, btnTitle } =
276
277
  this.getMatchingElement(branchData.id)
277
278
 
@@ -476,12 +477,14 @@ export default {
476
477
  * @return {Object} Matching element from
477
478
  */
478
479
  getMatchingElement(id) {
480
+ let matchingBranch = null
479
481
  if (this.isCustomButton) {
480
- return this.customButtons.find((c) => c.brchName === id)
482
+ matchingBranch = this.customButtons.find((c) => c.brchName === id)
481
483
  }
482
484
  if (this.isCard) {
483
- return this.cards.find((c) => c.brchName === id)
485
+ matchingBranch = this.cards.find((c) => c.brchName === id)
484
486
  }
487
+ return matchingBranch ? matchingBranch : null
485
488
  }
486
489
  }
487
490
  }
@@ -1,6 +1,6 @@
1
1
  <!--
2
- @ Description: This component is used to display and create the link's to all the activity creation in module.
3
- @ What it does: Goes trougth all the activity in the router and create a card that open the Table of content (appCompTableOfContent) that display the anchor.Display the title and subtitle enter in menu.json. Must be used with AppCompTableOfContent and AppCompMenu.
2
+ @ Description: This component is used to display and create the links for all the activities in module.
3
+ @ What it does: Goes through all the activities in the router and create a card that navigate to the corresponding activity. Display the title and subtitle enter in menu.json. Must be used with AppCompTableOfContent and AppCompMenu.
4
4
  -->
5
5
  <template>
6
6
  <v-row v-if="activities.length" class="box-msa">
@@ -26,7 +26,7 @@
26
26
  :error-text="`Vous avez une/des erreur(s) dans la création des notes/crédits.`"
27
27
  ></app-base-error-display>
28
28
  <template v-else>
29
- <div v-if="notes" class="ctn-note">
29
+ <div v-if="hasNotes" class="ctn-note">
30
30
  <p class="t-note">{{ $t('text.title_note') }}</p>
31
31
  <div id="notes-list">
32
32
  <template
@@ -62,7 +62,7 @@
62
62
  </template>
63
63
  </div>
64
64
  </div>
65
- <div v-if="credits" class="ctn-credit">
65
+ <div v-if="hasCredits" class="ctn-credit">
66
66
  <p class="t-crdt">{{ $t('text.title_credit') }}</p>
67
67
 
68
68
  <ul id="credits-list">
@@ -70,6 +70,7 @@
70
70
  v-for="(credit, index) of credits"
71
71
  :key="`credit_${index + 1}`"
72
72
  :ref="`#nt_${index + 1}`"
73
+ class="item-credits"
73
74
  v-html="credit"
74
75
  ></li>
75
76
  </ul>
@@ -79,7 +80,7 @@
79
80
  </div>
80
81
  </template>
81
82
  <script>
82
- import { mapState, mapActions } from 'pinia'
83
+ import { mapActions } from 'pinia'
83
84
  import { useAppStore } from '../module/stores/appStore'
84
85
  import { validateObjType } from '../shared/validators'
85
86
  import { useI18n } from 'vue-i18n'
@@ -99,17 +100,17 @@ export default {
99
100
  shouldDeactivate: false,
100
101
  errorData: [],
101
102
  notes: null,
102
- credits: null
103
+ credits: null,
104
+ test: null
103
105
  }
104
106
  },
105
107
  computed: {
106
- ...mapState(useAppStore, [
107
- 'getDataNoteCredit',
108
- 'getAllActivities',
109
- 'getCurrentPage',
110
- 'getNotes',
111
- 'getCredits'
112
- ])
108
+ hasNotes() {
109
+ return this.notes && this.notes.length
110
+ },
111
+ hasCredits() {
112
+ return this.credits && this.credits.length
113
+ }
113
114
  },
114
115
  created() {},
115
116
  beforeUnmount() {
@@ -150,7 +151,6 @@ export default {
150
151
  //Add all the note to the temp array
151
152
  formatedNotes.push(...Object.values(g)[0])
152
153
  })
153
-
154
154
  return formatedNotes
155
155
  },
156
156
 
@@ -168,6 +168,7 @@ export default {
168
168
  },
169
169
  setPageNotesAndCredits(data) {
170
170
  const { notes, credits } = data
171
+
171
172
  this.notes = this.getPageNotes(notes)
172
173
  this.credits = this.getPageCredits(credits)
173
174
  },
@@ -180,7 +181,6 @@ export default {
180
181
  validateData(ctx, data) {
181
182
  let errConsole = []
182
183
  if (this.errorData.length) this.errorData = [] //reset the error tracker
183
-
184
184
  switch (ctx) {
185
185
  case 'note': {
186
186
  if (data.constructor !== Object) {
@@ -191,7 +191,6 @@ export default {
191
191
  `Unexpected definition the note. Expecting Object but received ${typeof data}`
192
192
  )
193
193
  }
194
-
195
194
  let stringType = ['id', 'text'] //expected attribute in the note declaration
196
195
 
197
196
  let { errorInConsole, errorList } = validateObjType(
@@ -202,7 +201,6 @@ export default {
202
201
  null,
203
202
  `Note ${data.details}`
204
203
  )
205
-
206
204
  if (errorInConsole.length) errConsole.push(...errorInConsole)
207
205
  if (errorList.length) this.errorData.push(...errorList)
208
206
  break
@@ -353,6 +351,10 @@ export default {
353
351
  const elTarget = widgetContent.namedItem(ref) // Target current button
354
352
  const pageRef = elTarget.getAttribute('pageref')
355
353
 
354
+ console.log('widgetContent :', widgetContent)
355
+ console.log('elTarget :', elTarget)
356
+ console.log('pageRef :', pageRef)
357
+
356
358
  if (!this.sideBarIsOpen) this.prevNote = null //reset previous when sidebar is opened
357
359
 
358
360
  let prevPageref = this.prevNote
@@ -414,10 +416,6 @@ export default {
414
416
  }
415
417
  }
416
418
 
417
- // .note-txt {
418
- // pointer-events: none;
419
- // }
420
-
421
419
  .box-nc {
422
420
  margin-top: 54px;
423
421
  overflow-y: auto;
@@ -460,6 +460,7 @@ export default {
460
460
  const timer = reactive(new Timer(id)) // Making Timer instance reactive to be able to track changes
461
461
  const { t } = useI18n()
462
462
  return { id, store, timer, t }
463
+ //return { id, store, timer }
463
464
  },
464
465
  data() {
465
466
  return {
@@ -913,7 +914,7 @@ export default {
913
914
  * @description - handle all the listeners for medias
914
915
  */
915
916
  setMediaHandlers() {
916
- if (this.mediaElement) {
917
+ if (this.mediaElement && this.mediaElement.addEventListener) {
917
918
  //Prevent default on keys used for navigation in the player (prevent scrollbar to be trigger when changing volume)
918
919
  this.pbContainer.addEventListener('keydown', this.keysPreventDefault)
919
920
  //progressBar events
@@ -921,7 +922,7 @@ export default {
921
922
  //window handlers for playbar progress
922
923
  window.addEventListener('mousemove', this.progressWindowMove)
923
924
  window.addEventListener('mouseup', this.progressWindowUp)
924
-
925
+ // console.log('⚠️--- TEST AppCompPlayBarNext---', this.mediaElement)
925
926
  //Update data when media as a timeupdate/ended
926
927
  this.mediaElement.addEventListener(
927
928
  'timeupdate',
@@ -1580,7 +1581,10 @@ export default {
1580
1581
  */
1581
1582
  setVideoHandlers() {
1582
1583
  //Tooltip
1584
+ if (!this.progressArea || !this.progressArea.addEventListener) return
1583
1585
  this.progressArea.addEventListener('mousemove', this.updateSeekTooltip)
1586
+
1587
+ if (!this.mediaContainer || !this.mediaContainer.addEventListener) return
1584
1588
  //Fullscreen
1585
1589
  this.mediaContainer.addEventListener(
1586
1590
  'fullscreenchange',
@@ -1594,7 +1598,10 @@ export default {
1594
1598
  */
1595
1599
  removeVideoHandlers() {
1596
1600
  //Tooltip
1601
+ if (!this.progressArea || !this.progressArea.addEventListener) return
1597
1602
  this.progressArea.removeEventListener('mousemove', this.updateSeekTooltip)
1603
+ if (!this.mediaContainer || !this.mediaContainer.removeEventListener)
1604
+ return
1598
1605
  //Fullscreen
1599
1606
  this.mediaContainer.removeEventListener(
1600
1607
  'fullscreenchange',
@@ -1777,7 +1784,8 @@ export default {
1777
1784
  */
1778
1785
 
1779
1786
  hideControls() {
1780
- if (this.mediaElement.paused) return
1787
+ //Always show playbar when paused or not in fullscreen mode
1788
+ if (this.mediaElement.paused || !document.fullscreenElement) return
1781
1789
 
1782
1790
  this.hideTimer = setTimeout(() => {
1783
1791
  this.showControlsValue = false
@@ -103,27 +103,15 @@ export default {
103
103
  //Watch for user interaction change to get quizRecall answer
104
104
  getUserInteraction: {
105
105
  async handler(newValue) {
106
- //console.log('???')
107
106
  if (!this.getUserInteraction) return
108
- //console.log('--------------------')
109
107
  const { activityId, pageId } = this.quizRecallData
110
108
  const interaction = this.getPageInteraction(
111
109
  activityId,
112
110
  pageId
113
111
  ).userInteraction
114
-
115
- //console.log(interaction)
116
- if (!interaction) return //{
117
- // this.quizRecall.done == false
118
- // }
119
-
120
112
  //Get quizRecall answer
121
113
  if (this.quizRecallData && this.quizData) {
122
- //console.log('ici????')
123
114
  await this.getQuizRecallAnswer(interaction)
124
- } else {
125
- //console.log('laaaaaa ???? ')
126
- this.quizRecall.done == false
127
115
  }
128
116
  },
129
117
  immediate: true,
@@ -216,6 +204,13 @@ export default {
216
204
  //Get datas from quizRecallData and userData and add them to quizRecall object
217
205
  async getQuizRecallAnswer(userData) {
218
206
  await this.$nextTick() //wait for the DOM to update
207
+ //userData will be undefined if the page containing the target quiz was never visited
208
+ if (typeof userData === 'undefined') {
209
+ this.quizRecall.done = false //set quiz recall message (quiz not completed)
210
+ this.isReady = true //hide the skeleton
211
+ return
212
+ }
213
+
219
214
  const { quizId, hypertext_done, hypertext_undone, title, titletag } =
220
215
  this.quizRecallData
221
216
 
@@ -252,7 +247,6 @@ export default {
252
247
  this.quizRecall.answer = quizAnswer.value[0].filled || ''
253
248
  this.quizRecall.ennonce = this.quizData.ennonce
254
249
  }
255
- this.quizRecall
256
250
  this.isReady = true //Set isReady to true to display the component
257
251
  },
258
252
 
package/src/main.js CHANGED
@@ -489,8 +489,9 @@ export default {
489
489
 
490
490
  appStore.applicationSettings = settingsOptions
491
491
  //=================================END SETTING PREFERENCES ====================================//
492
-
493
- const i18n = initLocalisation()
492
+ // const appi18b = options.i18n
493
+ // console.log('i18n options received in appBase plugin...', appi18b)
494
+ const i18n = initLocalisation(options.i18n)
494
495
  app.use(i18n)
495
496
  app.use(helper)
496
497
  app.use(analytics)
@@ -27,7 +27,6 @@ export const useAppStore = defineStore('$appStore', {
27
27
  userMetaData: {},
28
28
  appConfigs: null,
29
29
  menuSetting: null,
30
- dataNc: {},
31
30
  wigIsOpen: false,
32
31
  popIsOpen: false,
33
32
  sideBIsOpen: false,
@@ -596,9 +595,6 @@ export const useAppStore = defineStore('$appStore', {
596
595
  getDataFromServer: (state) => {
597
596
  return state.dataFromServer
598
597
  },
599
- getDataNoteCredit: (state) => {
600
- return state.dataNc
601
- },
602
598
  getWidgetOpen(state) {
603
599
  return state.wigIsOpen
604
600
  },
@@ -801,9 +797,6 @@ export const useAppStore = defineStore('$appStore', {
801
797
  )
802
798
  this.currentSection = data
803
799
  },
804
- updateCurrentnoteCredit(data) {
805
- this.dataNc = data
806
- },
807
800
  /**
808
801
  * @description: Save user interaction on a page to store
809
802
  * USe to Update existing userMetadata
@@ -7,7 +7,6 @@ import { createI18n } from 'vue-i18n'
7
7
  */
8
8
  export default function initLocalisation(templateMessages) {
9
9
  const i18n = createI18n({ legacy: false })
10
-
11
10
  const thisLocales = import.meta.glob('../$locales/*.json', {
12
11
  import: 'default',
13
12
  eager: true
@@ -18,7 +17,7 @@ export default function initLocalisation(templateMessages) {
18
17
  const locale = matched[1]
19
18
  // Using lodash to deeply merge objects
20
19
  const coreMessages = JSON.parse(JSON.stringify(thisLocales[path]))
21
- const mergedMessages = _.merge(coreMessages, templateMessages)
20
+ const mergedMessages = _.merge(coreMessages, templateMessages[locale])
22
21
 
23
22
  // Since merLocalMessage will do a shallow merge of the object. We will use setLocalMessage to replace the message with new message object
24
23
 
@@ -955,18 +955,9 @@ const validateQuizData = (data) => {
955
955
  if (hasError) return errors
956
956
 
957
957
  //validate Containt for retroaction
958
-
959
-
960
- // if(data.solution !=null){
961
- // console.log('ici')
962
- // }else{
963
- // console.log('la')
964
- // }
965
-
966
958
  switch (true) {
967
959
  case data.retroaction != null:
968
960
  objectType = ['retro_positive', 'retro_negative', 'retro_neutre']
969
-
970
961
 
971
962
  errors = validateObjType(
972
963
  data.retroaction,
@@ -983,19 +974,15 @@ const validateQuizData = (data) => {
983
974
  // Validate containt of retroaction attributes
984
975
  stringType = ['title', 'hypertext']
985
976
 
986
-
987
977
  for (const key of Object.keys(data.retroaction)) {
988
-
989
- if(key == "retro_neutre") continue //skip
990
-
991
-
992
-
993
- errors = validateObjType(
994
- data.retroaction[key],
995
- { stringType },
996
- null,
997
- key
998
- )
978
+ if (key == 'retro_neutre') continue //skip
979
+
980
+ errors = validateObjType(
981
+ data.retroaction[key],
982
+ { stringType },
983
+ null,
984
+ key
985
+ )
999
986
 
1000
987
  hasError = errors.errorInConsole.length || errors.errorList.length
1001
988
 
@@ -0,0 +1,2 @@
1
+ export const routes = []
2
+ export const mappedFiles = []
@@ -1,5 +1,10 @@
1
1
  import { mount } from '@vue/test-utils'
2
- import { describe, it, test, expect } from 'vitest'
2
+ import { describe, it, test, expect, vi } from 'vitest'
3
+
4
+ //Mock store appStore
5
+ vi.mock('@/module/stores/appStore', () => ({
6
+ useAppStore: () => ({})
7
+ }))
3
8
 
4
9
  let dummyProps = {
5
10
  id: 'P01',
@@ -0,0 +1,172 @@
1
+ import { mount } from '@vue/test-utils'
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
3
+ import { createTestingPinia } from '@pinia/testing'
4
+ import { colors } from '../utility/colors'
5
+
6
+ //Mock store appStore
7
+ vi.mock('@/module/stores/appStore', () => ({
8
+ useAppStore: () => ({
9
+ getAllCompleted: { A01: [] }
10
+ })
11
+ }))
12
+
13
+ import AppCompBranchButtons from '@/components/AppCompBranchButtons.vue'
14
+
15
+ const dummyProps = {
16
+ cards: [
17
+ {
18
+ imgFile: 'https://loremflickr.com/500/500/kitten',
19
+ imgAlt: 'Test img 1',
20
+ title: 'banane',
21
+ text: 'Ceci est un embranchement factice, affiché sous la forme de carte.',
22
+ brchName: 'P02_E01'
23
+ },
24
+ {
25
+ imgFile: 'https://loremflickr.com/500/500/kitten',
26
+ imgAlt: 'Test img 2',
27
+ title: 'Titre embranchement 2',
28
+ text: 'Ceci est un embranchement factice, affiché sous la forme de carte, pour toto',
29
+ brchName: 'P02_E02'
30
+ },
31
+ {
32
+ imgFile: 'https://loremflickr.com/500/500/kitten',
33
+ imgAlt: 'Test img 3',
34
+ title: 'Titre embranchement 3',
35
+ text: 'Ceci est un embranchement factice, affiché sous la forme de carte, pour toto',
36
+ brchName: 'P02_E03'
37
+ }
38
+ ],
39
+ customButtons: [
40
+ { name: 'bouton_A02_P01_E01', brchName: 'P02_E01' },
41
+ { name: 'bouton_A02_P01_E02', brchName: 'P02_E02' }
42
+ ]
43
+ }
44
+
45
+ describe('AppCompBranchButtons.vue', () => {
46
+ let globalConfig
47
+
48
+ beforeEach(() => {
49
+ globalConfig = {
50
+ plugins: [createTestingPinia({ createSpy: vi.fn })],
51
+ mocks: {
52
+ $router: {
53
+ currentRoute: {
54
+ value: {
55
+ meta: {
56
+ activity_ref: 'A01',
57
+ children: [
58
+ {
59
+ _ref: 'P02_E01',
60
+ _path: 'branche-1',
61
+ _namedRoute: 'activite_3.page_2.branche_1'
62
+ },
63
+ {
64
+ _ref: 'P02_E02',
65
+ _path: 'branche-2',
66
+ _namedRoute: 'activite_3.page_2.branche_2'
67
+ },
68
+ {
69
+ _ref: 'P02_E03',
70
+ _path: 'branche-3',
71
+ _namedRoute: 'activite_3.page_2.branche_3'
72
+ }
73
+ ]
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ vi.clearAllMocks()
81
+ })
82
+
83
+ it('Renders ErrorDisplay when cards has errors', async () => {
84
+ const wrapper = mount(AppCompBranchButtons, {
85
+ global: globalConfig,
86
+ props: {
87
+ cards: [dummyProps.cards[0], dummyProps.cards[1]] // Only 2 cards passed instead of 3
88
+ }
89
+ })
90
+
91
+ await wrapper.vm.$nextTick() // Must wait for DOM updates to display AppBaseErrorDisplay
92
+
93
+ if (wrapper.vm.hasErrors) {
94
+ const cards = wrapper.vm.cards
95
+ console.log(colors.green, `\n ✅ Current cards: ${JSON.stringify(cards)}`)
96
+ console.log(
97
+ '✅ wrapper.vm.hasErrors:',
98
+ wrapper.vm.hasErrors,
99
+ colors.reset
100
+ )
101
+ }
102
+ // Error should be displayed
103
+ expect(wrapper.vm.hasErrors.length).toBeGreaterThan(0)
104
+ expect(
105
+ wrapper.findComponent({ name: 'AppBaseErrorDisplay' }).exists()
106
+ ).toBe(true)
107
+ })
108
+
109
+ it('Renders ErrorDisplay when customButtons has errors', async () => {
110
+ const wrapper = mount(AppCompBranchButtons, {
111
+ global: globalConfig,
112
+ props: {
113
+ customButtons: [
114
+ { brchName: 'BRANCH_1' }, // missing required key 'name' here
115
+ { name: 'bouton_A02_P01_E01', brchName: 'P02_E02' },
116
+ { name: 'bouton_A02_P01_E01', brchName: 'P02_E03' }
117
+ ]
118
+ }
119
+ })
120
+ await wrapper.vm.$nextTick() // Must wait for DOM updates to display AppBaseErrorDisplay
121
+
122
+ if (wrapper.vm.hasErrors) {
123
+ const el = wrapper.vm.customButtons[0]
124
+ console.log(colors.green, `\n ✅ Current cards: ${JSON.stringify(el)}`)
125
+ console.log(
126
+ '✅ wrapper.vm.hasErrors:',
127
+ wrapper.vm.hasErrors,
128
+ colors.reset
129
+ )
130
+ }
131
+ // hasError should have a message
132
+ expect(wrapper.vm.hasErrors.length).toBeGreaterThan(0)
133
+ // Error should be displayed
134
+ expect(
135
+ wrapper.findComponent({ name: 'AppBaseErrorDisplay' }).exists()
136
+ ).toBe(true)
137
+ })
138
+
139
+ //=====================================================================
140
+ it('It renders the buttons when no errors', async () => {
141
+ const wrapper = mount(AppCompBranchButtons, {
142
+ global: {
143
+ ...globalConfig
144
+ },
145
+ props: {
146
+ cards: dummyProps.cards
147
+ }
148
+ })
149
+
150
+ await wrapper.vm.$nextTick() // Must wait for DOM updates to display AppBaseErrorDisplay
151
+
152
+ if (wrapper.vm.hasErrors) {
153
+ console.log(colors.red)
154
+ console.log(
155
+ '\n wrapper.vm.hasErrors:',
156
+ wrapper.vm.hasErrors,
157
+ colors.reset
158
+ )
159
+ }
160
+
161
+ // expect hasErrors to return false
162
+ expect(wrapper.vm.hasErrors).toBe(false)
163
+ //error display not to be in DOM
164
+ expect(
165
+ wrapper.findComponent({ name: 'AppBaseErrorDisplay' }).exists()
166
+ ).not.toBe(true)
167
+ // element to rendered correctly in DOM
168
+ expect(wrapper.find('#branch-buttons-component').exists()).toBe(true)
169
+ //should display 3 buttons
170
+ expect(wrapper.findAll('.branch-btn').length).toBe(3)
171
+ })
172
+ })
@@ -1,7 +1,12 @@
1
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'
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
3
+
4
+ //Mock store appStore
5
+ vi.mock('@/module/stores/appStore', () => ({
6
+ useAppStore: () => ({
7
+ getAppConfigs: { lang: 'FR' }
8
+ })
9
+ }))
5
10
 
6
11
  const dummyProps = {
7
12
  slides: [
@@ -28,6 +33,9 @@ const dummyProps = {
28
33
  name: 'Mon super carousel'
29
34
  }
30
35
 
36
+ import AppCompCarousel from '@/components/AppCompCarousel.vue'
37
+ import AppBaseButton from '@/components/AppBaseButton.vue'
38
+
31
39
  describe('AppCompCarousel.vue', () => {
32
40
  let wrapper = null
33
41
  beforeEach(() => {