@cnamts/synapse 1.0.9 → 1.0.10
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/dist/{DateFilter-BylukfjR.js → DateFilter-C0wDuzgn.js} +1 -1
- package/dist/{NumberFilter-C_bUk9o1.js → NumberFilter-CBj7zdOi.js} +1 -1
- package/dist/{PeriodFilter-dVOmcfmt.js → PeriodFilter-DB4wWyKy.js} +1 -1
- package/dist/{SelectFilter-BW8KpXkQ.js → SelectFilter-Dces8572.js} +1 -1
- package/dist/{TextFilter-diwVzTz7.js → TextFilter-BU9nlkuS.js} +1 -1
- package/dist/components/Amelipro/AmeliproAccordionFrieze/AmeliproAccordionFrieze.d.ts +110 -0
- package/dist/components/Amelipro/AmeliproAccordionFrieze/types.d.ts +6 -0
- package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +120 -120
- package/dist/components/Amelipro/AmeliproBtn/AmeliproBtn.d.ts +2 -2
- package/dist/components/Amelipro/AmeliproCarousel/AmeliproCarousel.d.ts +3 -3
- package/dist/components/Amelipro/AmeliproDentalChart/AmeliproDentalChart.d.ts +47 -0
- package/dist/components/Amelipro/AmeliproDentalChart/AmeliproTooth/AmeliproTooth.d.ts +88 -0
- package/dist/components/Amelipro/AmeliproDentalChart/types.d.ts +13 -0
- package/dist/components/Amelipro/AmeliproFirstLogin/AmeliproFirstLogin.d.ts +70 -0
- package/dist/components/Amelipro/AmeliproFirstLogin/locales.d.ts +46 -0
- package/dist/components/Amelipro/AmeliproIconBtn/AmeliproIconBtn.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproPatientLogged/AmeliproPatientLogged.d.ts +149 -0
- package/dist/components/Amelipro/AmeliproPatientLogged/types.d.ts +48 -0
- package/dist/components/Amelipro/AmeliproPatientLogin/AmeliproPatientLogin.d.ts +177 -0
- package/dist/components/Amelipro/AmeliproPatientLogin/AmeliproPatientLoginForm/AmeliproPatientLoginForm.d.ts +169 -0
- package/dist/components/Amelipro/AmeliproPatientLogin/AmeliproPatientLoginForm/types.d.ts +5 -0
- package/dist/components/Amelipro/AmeliproPatientLogin/types.d.ts +5 -0
- package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressCityRow/AmeliproPostalAddressCityRow.d.ts +2925 -0
- package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressCityRow/types.d.ts +11 -0
- package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressField.d.ts +4489 -0
- package/dist/components/Amelipro/AmeliproPostalAddressField/types.d.ts +17 -0
- package/dist/components/Amelipro/AmeliproSelect/AmeliproSelect.d.ts +120 -120
- package/dist/components/Amelipro/AmeliproTabs/AmeliproTabs.d.ts +120 -120
- package/dist/components/Amelipro/AmeliproTextArea/AmeliproTextArea.d.ts +12 -12
- package/dist/components/Amelipro/AmeliproTextField/AmeliproTextField.d.ts +30 -30
- package/dist/components/Amelipro/AmeliproTooltips/AmeliproTooltips.d.ts +12 -2
- package/dist/components/CookieBanner/CookieBanner.d.ts +7 -7
- package/dist/components/CookiesSelection/CookiesInformation/CookiesInformation.d.ts +20 -20
- package/dist/components/CookiesSelection/CookiesSelection.d.ts +9 -9
- package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +7 -6
- package/dist/components/Customs/SyForm/SyForm.d.ts +1820 -0
- package/dist/components/Customs/SyTabs/SyTabs.d.ts +3 -1
- package/dist/components/Customs/SyTabs/useTabTransition.d.ts +5 -0
- package/dist/components/Customs/SyTextField/SyTextField.d.ts +36 -31
- package/dist/components/Customs/SyTextField/types.d.ts +1 -1
- package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +232 -134
- package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +121 -71
- package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +60 -37
- package/dist/components/DatePicker/composables/useDateValidation.d.ts +14 -2
- package/dist/components/DatePicker/composables/useManualDateValidation.d.ts +2 -2
- package/dist/components/DatePicker/tests/setup.d.ts +74354 -0
- package/dist/components/DialogBox/DialogBox.d.ts +10 -10
- package/dist/components/DialogBox/locales.d.ts +1 -0
- package/dist/components/DialogBox/useDraggable.d.ts +2 -0
- package/dist/components/FilterSideBar/FilterSideBar.d.ts +7 -7
- package/dist/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.d.ts +2 -0
- package/dist/components/HeaderNavigationBar/types.d.ts +1 -0
- package/dist/components/HeaderToolbar/HeaderToolbar.d.ts +842 -9
- package/dist/components/HeaderToolbar/locales.d.ts +3 -0
- package/dist/components/HeaderToolbar/useMobileRightMenu.d.ts +10 -0
- package/dist/components/LangBtn/LangBtn.d.ts +8 -8
- package/dist/components/NirField/NirField.d.ts +90 -65
- package/dist/components/NirField/locales.d.ts +6 -4
- package/dist/components/PasswordField/PasswordField.d.ts +3 -1
- package/dist/components/PasswordField/locales.d.ts +2 -0
- package/dist/components/PeriodField/PeriodField.d.ts +460 -260
- package/dist/components/PhoneField/PhoneField.d.ts +45 -32
- package/dist/components/RangeField/RangeField.d.ts +11 -1
- package/dist/components/RangeField/RangeSlider/RangeSlider.d.ts +2 -2
- package/dist/components/RangeField/config.d.ts +3 -0
- package/dist/components/RatingPicker/EmotionPicker/EmotionPicker.d.ts +3 -1
- package/dist/components/RatingPicker/EmotionPicker/locales.d.ts +2 -0
- package/dist/components/RatingPicker/NumberPicker/NumberPicker.d.ts +3 -1
- package/dist/components/RatingPicker/StarsPicker/StarsPicker.d.ts +3 -1
- package/dist/components/RatingPicker/locales.d.ts +1 -0
- package/dist/components/SearchListField/SearchListField.d.ts +6 -6
- package/dist/components/SyAlert/SyAlert.d.ts +2 -2
- package/dist/components/SyTextArea/SyTextArea.d.ts +13 -13
- package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +3 -5
- package/dist/components/Tables/SyTable/SyTable.d.ts +3 -5
- package/dist/components/Tables/common/SyTablePagination.d.ts +8 -6
- package/dist/components/Tables/common/organizeColumns/OrganizeColumns.d.ts +4 -4
- package/dist/components/Tables/common/usePagination.d.ts +1 -3
- package/dist/components/Tables/common/useTableCheckbox.d.ts +1 -1
- package/dist/components/UploadWorkflow/UploadWorkflow.d.ts +4 -4
- package/dist/components/index.d.ts +8 -0
- package/dist/composables/validation/useFormValidation.d.ts +24 -0
- package/dist/composables/validation/useValidatable.d.ts +17 -0
- package/dist/design-system-v3.js +181 -173
- package/dist/design-system-v3.umd.cjs +265 -263
- package/dist/{main-2eWGB7zZ.js → main-Dt4iNotT.js} +14095 -11151
- package/dist/style.css +1 -1
- package/dist/tooth-11-B9fN9Ow_.js +4 -0
- package/dist/tooth-12-BOOjuDe9.js +4 -0
- package/dist/tooth-13-DVU7jhZ8.js +4 -0
- package/dist/tooth-14-CXNleTBu.js +4 -0
- package/dist/tooth-15-iq3z8dzZ.js +4 -0
- package/dist/tooth-16-BuNIHSQk.js +4 -0
- package/dist/tooth-17-DLb4ijsH.js +4 -0
- package/dist/tooth-18-huijQe68.js +4 -0
- package/dist/tooth-21-Bl7Q-o4y.js +4 -0
- package/dist/tooth-22-ChQKI3h5.js +4 -0
- package/dist/tooth-23-CkzbEvBa.js +4 -0
- package/dist/tooth-24-BpaPUSEp.js +4 -0
- package/dist/tooth-25-BaVfhAL6.js +4 -0
- package/dist/tooth-26-BnL03Jv5.js +4 -0
- package/dist/tooth-27-BaHyZfhH.js +4 -0
- package/dist/tooth-28-BrMBVEgX.js +4 -0
- package/dist/tooth-31-DEH3Btej.js +4 -0
- package/dist/tooth-32-Dqcy596v.js +4 -0
- package/dist/tooth-33-DLzQOVky.js +4 -0
- package/dist/tooth-34-36nkjUPW.js +4 -0
- package/dist/tooth-35-VfFhleWT.js +4 -0
- package/dist/tooth-36-BHwtGkLx.js +4 -0
- package/dist/tooth-37-CT47Rtk-.js +4 -0
- package/dist/tooth-38-D15JmYSD.js +4 -0
- package/dist/tooth-41--x9N_iSc.js +4 -0
- package/dist/tooth-42-DZ1D3qmP.js +4 -0
- package/dist/tooth-43-C9T3b5_0.js +4 -0
- package/dist/tooth-44-CsPRBSZV.js +4 -0
- package/dist/tooth-45-Dg3wQunm.js +4 -0
- package/dist/tooth-46-DAOEt4G5.js +4 -0
- package/dist/tooth-47-DcqUeVM0.js +4 -0
- package/dist/tooth-48-0MVzkYem.js +4 -0
- package/dist/tooth-51-DOTod22I.js +4 -0
- package/dist/tooth-52-DZB1Jabv.js +4 -0
- package/dist/tooth-53-nunm2BQr.js +4 -0
- package/dist/tooth-54-BwdYfBd-.js +4 -0
- package/dist/tooth-55-BUJdNwqL.js +4 -0
- package/dist/tooth-61-BwqR1B88.js +4 -0
- package/dist/tooth-62-BzaECsvF.js +4 -0
- package/dist/tooth-63-wjdIfSq2.js +4 -0
- package/dist/tooth-64-CGW4ZcUq.js +4 -0
- package/dist/tooth-65-DxH4GgAL.js +4 -0
- package/dist/tooth-71-CmjVz11G.js +4 -0
- package/dist/tooth-72-CCyNUD-W.js +4 -0
- package/dist/tooth-73-D6aJwVz4.js +4 -0
- package/dist/tooth-74-zNtDQ6ig.js +4 -0
- package/dist/tooth-75-DDEx6y4E.js +4 -0
- package/dist/tooth-81-xg8UVvz2.js +4 -0
- package/dist/tooth-82-CtNXwBtB.js +4 -0
- package/dist/tooth-83-C2ODw7VT.js +4 -0
- package/dist/tooth-84-BKIdO9HA.js +4 -0
- package/dist/tooth-85-3YmvfAsK.js +4 -0
- package/package.json +2 -2
- package/src/assets/amelipro/img/dental-chart-img/tooth-11.svg +16 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-12.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-13.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-14.svg +26 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-15.svg +21 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-16.svg +31 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-17.svg +26 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-18.svg +26 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-21.svg +16 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-22.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-23.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-24.svg +26 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-25.svg +21 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-26.svg +31 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-27.svg +26 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-28.svg +26 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-31.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-32.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-33.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-34.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-35.svg +22 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-36.svg +26 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-37.svg +26 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-38.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-41.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-42.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-43.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-44.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-45.svg +22 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-46.svg +26 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-47.svg +26 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-48.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-51.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-52.svg +16 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-53.svg +16 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-54.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-55.svg +16 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-61.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-62.svg +16 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-63.svg +16 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-64.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-65.svg +16 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-71.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-72.svg +16 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-73.svg +16 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-74.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-75.svg +16 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-81.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-82.svg +16 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-83.svg +16 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-84.svg +11 -0
- package/src/assets/amelipro/img/dental-chart-img/tooth-85.svg +16 -0
- package/src/assets/amelipro/img/idpa/apcv_logo.svg +16 -0
- package/src/assets/amelipro/img/idpa/carte-vitale.svg +75 -0
- package/src/components/Amelipro/AmeliproAccordionFrieze/AmeliproAccordionFrieze.mdx +15 -0
- package/src/components/Amelipro/AmeliproAccordionFrieze/AmeliproAccordionFrieze.stories.ts +261 -0
- package/src/components/Amelipro/AmeliproAccordionFrieze/AmeliproAccordionFrieze.vue +419 -0
- package/src/components/Amelipro/AmeliproAccordionFrieze/__tests__/AmeliproAccordionFrieze.spec.ts +98 -0
- package/src/components/Amelipro/AmeliproAccordionFrieze/__tests__/__snapshots__/AmeliproAccordionFrieze.spec.ts.snap +858 -0
- package/src/components/Amelipro/AmeliproAccordionFrieze/types.d.ts +6 -0
- package/src/components/Amelipro/AmeliproAccordionList/AmeliproAccordionList.vue +2 -2
- package/src/components/Amelipro/AmeliproAccordionList/__tests__/__snapshots__/AmeliproAccordionList.spec.ts.snap +0 -4
- package/src/components/Amelipro/AmeliproAccordionResultList/AmeliproAccordionResultList.vue +2 -2
- package/src/components/Amelipro/AmeliproAccordionResultList/__tests__/__snapshots__/AmeliproAccordionResultList.spec.ts.snap +0 -4
- package/src/components/Amelipro/AmeliproBadge/AmeliproBadge.stories.ts +97 -0
- package/src/components/Amelipro/AmeliproBtn/AmeliproBtn.stories.ts +190 -8
- package/src/components/Amelipro/AmeliproCallback/AmeliproCallback.stories.ts +321 -0
- package/src/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.vue +1 -1
- package/src/components/Amelipro/AmeliproCard/AmeliproCard.stories.ts +360 -0
- package/src/components/Amelipro/AmeliproCheckbox/AmeliproCheckbox.stories.ts +1 -1
- package/src/components/Amelipro/AmeliproCheckboxGroup/AmeliproCheckboxGroup.stories.ts +2 -2
- package/src/components/Amelipro/AmeliproCheckboxGroup/AmeliproCheckboxGroup.vue +1 -1
- package/src/components/Amelipro/AmeliproChips/AmeliproChips.stories.ts +46 -0
- package/src/components/Amelipro/AmeliproClickableTile/AmeliproClickableTile.stories.ts +173 -0
- package/src/components/Amelipro/AmeliproCopyBtn/AmeliproCopyBtn.stories.ts +112 -26
- package/src/components/Amelipro/AmeliproDentalChart/AmeliproDentalChart.mdx +15 -0
- package/src/components/Amelipro/AmeliproDentalChart/AmeliproDentalChart.stories.ts +1078 -0
- package/src/components/Amelipro/AmeliproDentalChart/AmeliproDentalChart.vue +163 -0
- package/src/components/Amelipro/AmeliproDentalChart/AmeliproTooth/AmeliproTooth.vue +183 -0
- package/src/components/Amelipro/AmeliproDentalChart/AmeliproTooth/tests/AmeliproTooth.spec.ts +20 -0
- package/src/components/Amelipro/AmeliproDentalChart/AmeliproTooth/tests/__snapshots__/AmeliproTooth.spec.ts.snap +39 -0
- package/src/components/Amelipro/AmeliproDentalChart/tests/AmeliproDentalChart.spec.ts +468 -0
- package/src/components/Amelipro/AmeliproDentalChart/tests/__snapshots__/AmeliproDentalChart.spec.ts.snap +2589 -0
- package/src/components/Amelipro/AmeliproDentalChart/types.d.ts +13 -0
- package/src/components/Amelipro/AmeliproDialog/AmeliproDialog.stories.ts +333 -0
- package/src/components/Amelipro/AmeliproDialog/AmeliproDialog.vue +7 -2
- package/src/components/Amelipro/AmeliproDialog/tests/__snapshots__/AmeliproDialog.spec.ts.snap +1 -0
- package/src/components/Amelipro/AmeliproErrorTemplate/AmeliproErrorTemplate.vue +1 -1
- package/src/components/Amelipro/AmeliproErrorTemplate/__tests__/__snapshots__/AmeliproErrorTemplate.spec.ts.snap +1 -2
- package/src/components/Amelipro/AmeliproFirstLogin/AmeliproFirstLogin.mdx +15 -0
- package/src/components/Amelipro/AmeliproFirstLogin/AmeliproFirstLogin.stories.ts +287 -0
- package/src/components/Amelipro/AmeliproFirstLogin/AmeliproFirstLogin.vue +331 -0
- package/src/components/Amelipro/AmeliproFirstLogin/__tests__/AmeliproFirstLogin.spec.ts +29 -0
- package/src/components/Amelipro/AmeliproFirstLogin/__tests__/__snapshots__/AmeliproFirstLogin.spec.ts.snap +1210 -0
- package/src/components/Amelipro/AmeliproFirstLogin/locales.ts +48 -0
- package/src/components/Amelipro/AmeliproIcon/AmeliproIcon.stories.ts +61 -1
- package/src/components/Amelipro/AmeliproIconBtn/AmeliproIconBtn.stories.ts +174 -0
- package/src/components/Amelipro/AmeliproIllustratedDataTile/AmeliproIllustratedDataTile.stories.ts +186 -0
- package/src/components/Amelipro/AmeliproMailTile/AmeliproMailTile.stories.ts +237 -0
- package/src/components/Amelipro/AmeliproMessage/AmeliproMessage.stories.ts +111 -0
- package/src/components/Amelipro/AmeliproMultipleFoldingCard/AmeliproMultipleFoldingCard.stories.ts +199 -0
- package/src/components/Amelipro/AmeliproNumberedCard/AmeliproNumberedCard.stories.ts +150 -0
- package/src/components/Amelipro/AmeliproOnboarding/AmeliproOnboarding.stories.ts +281 -8
- package/src/components/Amelipro/AmeliproPagination/AmeliproPagination.stories.ts +123 -43
- package/src/components/Amelipro/AmeliproPatientLogged/AmeliproPatientLogged.mdx +18 -0
- package/src/components/Amelipro/AmeliproPatientLogged/AmeliproPatientLogged.stories.ts +250 -0
- package/src/components/Amelipro/AmeliproPatientLogged/AmeliproPatientLogged.vue +520 -0
- package/src/components/Amelipro/AmeliproPatientLogged/__tests__/AmeliproPatientLogged.spec.ts +79 -0
- package/src/components/Amelipro/AmeliproPatientLogged/__tests__/__snapshots__/AmeliproPatientLogged.spec.ts.snap +1140 -0
- package/src/components/Amelipro/AmeliproPatientLogged/types.d.ts +49 -0
- package/src/components/Amelipro/AmeliproPatientLogin/AmeliproPatientLogin.mdx +18 -0
- package/src/components/Amelipro/AmeliproPatientLogin/AmeliproPatientLogin.stories.ts +151 -0
- package/src/components/Amelipro/AmeliproPatientLogin/AmeliproPatientLogin.vue +231 -0
- package/src/components/Amelipro/AmeliproPatientLogin/AmeliproPatientLoginForm/AmeliproPatientLoginForm.vue +252 -0
- package/src/components/Amelipro/AmeliproPatientLogin/AmeliproPatientLoginForm/__tests__/AmeliproPatientLoginForm.spec.ts +46 -0
- package/src/components/Amelipro/AmeliproPatientLogin/AmeliproPatientLoginForm/__tests__/__snapshots__/AmeliproPatientLoginForm.spec.ts.snap +33 -0
- package/src/components/Amelipro/AmeliproPatientLogin/AmeliproPatientLoginForm/types.d.ts +6 -0
- package/src/components/Amelipro/AmeliproPatientLogin/__tests__/AmeliproPatientLogin.spec.ts +49 -0
- package/src/components/Amelipro/AmeliproPatientLogin/__tests__/__snapshots__/AmeliproPatientLogin.spec.ts.snap +60 -0
- package/src/components/Amelipro/AmeliproPatientLogin/types.d.ts +6 -0
- package/src/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressCityRow/AmeliproPostalAddressCityRow.vue +464 -0
- package/src/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressCityRow/__tests__/AmeliproPostalAddressCityRow.spec.ts +41 -0
- package/src/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressCityRow/__tests__/__snapshots__/AmeliproPostalAddressCityRow.spec.ts.snap +548 -0
- package/src/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressCityRow/types.d.ts +12 -0
- package/src/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressField.mdx +15 -0
- package/src/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressField.stories.ts +133 -0
- package/src/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressField.vue +360 -0
- package/src/components/Amelipro/AmeliproPostalAddressField/tests/AmeliproPostalAddressField.spec.ts +27 -0
- package/src/components/Amelipro/AmeliproPostalAddressField/tests/__snapshots__/AmeliproPostalAddressField.spec.ts.snap +548 -0
- package/src/components/Amelipro/AmeliproPostalAddressField/types.d.ts +18 -0
- package/src/components/Amelipro/AmeliproRadioGroup/AmeliproRadioGroup.vue +4 -3
- package/src/components/Amelipro/AmeliproResultList/AmeliproResultList.vue +2 -2
- package/src/components/Amelipro/AmeliproResultList/__tests__/__snapshots__/AmeliproResultList.spec.ts.snap +0 -4
- package/src/components/Amelipro/AmeliproStateTile/AmeliproStateTile.stories.ts +210 -0
- package/src/components/Amelipro/AmeliproStatus/AmeliproStatus.stories.ts +326 -0
- package/src/components/Amelipro/AmeliproTable/AmeliproTable.stories.ts +232 -4
- package/src/components/Amelipro/AmeliproTable/AmeliproTable.vue +3 -2
- package/src/components/Amelipro/AmeliproTable/__tests__/__snapshots__/AmeliproTable.spec.ts.snap +0 -4
- package/src/components/Amelipro/AmeliproTabs/AmeliproTabs.vue +1 -1
- package/src/components/Amelipro/AmeliproTextField/AmeliproTextField.stories.ts +2 -2
- package/src/components/Amelipro/AmeliproTileBtn/AmeliproTileBtn.stories.ts +222 -6
- package/src/components/Amelipro/AmeliproTooltips/AmeliproTooltips.stories.ts +169 -0
- package/src/components/Amelipro/AmeliproTooltips/AmeliproTooltips.vue +6 -1
- package/src/components/Amelipro/AmeliproTooltips/tests/__snapshots__/AmeliproTooltips.spec.ts.snap +1 -5
- package/src/components/Amelipro/AmeliproTransmission/AmeliproTransmission.stories.ts +160 -0
- package/src/components/Amelipro/StructureMenu/StructureMenu.vue +1 -1
- package/src/components/Amelipro/StructureMenu/tests/__snapshots__/StructureMenu.spec.ts.snap +1 -2
- package/src/components/Customs/Selects/SySelect/SySelect.vue +43 -1
- package/src/components/Customs/SyCheckbox/SyCheckbox.vue +4 -0
- package/src/components/Customs/SyForm/Introduction.mdx +132 -0
- package/src/components/Customs/SyForm/SyForm.mdx +105 -0
- package/src/components/Customs/SyForm/SyForm.stories.ts +375 -0
- package/src/components/Customs/SyForm/SyForm.vue +80 -0
- package/src/components/Customs/SyTabs/SyTabs.stories.ts +31 -0
- package/src/components/Customs/SyTabs/SyTabs.vue +185 -27
- package/src/components/Customs/SyTabs/useTabTransition.ts +42 -0
- package/src/components/Customs/SyTextField/SyTextField.vue +12 -3
- package/src/components/Customs/SyTextField/types.d.ts +1 -1
- package/src/components/DataListItem/DataListItem.vue +12 -13
- package/src/components/DatePicker/CalendarMode/DatePicker.stories.ts +242 -41
- package/src/components/DatePicker/CalendarMode/DatePicker.vue +30 -12
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +246 -59
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +40 -10
- package/src/components/DatePicker/DatePickerOverview.mdx +5 -1
- package/src/components/DatePicker/DatePickerValidationExample/DatePickerValidation.mdx +21 -21
- package/src/components/DatePicker/DatePickerValidationExample/DatePickerValidation.stories.ts +240 -133
- package/src/components/DatePicker/DateTextInput/DateRange.stories.ts +29 -1
- package/src/components/DatePicker/DateTextInput/DateTextInput.vue +32 -9
- package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +166 -38
- package/src/components/DatePicker/composables/useDateValidation.ts +8 -5
- package/src/components/DatePicker/composables/useManualDateValidation.ts +23 -6
- package/src/components/DatePicker/datePickers.stories.ts +28 -0
- package/src/components/DatePicker/docExamples/DatePickerBidirectionalValidation.vue +47 -58
- package/src/components/DatePicker/docExamples/DatePickerValidationExamples.vue +2 -2
- package/src/components/DatePicker/tests/DatePicker.validation.spec.ts +4654 -0
- package/src/components/DatePicker/tests/archiTest.md +33 -0
- package/src/components/DatePicker/tests/setup.ts +243 -0
- package/src/components/DialogBox/DialogBox.stories.ts +1 -1
- package/src/components/DialogBox/DialogBox.vue +25 -8
- package/src/components/DialogBox/locales.ts +1 -0
- package/src/components/DialogBox/tests/DialogBox.spec.ts +187 -15
- package/src/components/DialogBox/useDraggable.ts +92 -4
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.vue +4 -0
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/tests/__snapshots__/HeaderMenuItem.spec.ts.snap +4 -1
- package/src/components/HeaderNavigationBar/HeaderNavigationBar.vue +18 -2
- package/src/components/HeaderNavigationBar/HorizontalNavbar/HorizontalNavbar.vue +14 -4
- package/src/components/HeaderNavigationBar/types.ts +1 -0
- package/src/components/HeaderToolbar/Accessibilite.stories.ts +8 -0
- package/src/components/HeaderToolbar/HeaderToolbar.mdx +0 -1
- package/src/components/HeaderToolbar/HeaderToolbar.stories.ts +65 -6
- package/src/components/HeaderToolbar/HeaderToolbar.vue +589 -162
- package/src/components/HeaderToolbar/locales.ts +3 -0
- package/src/components/HeaderToolbar/useMobileRightMenu.ts +121 -0
- package/src/components/NirField/Accessibilite.stories.ts +4 -0
- package/src/components/NirField/NirField.stories.ts +0 -11
- package/src/components/NirField/NirField.vue +164 -53
- package/src/components/NirField/locales.ts +6 -4
- package/src/components/NirField/tests/NirField.spec.ts +2 -2
- package/src/components/PasswordField/Accessibilite.stories.ts +96 -0
- package/src/components/PasswordField/PasswordField.stories.ts +8 -1
- package/src/components/PasswordField/PasswordField.vue +98 -19
- package/src/components/PasswordField/locales.ts +2 -0
- package/src/components/PasswordField/tests/PasswordField.spec.ts +1 -1
- package/src/components/PhoneField/PhoneField.vue +4 -0
- package/src/components/RangeField/Accessibilite.stories.ts +4 -0
- package/src/components/RangeField/RangeField.stories.ts +60 -0
- package/src/components/RangeField/RangeField.vue +37 -21
- package/src/components/RangeField/RangeSlider/RangeSlider.vue +30 -8
- package/src/components/RangeField/RangeSlider/Tooltip/Tooltip.vue +1 -0
- package/src/components/RangeField/RangeSlider/tests/__snapshots__/rangeSlider.spec.ts.snap +12 -4
- package/src/components/RangeField/RangeSlider/tests/useMouseSlide.spec.ts +9 -1
- package/src/components/RangeField/RangeSlider/useMouseSlide.ts +23 -8
- package/src/components/RangeField/config.ts +3 -1
- package/src/components/RangeField/tests/__snapshots__/RangeField.spec.ts.snap +132 -141
- package/src/components/RatingPicker/Accessibilite.stories.ts +4 -0
- package/src/components/RatingPicker/EmotionPicker/EmotionPicker.vue +119 -66
- package/src/components/RatingPicker/EmotionPicker/locales.ts +2 -0
- package/src/components/RatingPicker/EmotionPicker/tests/EmotionPicker.spec.ts +4 -4
- package/src/components/RatingPicker/EmotionPicker/tests/__snapshots__/EmotionPicker.spec.ts.snap +462 -678
- package/src/components/RatingPicker/NumberPicker/NumberPicker.vue +106 -42
- package/src/components/RatingPicker/NumberPicker/tests/NumberPicker.spec.ts +3 -3
- package/src/components/RatingPicker/NumberPicker/tests/__snapshots__/NumberPicker.spec.ts.snap +119 -515
- package/src/components/RatingPicker/Rating.ts +5 -1
- package/src/components/RatingPicker/RatingPicker.stories.ts +5 -6
- package/src/components/RatingPicker/RatingPicker.vue +7 -2
- package/src/components/RatingPicker/StarsPicker/StarsPicker.vue +78 -42
- package/src/components/RatingPicker/StarsPicker/tests/StarsPicker.spec.ts +7 -7
- package/src/components/RatingPicker/StarsPicker/tests/__snapshots__/StarsPicker.spec.ts.snap +163 -245
- package/src/components/RatingPicker/locales.ts +1 -0
- package/src/components/RatingPicker/tests/__snapshots__/RatingPicker.spec.ts.snap +120 -516
- package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +109 -84
- package/src/components/Tables/SyServerTable/SyServerTable.vue +51 -16
- package/src/components/Tables/SyTable/SyTable.vue +1 -6
- package/src/components/Tables/SyTable/tests/SyTable.spec.ts +6 -0
- package/src/components/Tables/common/SyTablePagination.vue +0 -6
- package/src/components/Tables/common/tableProps.ts +19 -1
- package/src/components/Tables/common/usePagination.ts +0 -6
- package/src/components/Tables/common/useTableCheckbox.ts +5 -5
- package/src/components/index.ts +8 -0
- package/src/composables/rules/useFieldValidation.ts +21 -3
- package/src/composables/validation/AvecVosComposants.mdx +145 -0
- package/src/composables/validation/FormValidation.mdx +151 -0
- package/src/composables/validation/FormValidation.stories.ts +402 -0
- package/src/composables/validation/useFormValidation.ts +91 -0
- package/src/composables/validation/useValidatable.ts +41 -0
- package/src/stories/Accessibilite/Avancement/Avancement.stories.ts +2 -2
- package/src/stories/Accessibilite/KitDePreAudit/Outils/Introduction.mdx +2 -2
- package/src/stories/Accessibilite/KitDePreAudit/Preaudit.mdx +2 -2
- package/src/stories/Demarrer/Accueil.stories.ts +6 -6
- package/src/stories/GuideDuDev/Installation.mdx +13 -0
- package/src/stories/GuideDuDev/LesBreackingChanges.mdx +1 -1
- package/src/stories/GuideDuDev/MigrationDepuisBridge.mdx +1 -1
- package/src/stories/GuideDuDev/MigrationDepuisVue2.mdx +1 -1
|
@@ -0,0 +1,4654 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import { nextTick, ref, computed } from 'vue'
|
|
4
|
+
import { vuetify } from '../../../../tests/unit/setup'
|
|
5
|
+
import DatePicker from '@/components/DatePicker/CalendarMode/DatePicker.vue'
|
|
6
|
+
/**
|
|
7
|
+
* Tests de validation complets pour tous les modes DatePicker
|
|
8
|
+
*
|
|
9
|
+
* Ce fichier couvre tous les cas de validation pour les 3 modes DatePicker :
|
|
10
|
+
* 1. CalendarMode - Mode calendrier classique
|
|
11
|
+
* 2. DatePicker - Mode complexe standard
|
|
12
|
+
* 3. DatePicker avec useCombinedMode - Mode combiné
|
|
13
|
+
* 4. DatePicker - Mode saisie texte uniquement
|
|
14
|
+
*
|
|
15
|
+
* Basé sur les mémoires de bugs résolus et les cas edge identifiés.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// Import des composants DatePicker
|
|
19
|
+
|
|
20
|
+
describe('DatePicker - Tests de Validation Complets', () => {
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- tests
|
|
22
|
+
let wrapper: any
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
vi.clearAllMocks()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
if (wrapper) {
|
|
30
|
+
wrapper.unmount()
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* TESTS POUR CALENDARMODE DATEPICKER
|
|
36
|
+
*/
|
|
37
|
+
describe('CalendarMode DatePicker', () => {
|
|
38
|
+
describe('Cas normaux - Fonctionnement de base', () => {
|
|
39
|
+
it('doit afficher le composant avec les props par défaut', async () => {
|
|
40
|
+
wrapper = mount(DatePicker, {
|
|
41
|
+
global: {
|
|
42
|
+
plugins: [vuetify],
|
|
43
|
+
},
|
|
44
|
+
props: {
|
|
45
|
+
modelValue: null,
|
|
46
|
+
label: 'Date de test',
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
await nextTick()
|
|
51
|
+
|
|
52
|
+
expect(wrapper.exists()).toBe(true)
|
|
53
|
+
expect(wrapper.find('input').exists()).toBe(true)
|
|
54
|
+
expect(wrapper.find('label').text()).toContain('Date de test')
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('doit accepter une valeur initiale', async () => {
|
|
58
|
+
const initialDate = '2024-06-15'
|
|
59
|
+
wrapper = mount(DatePicker, {
|
|
60
|
+
global: {
|
|
61
|
+
plugins: [vuetify],
|
|
62
|
+
},
|
|
63
|
+
props: {
|
|
64
|
+
modelValue: initialDate,
|
|
65
|
+
label: 'Date avec valeur initiale',
|
|
66
|
+
},
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
await nextTick()
|
|
70
|
+
|
|
71
|
+
// Vérifier que le composant existe
|
|
72
|
+
expect(wrapper.exists()).toBe(true)
|
|
73
|
+
expect(wrapper.props('modelValue')).toBe(initialDate)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('doit gérer le format européen DD/MM/YYYY', async () => {
|
|
77
|
+
wrapper = mount(DatePicker, {
|
|
78
|
+
global: {
|
|
79
|
+
plugins: [vuetify],
|
|
80
|
+
},
|
|
81
|
+
props: {
|
|
82
|
+
modelValue: null,
|
|
83
|
+
label: 'Date format européen',
|
|
84
|
+
format: 'DD/MM/YYYY',
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
await nextTick()
|
|
89
|
+
|
|
90
|
+
expect(wrapper.exists()).toBe(true)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('doit gérer les différents formats de date', async () => {
|
|
94
|
+
const formats = ['DD/MM/YYYY', 'MM/DD/YYYY', 'YYYY-MM-DD']
|
|
95
|
+
|
|
96
|
+
for (const format of formats) {
|
|
97
|
+
wrapper = mount(DatePicker, {
|
|
98
|
+
global: {
|
|
99
|
+
plugins: [vuetify],
|
|
100
|
+
},
|
|
101
|
+
props: {
|
|
102
|
+
modelValue: null,
|
|
103
|
+
label: `Date format ${format}`,
|
|
104
|
+
format,
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
await nextTick()
|
|
109
|
+
expect(wrapper.exists()).toBe(true)
|
|
110
|
+
wrapper.unmount()
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('doit gérer le mode date de naissance', async () => {
|
|
115
|
+
wrapper = mount(DatePicker, {
|
|
116
|
+
global: {
|
|
117
|
+
plugins: [vuetify],
|
|
118
|
+
},
|
|
119
|
+
props: {
|
|
120
|
+
modelValue: null,
|
|
121
|
+
label: 'Date de naissance',
|
|
122
|
+
birthDate: true,
|
|
123
|
+
},
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
await nextTick()
|
|
127
|
+
|
|
128
|
+
expect(wrapper.exists()).toBe(true)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('doit gérer les plages de dates', async () => {
|
|
132
|
+
wrapper = mount(DatePicker, {
|
|
133
|
+
global: {
|
|
134
|
+
plugins: [vuetify],
|
|
135
|
+
},
|
|
136
|
+
props: {
|
|
137
|
+
modelValue: null,
|
|
138
|
+
label: 'Plage de dates',
|
|
139
|
+
displayRange: true,
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
await nextTick()
|
|
144
|
+
|
|
145
|
+
expect(wrapper.exists()).toBe(true)
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
describe('États et propriétés', () => {
|
|
150
|
+
it('doit gérer l\'état required', async () => {
|
|
151
|
+
wrapper = mount(DatePicker, {
|
|
152
|
+
global: {
|
|
153
|
+
plugins: [vuetify],
|
|
154
|
+
},
|
|
155
|
+
props: {
|
|
156
|
+
modelValue: null,
|
|
157
|
+
label: 'Date obligatoire',
|
|
158
|
+
required: true,
|
|
159
|
+
},
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
await nextTick()
|
|
163
|
+
|
|
164
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
165
|
+
expect(result).toBe(false)
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('doit gérer l\'état disabled', async () => {
|
|
169
|
+
wrapper = mount(DatePicker, {
|
|
170
|
+
global: {
|
|
171
|
+
plugins: [vuetify],
|
|
172
|
+
},
|
|
173
|
+
props: {
|
|
174
|
+
modelValue: null,
|
|
175
|
+
label: 'Date désactivée',
|
|
176
|
+
disabled: true,
|
|
177
|
+
},
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
await nextTick()
|
|
181
|
+
|
|
182
|
+
const input = wrapper.find('input')
|
|
183
|
+
expect(input.attributes('disabled')).toBeDefined()
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('doit gérer l\'état readonly', async () => {
|
|
187
|
+
wrapper = mount(DatePicker, {
|
|
188
|
+
global: {
|
|
189
|
+
plugins: [vuetify],
|
|
190
|
+
},
|
|
191
|
+
props: {
|
|
192
|
+
modelValue: '2024-06-15',
|
|
193
|
+
label: 'Date lecture seule',
|
|
194
|
+
readonly: true,
|
|
195
|
+
},
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
await nextTick()
|
|
199
|
+
|
|
200
|
+
const input = wrapper.find('input')
|
|
201
|
+
expect(input.attributes('readonly')).toBeDefined()
|
|
202
|
+
})
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
describe('Icônes et affichage', () => {
|
|
206
|
+
it('doit afficher l\'icône par défaut', async () => {
|
|
207
|
+
wrapper = mount(DatePicker, {
|
|
208
|
+
global: {
|
|
209
|
+
plugins: [vuetify],
|
|
210
|
+
},
|
|
211
|
+
props: {
|
|
212
|
+
modelValue: null,
|
|
213
|
+
label: 'Date avec icône',
|
|
214
|
+
},
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
await nextTick()
|
|
218
|
+
|
|
219
|
+
expect(wrapper.find('.v-icon').exists()).toBe(true)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('doit masquer les icônes avec noIcon', async () => {
|
|
223
|
+
wrapper = mount(DatePicker, {
|
|
224
|
+
global: {
|
|
225
|
+
plugins: [vuetify],
|
|
226
|
+
},
|
|
227
|
+
props: {
|
|
228
|
+
modelValue: null,
|
|
229
|
+
label: 'Date sans icône',
|
|
230
|
+
noIcon: true,
|
|
231
|
+
},
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
await nextTick()
|
|
235
|
+
|
|
236
|
+
expect(wrapper.exists()).toBe(true)
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
it('doit gérer l\'icône en append', async () => {
|
|
240
|
+
wrapper = mount(DatePicker, {
|
|
241
|
+
global: {
|
|
242
|
+
plugins: [vuetify],
|
|
243
|
+
},
|
|
244
|
+
props: {
|
|
245
|
+
modelValue: null,
|
|
246
|
+
label: 'Date avec append icon',
|
|
247
|
+
displayAppendIcon: true,
|
|
248
|
+
},
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
await nextTick()
|
|
252
|
+
|
|
253
|
+
expect(wrapper.exists()).toBe(true)
|
|
254
|
+
})
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
describe('Messages de validation', () => {
|
|
258
|
+
it('doit afficher des messages d\'erreur', async () => {
|
|
259
|
+
wrapper = mount(DatePicker, {
|
|
260
|
+
global: {
|
|
261
|
+
plugins: [vuetify],
|
|
262
|
+
},
|
|
263
|
+
props: {
|
|
264
|
+
modelValue: null,
|
|
265
|
+
label: 'Date avec erreur',
|
|
266
|
+
errorMessages: ['Erreur de test'],
|
|
267
|
+
},
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
await nextTick()
|
|
271
|
+
|
|
272
|
+
expect(wrapper.exists()).toBe(true)
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
it('doit afficher des messages de succès', async () => {
|
|
276
|
+
wrapper = mount(DatePicker, {
|
|
277
|
+
global: {
|
|
278
|
+
plugins: [vuetify],
|
|
279
|
+
},
|
|
280
|
+
props: {
|
|
281
|
+
modelValue: '2024-06-15',
|
|
282
|
+
label: 'Date avec succès',
|
|
283
|
+
successMessages: ['Validation réussie'],
|
|
284
|
+
},
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
await nextTick()
|
|
288
|
+
|
|
289
|
+
expect(wrapper.exists()).toBe(true)
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
it('doit afficher des messages d\'avertissement', async () => {
|
|
293
|
+
wrapper = mount(DatePicker, {
|
|
294
|
+
global: {
|
|
295
|
+
plugins: [vuetify],
|
|
296
|
+
},
|
|
297
|
+
props: {
|
|
298
|
+
modelValue: '2024-06-15',
|
|
299
|
+
label: 'Date avec avertissement',
|
|
300
|
+
warningMessages: ['Avertissement de test'],
|
|
301
|
+
},
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
await nextTick()
|
|
305
|
+
|
|
306
|
+
expect(wrapper.exists()).toBe(true)
|
|
307
|
+
})
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
describe('Événements', () => {
|
|
311
|
+
it('doit émettre l\'événement focus', async () => {
|
|
312
|
+
wrapper = mount(DatePicker, {
|
|
313
|
+
global: {
|
|
314
|
+
plugins: [vuetify],
|
|
315
|
+
},
|
|
316
|
+
props: {
|
|
317
|
+
modelValue: null,
|
|
318
|
+
label: 'Date événement focus',
|
|
319
|
+
},
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
await nextTick()
|
|
323
|
+
|
|
324
|
+
const input = wrapper.find('input')
|
|
325
|
+
await input.trigger('focus')
|
|
326
|
+
|
|
327
|
+
expect(wrapper.emitted('focus')).toBeTruthy()
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
it('doit émettre l\'événement blur', async () => {
|
|
331
|
+
wrapper = mount(DatePicker, {
|
|
332
|
+
global: {
|
|
333
|
+
plugins: [vuetify],
|
|
334
|
+
},
|
|
335
|
+
props: {
|
|
336
|
+
modelValue: null,
|
|
337
|
+
label: 'Date événement blur',
|
|
338
|
+
},
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
await nextTick()
|
|
342
|
+
|
|
343
|
+
const input = wrapper.find('input')
|
|
344
|
+
await input.trigger('focus')
|
|
345
|
+
await input.trigger('blur')
|
|
346
|
+
|
|
347
|
+
expect(wrapper.emitted('blur')).toBeTruthy()
|
|
348
|
+
})
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
describe('Custom rules sur champs vides (Mémoire b5baeb0e)', () => {
|
|
352
|
+
it('doit exécuter les custom rules sur champ vide avec validateOnSubmit()', async () => {
|
|
353
|
+
const customRuleMock = vi.fn().mockReturnValue(false)
|
|
354
|
+
const customRules = [
|
|
355
|
+
{
|
|
356
|
+
type: 'custom',
|
|
357
|
+
options: {
|
|
358
|
+
validate: customRuleMock,
|
|
359
|
+
message: 'Champ obligatoire',
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
]
|
|
363
|
+
|
|
364
|
+
wrapper = mount(DatePicker, {
|
|
365
|
+
global: {
|
|
366
|
+
plugins: [vuetify],
|
|
367
|
+
},
|
|
368
|
+
props: {
|
|
369
|
+
modelValue: null,
|
|
370
|
+
label: 'Date CalendarMode',
|
|
371
|
+
customRules,
|
|
372
|
+
},
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
await nextTick()
|
|
376
|
+
|
|
377
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
378
|
+
expect(customRuleMock).toHaveBeenCalledWith(null)
|
|
379
|
+
expect(result).toBe(false)
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
it('doit exécuter les custom rules après interaction utilisateur', async () => {
|
|
383
|
+
const customRuleMock = vi.fn().mockReturnValue(false)
|
|
384
|
+
const customRules = [
|
|
385
|
+
{
|
|
386
|
+
type: 'custom',
|
|
387
|
+
options: {
|
|
388
|
+
validate: customRuleMock,
|
|
389
|
+
message: 'Erreur après interaction',
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
]
|
|
393
|
+
|
|
394
|
+
wrapper = mount(DatePicker, {
|
|
395
|
+
global: {
|
|
396
|
+
plugins: [vuetify],
|
|
397
|
+
},
|
|
398
|
+
props: {
|
|
399
|
+
modelValue: null,
|
|
400
|
+
label: 'Date CalendarMode',
|
|
401
|
+
customRules,
|
|
402
|
+
},
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
await nextTick()
|
|
406
|
+
|
|
407
|
+
// Simuler interaction utilisateur
|
|
408
|
+
const input = wrapper.find('input')
|
|
409
|
+
await input.trigger('focus')
|
|
410
|
+
await input.trigger('blur')
|
|
411
|
+
|
|
412
|
+
expect(customRuleMock).toHaveBeenCalledWith(null)
|
|
413
|
+
})
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
describe('Validation avec required', () => {
|
|
417
|
+
it('doit afficher erreur required sur champ vide', async () => {
|
|
418
|
+
wrapper = mount(DatePicker, {
|
|
419
|
+
global: {
|
|
420
|
+
plugins: [vuetify],
|
|
421
|
+
},
|
|
422
|
+
props: {
|
|
423
|
+
modelValue: null,
|
|
424
|
+
label: 'Date CalendarMode',
|
|
425
|
+
required: true,
|
|
426
|
+
},
|
|
427
|
+
})
|
|
428
|
+
|
|
429
|
+
await nextTick()
|
|
430
|
+
|
|
431
|
+
// Simuler interaction
|
|
432
|
+
const input = wrapper.find('input')
|
|
433
|
+
await input.trigger('focus')
|
|
434
|
+
await input.trigger('blur')
|
|
435
|
+
|
|
436
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
437
|
+
expect(result).toBe(false)
|
|
438
|
+
})
|
|
439
|
+
})
|
|
440
|
+
})
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* TESTS POUR COMPLEX DATEPICKER (MODE STANDARD)
|
|
444
|
+
*/
|
|
445
|
+
describe('DatePicker - Mode Standard', () => {
|
|
446
|
+
describe('Cas normaux - Fonctionnement de base', () => {
|
|
447
|
+
it('doit afficher le composant avec les props par défaut', async () => {
|
|
448
|
+
wrapper = mount(DatePicker, {
|
|
449
|
+
global: {
|
|
450
|
+
plugins: [vuetify],
|
|
451
|
+
},
|
|
452
|
+
props: {
|
|
453
|
+
useCombinedMode: true,
|
|
454
|
+
modelValue: null,
|
|
455
|
+
label: 'Date DatePicker',
|
|
456
|
+
},
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
await nextTick()
|
|
460
|
+
|
|
461
|
+
expect(wrapper.exists()).toBe(true)
|
|
462
|
+
expect(wrapper.find('input').exists()).toBe(true)
|
|
463
|
+
})
|
|
464
|
+
|
|
465
|
+
it('doit gérer le mode combined', async () => {
|
|
466
|
+
wrapper = mount(DatePicker, {
|
|
467
|
+
global: {
|
|
468
|
+
plugins: [vuetify],
|
|
469
|
+
},
|
|
470
|
+
props: {
|
|
471
|
+
useCombinedMode: true,
|
|
472
|
+
modelValue: null,
|
|
473
|
+
label: 'Date Combined Mode',
|
|
474
|
+
},
|
|
475
|
+
})
|
|
476
|
+
|
|
477
|
+
await nextTick()
|
|
478
|
+
|
|
479
|
+
expect(wrapper.exists()).toBe(true)
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
it('doit gérer les plages de dates', async () => {
|
|
483
|
+
wrapper = mount(DatePicker, {
|
|
484
|
+
global: {
|
|
485
|
+
plugins: [vuetify],
|
|
486
|
+
},
|
|
487
|
+
props: {
|
|
488
|
+
useCombinedMode: true,
|
|
489
|
+
modelValue: null,
|
|
490
|
+
label: 'Plage de dates Complex',
|
|
491
|
+
displayRange: true,
|
|
492
|
+
},
|
|
493
|
+
})
|
|
494
|
+
|
|
495
|
+
await nextTick()
|
|
496
|
+
|
|
497
|
+
expect(wrapper.exists()).toBe(true)
|
|
498
|
+
})
|
|
499
|
+
|
|
500
|
+
it('doit gérer le formatage automatique', async () => {
|
|
501
|
+
wrapper = mount(DatePicker, {
|
|
502
|
+
global: {
|
|
503
|
+
plugins: [vuetify],
|
|
504
|
+
},
|
|
505
|
+
props: {
|
|
506
|
+
useCombinedMode: true,
|
|
507
|
+
modelValue: null,
|
|
508
|
+
label: 'Date auto format',
|
|
509
|
+
autoClamp: true,
|
|
510
|
+
},
|
|
511
|
+
})
|
|
512
|
+
|
|
513
|
+
await nextTick()
|
|
514
|
+
|
|
515
|
+
expect(wrapper.exists()).toBe(true)
|
|
516
|
+
})
|
|
517
|
+
|
|
518
|
+
it('doit gérer le mode readonly', async () => {
|
|
519
|
+
wrapper = mount(DatePicker, {
|
|
520
|
+
global: {
|
|
521
|
+
plugins: [vuetify],
|
|
522
|
+
},
|
|
523
|
+
props: {
|
|
524
|
+
useCombinedMode: true,
|
|
525
|
+
modelValue: '2024-06-15',
|
|
526
|
+
label: 'Date readonly',
|
|
527
|
+
readonly: true,
|
|
528
|
+
},
|
|
529
|
+
})
|
|
530
|
+
|
|
531
|
+
await nextTick()
|
|
532
|
+
|
|
533
|
+
expect(wrapper.exists()).toBe(true)
|
|
534
|
+
})
|
|
535
|
+
|
|
536
|
+
it('doit gérer les custom rules de succès', async () => {
|
|
537
|
+
wrapper = mount(DatePicker, {
|
|
538
|
+
global: {
|
|
539
|
+
plugins: [vuetify],
|
|
540
|
+
},
|
|
541
|
+
props: {
|
|
542
|
+
useCombinedMode: true,
|
|
543
|
+
modelValue: '2024-06-15',
|
|
544
|
+
label: 'Date avec succès',
|
|
545
|
+
},
|
|
546
|
+
})
|
|
547
|
+
|
|
548
|
+
await nextTick()
|
|
549
|
+
|
|
550
|
+
// Vérifier que le composant existe
|
|
551
|
+
expect(wrapper.exists()).toBe(true)
|
|
552
|
+
expect(wrapper.find('input').exists()).toBe(true)
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
it('doit gérer les custom warning rules', async () => {
|
|
556
|
+
wrapper = mount(DatePicker, {
|
|
557
|
+
global: {
|
|
558
|
+
plugins: [vuetify],
|
|
559
|
+
},
|
|
560
|
+
props: {
|
|
561
|
+
useCombinedMode: true,
|
|
562
|
+
modelValue: '2024-06-15',
|
|
563
|
+
label: 'Date avec warning',
|
|
564
|
+
customWarningRules: [],
|
|
565
|
+
},
|
|
566
|
+
})
|
|
567
|
+
|
|
568
|
+
await nextTick()
|
|
569
|
+
|
|
570
|
+
// Vérifier que le composant existe et gère les warning rules
|
|
571
|
+
expect(wrapper.exists()).toBe(true)
|
|
572
|
+
expect(wrapper.props('customWarningRules')).toEqual([])
|
|
573
|
+
})
|
|
574
|
+
})
|
|
575
|
+
|
|
576
|
+
describe('Validation avec règles réactives (Mémoire 2196b67a)', () => {
|
|
577
|
+
it('doit gérer les règles réactives correctement', async () => {
|
|
578
|
+
const dateA = ref('2024-06-15')
|
|
579
|
+
const customRuleMock = vi.fn().mockReturnValue(true)
|
|
580
|
+
|
|
581
|
+
const dateBRules = computed(() => [
|
|
582
|
+
{
|
|
583
|
+
type: 'custom',
|
|
584
|
+
options: {
|
|
585
|
+
validate: customRuleMock,
|
|
586
|
+
message: `Date doit être après ${dateA.value}`,
|
|
587
|
+
},
|
|
588
|
+
},
|
|
589
|
+
])
|
|
590
|
+
|
|
591
|
+
wrapper = mount(DatePicker, {
|
|
592
|
+
global: {
|
|
593
|
+
plugins: [vuetify],
|
|
594
|
+
},
|
|
595
|
+
props: {
|
|
596
|
+
useCombinedMode: true,
|
|
597
|
+
modelValue: null,
|
|
598
|
+
label: 'Date B',
|
|
599
|
+
customRules: dateBRules.value,
|
|
600
|
+
},
|
|
601
|
+
})
|
|
602
|
+
|
|
603
|
+
await nextTick()
|
|
604
|
+
|
|
605
|
+
// Validation initiale
|
|
606
|
+
wrapper.vm.validateOnSubmit()
|
|
607
|
+
expect(customRuleMock).toHaveBeenCalled()
|
|
608
|
+
|
|
609
|
+
// Changer dateA et re-valider
|
|
610
|
+
dateA.value = '2024-07-01'
|
|
611
|
+
await wrapper.setProps({ customRules: dateBRules.value })
|
|
612
|
+
await nextTick()
|
|
613
|
+
|
|
614
|
+
wrapper.vm.validateOnSubmit()
|
|
615
|
+
expect(customRuleMock).toHaveBeenCalled()
|
|
616
|
+
})
|
|
617
|
+
})
|
|
618
|
+
})
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* TESTS POUR COMPLEX DATEPICKER (MODE COMBINÉ)
|
|
622
|
+
*/
|
|
623
|
+
describe('DatePicker - Mode Combiné (useCombinedMode=true)', () => {
|
|
624
|
+
describe('Messages d\'erreur en combined-mode (Mémoire a60921cf)', () => {
|
|
625
|
+
it('doit maintenir la réactivité des règles en combined-mode', async () => {
|
|
626
|
+
const dateA = ref('2024-06-15')
|
|
627
|
+
const customRuleMock = vi.fn().mockReturnValue(true)
|
|
628
|
+
|
|
629
|
+
const dateBRules = computed(() => [
|
|
630
|
+
{
|
|
631
|
+
type: 'custom',
|
|
632
|
+
options: {
|
|
633
|
+
validate: customRuleMock,
|
|
634
|
+
message: `Date doit être après ${dateA.value}`,
|
|
635
|
+
},
|
|
636
|
+
},
|
|
637
|
+
])
|
|
638
|
+
|
|
639
|
+
wrapper = mount(DatePicker, {
|
|
640
|
+
global: {
|
|
641
|
+
plugins: [vuetify],
|
|
642
|
+
},
|
|
643
|
+
props: {
|
|
644
|
+
useCombinedMode: true,
|
|
645
|
+
modelValue: null,
|
|
646
|
+
label: 'Date B Combined',
|
|
647
|
+
customRules: dateBRules.value,
|
|
648
|
+
},
|
|
649
|
+
})
|
|
650
|
+
|
|
651
|
+
await nextTick()
|
|
652
|
+
|
|
653
|
+
// Validation initiale
|
|
654
|
+
wrapper.vm.validateOnSubmit()
|
|
655
|
+
expect(customRuleMock).toHaveBeenCalled()
|
|
656
|
+
|
|
657
|
+
// Changer dateA et vérifier la réactivité
|
|
658
|
+
dateA.value = '2024-07-01'
|
|
659
|
+
await wrapper.setProps({ customRules: dateBRules.value })
|
|
660
|
+
await nextTick()
|
|
661
|
+
|
|
662
|
+
wrapper.vm.validateOnSubmit()
|
|
663
|
+
expect(customRuleMock).toHaveBeenCalled()
|
|
664
|
+
})
|
|
665
|
+
})
|
|
666
|
+
})
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* TESTS POUR DATETEXTINPUT
|
|
670
|
+
*/
|
|
671
|
+
describe('DatePicker - Mode Saisie Texte', () => {
|
|
672
|
+
describe('Cas normaux - Fonctionnement de base', () => {
|
|
673
|
+
it('doit afficher le composant avec les props par défaut', async () => {
|
|
674
|
+
wrapper = mount(DatePicker, {
|
|
675
|
+
global: {
|
|
676
|
+
plugins: [vuetify],
|
|
677
|
+
},
|
|
678
|
+
props: {
|
|
679
|
+
noCalendar: true,
|
|
680
|
+
modelValue: null,
|
|
681
|
+
label: 'Date TextInput',
|
|
682
|
+
},
|
|
683
|
+
})
|
|
684
|
+
|
|
685
|
+
await nextTick()
|
|
686
|
+
|
|
687
|
+
expect(wrapper.exists()).toBe(true)
|
|
688
|
+
expect(wrapper.find('input').exists()).toBe(true)
|
|
689
|
+
})
|
|
690
|
+
|
|
691
|
+
it('doit formater automatiquement la saisie', async () => {
|
|
692
|
+
wrapper = mount(DatePicker, {
|
|
693
|
+
global: {
|
|
694
|
+
plugins: [vuetify],
|
|
695
|
+
},
|
|
696
|
+
props: {
|
|
697
|
+
noCalendar: true,
|
|
698
|
+
modelValue: null,
|
|
699
|
+
label: 'Date avec formatage',
|
|
700
|
+
format: 'DD/MM/YYYY',
|
|
701
|
+
},
|
|
702
|
+
})
|
|
703
|
+
|
|
704
|
+
await nextTick()
|
|
705
|
+
|
|
706
|
+
const input = wrapper.find('input')
|
|
707
|
+
await input.setValue('15062024')
|
|
708
|
+
await input.trigger('blur')
|
|
709
|
+
|
|
710
|
+
expect(wrapper.exists()).toBe(true)
|
|
711
|
+
})
|
|
712
|
+
|
|
713
|
+
it('doit gérer les différents formats', async () => {
|
|
714
|
+
const formats = ['DD/MM/YYYY', 'MM/DD/YYYY', 'YYYY-MM-DD']
|
|
715
|
+
|
|
716
|
+
for (const format of formats) {
|
|
717
|
+
wrapper = mount(DatePicker, {
|
|
718
|
+
global: {
|
|
719
|
+
plugins: [vuetify],
|
|
720
|
+
},
|
|
721
|
+
props: {
|
|
722
|
+
noCalendar: true,
|
|
723
|
+
modelValue: null,
|
|
724
|
+
label: `Date format ${format}`,
|
|
725
|
+
format,
|
|
726
|
+
},
|
|
727
|
+
})
|
|
728
|
+
|
|
729
|
+
await nextTick()
|
|
730
|
+
expect(wrapper.exists()).toBe(true)
|
|
731
|
+
wrapper.unmount()
|
|
732
|
+
}
|
|
733
|
+
})
|
|
734
|
+
|
|
735
|
+
it('doit gérer l\'état required', async () => {
|
|
736
|
+
wrapper = mount(DatePicker, {
|
|
737
|
+
global: {
|
|
738
|
+
plugins: [vuetify],
|
|
739
|
+
},
|
|
740
|
+
props: {
|
|
741
|
+
noCalendar: true,
|
|
742
|
+
modelValue: null,
|
|
743
|
+
label: 'Date obligatoire',
|
|
744
|
+
required: true,
|
|
745
|
+
},
|
|
746
|
+
})
|
|
747
|
+
|
|
748
|
+
await nextTick()
|
|
749
|
+
|
|
750
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
751
|
+
expect(result).toBe(false)
|
|
752
|
+
})
|
|
753
|
+
|
|
754
|
+
it('doit gérer l\'état disabled', async () => {
|
|
755
|
+
wrapper = mount(DatePicker, {
|
|
756
|
+
global: {
|
|
757
|
+
plugins: [vuetify],
|
|
758
|
+
},
|
|
759
|
+
props: {
|
|
760
|
+
noCalendar: true,
|
|
761
|
+
modelValue: null,
|
|
762
|
+
label: 'Date désactivée',
|
|
763
|
+
disabled: true,
|
|
764
|
+
},
|
|
765
|
+
})
|
|
766
|
+
|
|
767
|
+
await nextTick()
|
|
768
|
+
|
|
769
|
+
const input = wrapper.find('input')
|
|
770
|
+
expect(input.attributes('disabled')).toBeDefined()
|
|
771
|
+
})
|
|
772
|
+
|
|
773
|
+
it('doit gérer les icônes append', async () => {
|
|
774
|
+
wrapper = mount(DatePicker, {
|
|
775
|
+
global: {
|
|
776
|
+
plugins: [vuetify],
|
|
777
|
+
},
|
|
778
|
+
props: {
|
|
779
|
+
noCalendar: true,
|
|
780
|
+
modelValue: null,
|
|
781
|
+
label: 'Date avec append icon',
|
|
782
|
+
displayAppendIcon: true,
|
|
783
|
+
},
|
|
784
|
+
})
|
|
785
|
+
|
|
786
|
+
await nextTick()
|
|
787
|
+
|
|
788
|
+
expect(wrapper.exists()).toBe(true)
|
|
789
|
+
})
|
|
790
|
+
|
|
791
|
+
it('doit gérer l\'autoClamp', async () => {
|
|
792
|
+
wrapper = mount(DatePicker, {
|
|
793
|
+
global: {
|
|
794
|
+
plugins: [vuetify],
|
|
795
|
+
},
|
|
796
|
+
props: {
|
|
797
|
+
noCalendar: true,
|
|
798
|
+
modelValue: null,
|
|
799
|
+
label: 'Date avec autoClamp',
|
|
800
|
+
autoClamp: true,
|
|
801
|
+
},
|
|
802
|
+
})
|
|
803
|
+
|
|
804
|
+
await nextTick()
|
|
805
|
+
|
|
806
|
+
expect(wrapper.exists()).toBe(true)
|
|
807
|
+
})
|
|
808
|
+
|
|
809
|
+
it('doit valider les formats de date invalides', async () => {
|
|
810
|
+
wrapper = mount(DatePicker, {
|
|
811
|
+
global: {
|
|
812
|
+
plugins: [vuetify],
|
|
813
|
+
},
|
|
814
|
+
props: {
|
|
815
|
+
noCalendar: true,
|
|
816
|
+
modelValue: null,
|
|
817
|
+
label: 'Date validation format',
|
|
818
|
+
required: true, // Ajouter required pour s'assurer qu'il y a une validation
|
|
819
|
+
},
|
|
820
|
+
})
|
|
821
|
+
|
|
822
|
+
await nextTick()
|
|
823
|
+
|
|
824
|
+
const input = wrapper.find('input')
|
|
825
|
+
await input.setValue('32/13/2024') // Date invalide
|
|
826
|
+
await input.trigger('blur')
|
|
827
|
+
|
|
828
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
829
|
+
expect(result).toBe(false)
|
|
830
|
+
})
|
|
831
|
+
|
|
832
|
+
it('doit gérer les custom warning rules', async () => {
|
|
833
|
+
const warningRuleMock = vi.fn().mockReturnValue(false)
|
|
834
|
+
const customWarningRules = [
|
|
835
|
+
{
|
|
836
|
+
type: 'custom',
|
|
837
|
+
options: {
|
|
838
|
+
validate: warningRuleMock,
|
|
839
|
+
message: 'Avertissement TextInput',
|
|
840
|
+
},
|
|
841
|
+
},
|
|
842
|
+
]
|
|
843
|
+
|
|
844
|
+
wrapper = mount(DatePicker, {
|
|
845
|
+
global: {
|
|
846
|
+
plugins: [vuetify],
|
|
847
|
+
},
|
|
848
|
+
props: {
|
|
849
|
+
noCalendar: true,
|
|
850
|
+
modelValue: '2024-06-15',
|
|
851
|
+
label: 'Date avec warning',
|
|
852
|
+
customWarningRules,
|
|
853
|
+
},
|
|
854
|
+
})
|
|
855
|
+
|
|
856
|
+
await nextTick()
|
|
857
|
+
|
|
858
|
+
// Simuler interaction pour déclencher la validation
|
|
859
|
+
const input = wrapper.find('input')
|
|
860
|
+
await input.trigger('focus')
|
|
861
|
+
await input.trigger('blur')
|
|
862
|
+
await nextTick()
|
|
863
|
+
|
|
864
|
+
wrapper.vm.validateOnSubmit()
|
|
865
|
+
expect(warningRuleMock).toHaveBeenCalled()
|
|
866
|
+
})
|
|
867
|
+
|
|
868
|
+
it('doit émettre les événements correctement', async () => {
|
|
869
|
+
wrapper = mount(DatePicker, {
|
|
870
|
+
global: {
|
|
871
|
+
plugins: [vuetify],
|
|
872
|
+
},
|
|
873
|
+
props: {
|
|
874
|
+
noCalendar: true,
|
|
875
|
+
modelValue: null,
|
|
876
|
+
label: 'Date événements',
|
|
877
|
+
},
|
|
878
|
+
})
|
|
879
|
+
|
|
880
|
+
await nextTick()
|
|
881
|
+
|
|
882
|
+
const input = wrapper.find('input')
|
|
883
|
+
await input.trigger('focus')
|
|
884
|
+
await input.trigger('blur')
|
|
885
|
+
|
|
886
|
+
expect(wrapper.emitted('focus')).toBeTruthy()
|
|
887
|
+
expect(wrapper.emitted('blur')).toBeTruthy()
|
|
888
|
+
})
|
|
889
|
+
})
|
|
890
|
+
|
|
891
|
+
describe('Custom rules sur champs vides', () => {
|
|
892
|
+
it('doit exécuter les custom rules sur champ vide même sans interaction', async () => {
|
|
893
|
+
const customRuleMock = vi.fn().mockReturnValue(false)
|
|
894
|
+
const customRules = [
|
|
895
|
+
{
|
|
896
|
+
type: 'custom',
|
|
897
|
+
options: {
|
|
898
|
+
validate: customRuleMock,
|
|
899
|
+
message: 'Champ obligatoire',
|
|
900
|
+
},
|
|
901
|
+
},
|
|
902
|
+
]
|
|
903
|
+
|
|
904
|
+
wrapper = mount(DatePicker, {
|
|
905
|
+
global: {
|
|
906
|
+
plugins: [vuetify],
|
|
907
|
+
},
|
|
908
|
+
props: {
|
|
909
|
+
noCalendar: true,
|
|
910
|
+
modelValue: null,
|
|
911
|
+
label: 'Date TextInput',
|
|
912
|
+
customRules,
|
|
913
|
+
},
|
|
914
|
+
})
|
|
915
|
+
|
|
916
|
+
await nextTick()
|
|
917
|
+
|
|
918
|
+
// DatePicker exécute les custom rules même sans interaction
|
|
919
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
920
|
+
expect(customRuleMock).toHaveBeenCalledWith(null)
|
|
921
|
+
expect(result).toBe(false)
|
|
922
|
+
})
|
|
923
|
+
})
|
|
924
|
+
})
|
|
925
|
+
|
|
926
|
+
/**
|
|
927
|
+
* TESTS SPÉCIFIQUES AUX COMPOSABLES ET FONCTIONNALITÉS AVANCÉES
|
|
928
|
+
*/
|
|
929
|
+
describe('Tests des Composables et Fonctionnalités', () => {
|
|
930
|
+
describe('Gestion des périodes (period)', () => {
|
|
931
|
+
it('doit respecter les dates min/max définies', async () => {
|
|
932
|
+
const period = {
|
|
933
|
+
min: '2024-01-01',
|
|
934
|
+
max: '2024-12-31',
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
wrapper = mount(DatePicker, {
|
|
938
|
+
global: {
|
|
939
|
+
plugins: [vuetify],
|
|
940
|
+
},
|
|
941
|
+
props: {
|
|
942
|
+
modelValue: null,
|
|
943
|
+
label: 'Date avec période',
|
|
944
|
+
period,
|
|
945
|
+
},
|
|
946
|
+
})
|
|
947
|
+
|
|
948
|
+
await nextTick()
|
|
949
|
+
|
|
950
|
+
expect(wrapper.exists()).toBe(true)
|
|
951
|
+
expect(wrapper.props('period')).toEqual(period)
|
|
952
|
+
})
|
|
953
|
+
})
|
|
954
|
+
|
|
955
|
+
describe('Gestion des jours fériés et week-ends', () => {
|
|
956
|
+
it('doit gérer displayWeekendDays', async () => {
|
|
957
|
+
wrapper = mount(DatePicker, {
|
|
958
|
+
global: {
|
|
959
|
+
plugins: [vuetify],
|
|
960
|
+
},
|
|
961
|
+
props: {
|
|
962
|
+
modelValue: null,
|
|
963
|
+
label: 'Date avec week-ends',
|
|
964
|
+
displayWeekendDays: false,
|
|
965
|
+
},
|
|
966
|
+
})
|
|
967
|
+
|
|
968
|
+
await nextTick()
|
|
969
|
+
|
|
970
|
+
expect(wrapper.exists()).toBe(true)
|
|
971
|
+
expect(wrapper.props('displayWeekendDays')).toBe(false)
|
|
972
|
+
})
|
|
973
|
+
|
|
974
|
+
it('doit gérer displayHolidayDays', async () => {
|
|
975
|
+
wrapper = mount(DatePicker, {
|
|
976
|
+
global: {
|
|
977
|
+
plugins: [vuetify],
|
|
978
|
+
},
|
|
979
|
+
props: {
|
|
980
|
+
modelValue: null,
|
|
981
|
+
label: 'Date avec jours fériés',
|
|
982
|
+
displayHolidayDays: false,
|
|
983
|
+
},
|
|
984
|
+
})
|
|
985
|
+
|
|
986
|
+
await nextTick()
|
|
987
|
+
|
|
988
|
+
expect(wrapper.exists()).toBe(true)
|
|
989
|
+
expect(wrapper.props('displayHolidayDays')).toBe(false)
|
|
990
|
+
})
|
|
991
|
+
})
|
|
992
|
+
|
|
993
|
+
describe('Gestion du bouton Today', () => {
|
|
994
|
+
it('doit gérer displayTodayButton', async () => {
|
|
995
|
+
wrapper = mount(DatePicker, {
|
|
996
|
+
global: {
|
|
997
|
+
plugins: [vuetify],
|
|
998
|
+
},
|
|
999
|
+
props: {
|
|
1000
|
+
modelValue: null,
|
|
1001
|
+
label: 'Date avec bouton Today',
|
|
1002
|
+
displayTodayButton: false,
|
|
1003
|
+
},
|
|
1004
|
+
})
|
|
1005
|
+
|
|
1006
|
+
await nextTick()
|
|
1007
|
+
|
|
1008
|
+
expect(wrapper.exists()).toBe(true)
|
|
1009
|
+
expect(wrapper.props('displayTodayButton')).toBe(false)
|
|
1010
|
+
})
|
|
1011
|
+
})
|
|
1012
|
+
|
|
1013
|
+
describe('Gestion des numéros de semaine', () => {
|
|
1014
|
+
it('doit gérer showWeekNumber', async () => {
|
|
1015
|
+
wrapper = mount(DatePicker, {
|
|
1016
|
+
global: {
|
|
1017
|
+
plugins: [vuetify],
|
|
1018
|
+
},
|
|
1019
|
+
props: {
|
|
1020
|
+
modelValue: null,
|
|
1021
|
+
label: 'Date avec numéros de semaine',
|
|
1022
|
+
showWeekNumber: true,
|
|
1023
|
+
},
|
|
1024
|
+
})
|
|
1025
|
+
|
|
1026
|
+
await nextTick()
|
|
1027
|
+
|
|
1028
|
+
expect(wrapper.exists()).toBe(true)
|
|
1029
|
+
expect(wrapper.props('showWeekNumber')).toBe(true)
|
|
1030
|
+
})
|
|
1031
|
+
})
|
|
1032
|
+
|
|
1033
|
+
describe('Gestion du textFieldActivator', () => {
|
|
1034
|
+
it('doit gérer textFieldActivator pour DatePicker', async () => {
|
|
1035
|
+
wrapper = mount(DatePicker, {
|
|
1036
|
+
global: {
|
|
1037
|
+
plugins: [vuetify],
|
|
1038
|
+
},
|
|
1039
|
+
props: {
|
|
1040
|
+
useCombinedMode: true,
|
|
1041
|
+
modelValue: null,
|
|
1042
|
+
label: 'Date avec textFieldActivator',
|
|
1043
|
+
textFieldActivator: true,
|
|
1044
|
+
},
|
|
1045
|
+
})
|
|
1046
|
+
|
|
1047
|
+
await nextTick()
|
|
1048
|
+
|
|
1049
|
+
expect(wrapper.exists()).toBe(true)
|
|
1050
|
+
expect(wrapper.props('textFieldActivator')).toBe(true)
|
|
1051
|
+
})
|
|
1052
|
+
})
|
|
1053
|
+
|
|
1054
|
+
describe('Gestion de la densité', () => {
|
|
1055
|
+
it('doit gérer les différentes densités', async () => {
|
|
1056
|
+
const densities = ['default', 'comfortable', 'compact'] as const
|
|
1057
|
+
|
|
1058
|
+
for (const density of densities) {
|
|
1059
|
+
wrapper = mount(DatePicker, {
|
|
1060
|
+
global: {
|
|
1061
|
+
plugins: [vuetify],
|
|
1062
|
+
},
|
|
1063
|
+
props: {
|
|
1064
|
+
modelValue: null,
|
|
1065
|
+
label: `Date densité ${density}`,
|
|
1066
|
+
density,
|
|
1067
|
+
},
|
|
1068
|
+
})
|
|
1069
|
+
|
|
1070
|
+
await nextTick()
|
|
1071
|
+
expect(wrapper.exists()).toBe(true)
|
|
1072
|
+
expect(wrapper.props('density')).toBe(density)
|
|
1073
|
+
wrapper.unmount()
|
|
1074
|
+
}
|
|
1075
|
+
})
|
|
1076
|
+
})
|
|
1077
|
+
|
|
1078
|
+
describe('Gestion de hideDetails', () => {
|
|
1079
|
+
it('doit gérer hideDetails=true', async () => {
|
|
1080
|
+
wrapper = mount(DatePicker, {
|
|
1081
|
+
global: {
|
|
1082
|
+
plugins: [vuetify],
|
|
1083
|
+
},
|
|
1084
|
+
props: {
|
|
1085
|
+
modelValue: null,
|
|
1086
|
+
label: 'Date sans détails',
|
|
1087
|
+
hideDetails: true,
|
|
1088
|
+
},
|
|
1089
|
+
})
|
|
1090
|
+
|
|
1091
|
+
await nextTick()
|
|
1092
|
+
|
|
1093
|
+
expect(wrapper.exists()).toBe(true)
|
|
1094
|
+
expect(wrapper.props('hideDetails')).toBe(true)
|
|
1095
|
+
})
|
|
1096
|
+
|
|
1097
|
+
it('doit gérer hideDetails="auto"', async () => {
|
|
1098
|
+
wrapper = mount(DatePicker, {
|
|
1099
|
+
global: {
|
|
1100
|
+
plugins: [vuetify],
|
|
1101
|
+
},
|
|
1102
|
+
props: {
|
|
1103
|
+
modelValue: null,
|
|
1104
|
+
label: 'Date détails auto',
|
|
1105
|
+
hideDetails: 'auto',
|
|
1106
|
+
},
|
|
1107
|
+
})
|
|
1108
|
+
|
|
1109
|
+
await nextTick()
|
|
1110
|
+
|
|
1111
|
+
expect(wrapper.exists()).toBe(true)
|
|
1112
|
+
expect(wrapper.props('hideDetails')).toBe('auto')
|
|
1113
|
+
})
|
|
1114
|
+
})
|
|
1115
|
+
|
|
1116
|
+
describe('Gestion de l\'astérisque', () => {
|
|
1117
|
+
it('doit gérer displayAsterisk', async () => {
|
|
1118
|
+
wrapper = mount(DatePicker, {
|
|
1119
|
+
global: {
|
|
1120
|
+
plugins: [vuetify],
|
|
1121
|
+
},
|
|
1122
|
+
props: {
|
|
1123
|
+
modelValue: null,
|
|
1124
|
+
label: 'Date avec astérisque',
|
|
1125
|
+
displayAsterisk: true,
|
|
1126
|
+
required: true,
|
|
1127
|
+
},
|
|
1128
|
+
})
|
|
1129
|
+
|
|
1130
|
+
await nextTick()
|
|
1131
|
+
|
|
1132
|
+
expect(wrapper.exists()).toBe(true)
|
|
1133
|
+
expect(wrapper.props('displayAsterisk')).toBe(true)
|
|
1134
|
+
})
|
|
1135
|
+
})
|
|
1136
|
+
|
|
1137
|
+
describe('Gestion de isValidateOnBlur', () => {
|
|
1138
|
+
it('doit gérer isValidateOnBlur=false', async () => {
|
|
1139
|
+
wrapper = mount(DatePicker, {
|
|
1140
|
+
global: {
|
|
1141
|
+
plugins: [vuetify],
|
|
1142
|
+
},
|
|
1143
|
+
props: {
|
|
1144
|
+
modelValue: null,
|
|
1145
|
+
label: 'Date sans validation blur',
|
|
1146
|
+
isValidateOnBlur: false,
|
|
1147
|
+
},
|
|
1148
|
+
})
|
|
1149
|
+
|
|
1150
|
+
await nextTick()
|
|
1151
|
+
|
|
1152
|
+
expect(wrapper.exists()).toBe(true)
|
|
1153
|
+
expect(wrapper.props('isValidateOnBlur')).toBe(false)
|
|
1154
|
+
})
|
|
1155
|
+
})
|
|
1156
|
+
})
|
|
1157
|
+
|
|
1158
|
+
/**
|
|
1159
|
+
* TESTS DE RÉGRESSION SPÉCIFIQUES
|
|
1160
|
+
*/
|
|
1161
|
+
describe('Tests de Régression Spécifiques', () => {
|
|
1162
|
+
describe('Suppression via croix (Mémoire 1f50fe1b)', () => {
|
|
1163
|
+
it('ne doit pas afficher "Date invalide" lors de suppression via croix - CalendarMode', async () => {
|
|
1164
|
+
wrapper = mount(DatePicker, {
|
|
1165
|
+
global: {
|
|
1166
|
+
plugins: [vuetify],
|
|
1167
|
+
},
|
|
1168
|
+
props: {
|
|
1169
|
+
modelValue: '2024-06-15',
|
|
1170
|
+
label: 'Date CalendarMode',
|
|
1171
|
+
customRules: [
|
|
1172
|
+
{
|
|
1173
|
+
type: 'notBeforeDate',
|
|
1174
|
+
options: {
|
|
1175
|
+
date: '2024-01-01',
|
|
1176
|
+
message: 'Date trop ancienne',
|
|
1177
|
+
},
|
|
1178
|
+
},
|
|
1179
|
+
],
|
|
1180
|
+
},
|
|
1181
|
+
})
|
|
1182
|
+
|
|
1183
|
+
await nextTick()
|
|
1184
|
+
|
|
1185
|
+
// Simuler suppression via croix (modelValue devient null)
|
|
1186
|
+
await wrapper.setProps({ modelValue: null })
|
|
1187
|
+
await nextTick()
|
|
1188
|
+
|
|
1189
|
+
// Ne doit pas afficher "Date invalide"
|
|
1190
|
+
const errorMessages = wrapper.findAll('.v-messages__message')
|
|
1191
|
+
const hasDateInvalidError = errorMessages.some(msg =>
|
|
1192
|
+
msg.text().includes('Date invalide'),
|
|
1193
|
+
)
|
|
1194
|
+
expect(hasDateInvalidError).toBe(false)
|
|
1195
|
+
})
|
|
1196
|
+
|
|
1197
|
+
it('ne doit pas afficher "Date invalide" lors de suppression via croix - DatePicker', async () => {
|
|
1198
|
+
wrapper = mount(DatePicker, {
|
|
1199
|
+
global: {
|
|
1200
|
+
plugins: [vuetify],
|
|
1201
|
+
},
|
|
1202
|
+
props: {
|
|
1203
|
+
useCombinedMode: true,
|
|
1204
|
+
modelValue: '2024-06-15',
|
|
1205
|
+
label: 'Date DatePicker',
|
|
1206
|
+
customRules: [
|
|
1207
|
+
{
|
|
1208
|
+
type: 'notAfterDate',
|
|
1209
|
+
options: {
|
|
1210
|
+
date: '2024-12-31',
|
|
1211
|
+
message: 'Date trop récente',
|
|
1212
|
+
},
|
|
1213
|
+
},
|
|
1214
|
+
],
|
|
1215
|
+
},
|
|
1216
|
+
})
|
|
1217
|
+
|
|
1218
|
+
await nextTick()
|
|
1219
|
+
|
|
1220
|
+
// Simuler suppression via croix (modelValue devient null)
|
|
1221
|
+
await wrapper.setProps({ modelValue: null })
|
|
1222
|
+
await nextTick()
|
|
1223
|
+
|
|
1224
|
+
// Ne doit pas afficher "Date invalide"
|
|
1225
|
+
const errorMessages = wrapper.findAll('.v-messages__message')
|
|
1226
|
+
const hasDateInvalidError = errorMessages.some(msg =>
|
|
1227
|
+
msg.text().includes('Date invalide'),
|
|
1228
|
+
)
|
|
1229
|
+
expect(hasDateInvalidError).toBe(false)
|
|
1230
|
+
})
|
|
1231
|
+
})
|
|
1232
|
+
|
|
1233
|
+
describe('Configuration de règle invalide (Mémoire 36a3ff57)', () => {
|
|
1234
|
+
it('ne doit pas afficher "Configuration de la règle invalide" - DatePicker', async () => {
|
|
1235
|
+
const dateA = ref('2024-06-15')
|
|
1236
|
+
|
|
1237
|
+
const dateBRules = computed(() => [
|
|
1238
|
+
{
|
|
1239
|
+
type: 'notBeforeDate',
|
|
1240
|
+
options: {
|
|
1241
|
+
date: dateA.value,
|
|
1242
|
+
message: `Date ne peut pas être avant le ${dateA.value}`,
|
|
1243
|
+
},
|
|
1244
|
+
},
|
|
1245
|
+
])
|
|
1246
|
+
|
|
1247
|
+
wrapper = mount(DatePicker, {
|
|
1248
|
+
global: {
|
|
1249
|
+
plugins: [vuetify],
|
|
1250
|
+
},
|
|
1251
|
+
props: {
|
|
1252
|
+
useCombinedMode: true,
|
|
1253
|
+
modelValue: null,
|
|
1254
|
+
label: 'Date B',
|
|
1255
|
+
customRules: dateBRules.value,
|
|
1256
|
+
},
|
|
1257
|
+
})
|
|
1258
|
+
|
|
1259
|
+
await nextTick()
|
|
1260
|
+
|
|
1261
|
+
// Changer dateA pour déclencher une mise à jour des règles
|
|
1262
|
+
dateA.value = '2024-07-01'
|
|
1263
|
+
await wrapper.setProps({ customRules: dateBRules.value })
|
|
1264
|
+
await nextTick()
|
|
1265
|
+
|
|
1266
|
+
// Saisir une date et valider
|
|
1267
|
+
await wrapper.setProps({ modelValue: '2024-07-15' })
|
|
1268
|
+
await nextTick()
|
|
1269
|
+
|
|
1270
|
+
wrapper.vm.validateOnSubmit()
|
|
1271
|
+
|
|
1272
|
+
// Ne doit pas y avoir d'erreur "Configuration de la règle invalide"
|
|
1273
|
+
const errorMessages = wrapper.findAll('.v-messages__message')
|
|
1274
|
+
const hasConfigError = errorMessages.some(msg =>
|
|
1275
|
+
msg.text().includes('Configuration de la règle invalide'),
|
|
1276
|
+
)
|
|
1277
|
+
expect(hasConfigError).toBe(false)
|
|
1278
|
+
})
|
|
1279
|
+
})
|
|
1280
|
+
|
|
1281
|
+
describe('Priorité des messages (Mémoire 36e3ba09)', () => {
|
|
1282
|
+
it('doit prioriser les erreurs sur les succès - DatePicker', async () => {
|
|
1283
|
+
const customErrorRule = vi.fn().mockReturnValue(false)
|
|
1284
|
+
const customSuccessRule = vi.fn().mockReturnValue(true)
|
|
1285
|
+
|
|
1286
|
+
const customRules = [
|
|
1287
|
+
{
|
|
1288
|
+
type: 'custom',
|
|
1289
|
+
options: {
|
|
1290
|
+
validate: customErrorRule,
|
|
1291
|
+
message: 'Erreur critique',
|
|
1292
|
+
},
|
|
1293
|
+
},
|
|
1294
|
+
]
|
|
1295
|
+
|
|
1296
|
+
const customSuccessRules = [
|
|
1297
|
+
{
|
|
1298
|
+
type: 'custom',
|
|
1299
|
+
options: {
|
|
1300
|
+
validate: customSuccessRule,
|
|
1301
|
+
message: 'Validation réussie',
|
|
1302
|
+
},
|
|
1303
|
+
},
|
|
1304
|
+
]
|
|
1305
|
+
|
|
1306
|
+
wrapper = mount(DatePicker, {
|
|
1307
|
+
global: {
|
|
1308
|
+
plugins: [vuetify],
|
|
1309
|
+
},
|
|
1310
|
+
props: {
|
|
1311
|
+
useCombinedMode: true,
|
|
1312
|
+
modelValue: '2024-06-15',
|
|
1313
|
+
label: 'Date DatePicker',
|
|
1314
|
+
customRules,
|
|
1315
|
+
customSuccessRules,
|
|
1316
|
+
},
|
|
1317
|
+
})
|
|
1318
|
+
|
|
1319
|
+
await nextTick()
|
|
1320
|
+
|
|
1321
|
+
// Simuler interaction pour déclencher la validation
|
|
1322
|
+
const input = wrapper.find('input')
|
|
1323
|
+
await input.trigger('focus')
|
|
1324
|
+
await input.trigger('blur')
|
|
1325
|
+
await nextTick()
|
|
1326
|
+
|
|
1327
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
1328
|
+
expect(result).toBe(false) // Erreur doit primer
|
|
1329
|
+
|
|
1330
|
+
// Vérifier que les règles ont été appelées
|
|
1331
|
+
expect(customErrorRule).toHaveBeenCalled()
|
|
1332
|
+
})
|
|
1333
|
+
})
|
|
1334
|
+
})
|
|
1335
|
+
|
|
1336
|
+
/**
|
|
1337
|
+
* TESTS DE PERFORMANCE ET EDGE CASES
|
|
1338
|
+
*/
|
|
1339
|
+
describe('Tests de Performance et Edge Cases', () => {
|
|
1340
|
+
describe('Gestion des valeurs limites', () => {
|
|
1341
|
+
it('doit gérer les dates très anciennes', async () => {
|
|
1342
|
+
const ancientDate = '1900-01-01'
|
|
1343
|
+
wrapper = mount(DatePicker, {
|
|
1344
|
+
global: {
|
|
1345
|
+
plugins: [vuetify],
|
|
1346
|
+
},
|
|
1347
|
+
props: {
|
|
1348
|
+
modelValue: ancientDate,
|
|
1349
|
+
label: 'Date ancienne',
|
|
1350
|
+
},
|
|
1351
|
+
})
|
|
1352
|
+
|
|
1353
|
+
await nextTick()
|
|
1354
|
+
|
|
1355
|
+
expect(wrapper.exists()).toBe(true)
|
|
1356
|
+
expect(wrapper.props('modelValue')).toBe(ancientDate)
|
|
1357
|
+
})
|
|
1358
|
+
|
|
1359
|
+
it('doit gérer les dates très futures', async () => {
|
|
1360
|
+
const futureDate = '2100-12-31'
|
|
1361
|
+
wrapper = mount(DatePicker, {
|
|
1362
|
+
global: {
|
|
1363
|
+
plugins: [vuetify],
|
|
1364
|
+
},
|
|
1365
|
+
props: {
|
|
1366
|
+
modelValue: futureDate,
|
|
1367
|
+
label: 'Date future',
|
|
1368
|
+
},
|
|
1369
|
+
})
|
|
1370
|
+
|
|
1371
|
+
await nextTick()
|
|
1372
|
+
|
|
1373
|
+
expect(wrapper.exists()).toBe(true)
|
|
1374
|
+
expect(wrapper.props('modelValue')).toBe(futureDate)
|
|
1375
|
+
})
|
|
1376
|
+
})
|
|
1377
|
+
|
|
1378
|
+
describe('Gestion des formats exotiques', () => {
|
|
1379
|
+
it('doit gérer le format YYYY/MM/DD', async () => {
|
|
1380
|
+
wrapper = mount(DatePicker, {
|
|
1381
|
+
global: {
|
|
1382
|
+
plugins: [vuetify],
|
|
1383
|
+
},
|
|
1384
|
+
props: {
|
|
1385
|
+
modelValue: null,
|
|
1386
|
+
label: 'Date format YYYY/MM/DD',
|
|
1387
|
+
format: 'YYYY/MM/DD',
|
|
1388
|
+
},
|
|
1389
|
+
})
|
|
1390
|
+
|
|
1391
|
+
await nextTick()
|
|
1392
|
+
|
|
1393
|
+
expect(wrapper.exists()).toBe(true)
|
|
1394
|
+
expect(wrapper.props('format')).toBe('YYYY/MM/DD')
|
|
1395
|
+
})
|
|
1396
|
+
|
|
1397
|
+
it('doit gérer le format DD-MM-YYYY', async () => {
|
|
1398
|
+
wrapper = mount(DatePicker, {
|
|
1399
|
+
global: {
|
|
1400
|
+
plugins: [vuetify],
|
|
1401
|
+
},
|
|
1402
|
+
props: {
|
|
1403
|
+
modelValue: null,
|
|
1404
|
+
label: 'Date format DD-MM-YYYY',
|
|
1405
|
+
format: 'DD-MM-YYYY',
|
|
1406
|
+
},
|
|
1407
|
+
})
|
|
1408
|
+
|
|
1409
|
+
await nextTick()
|
|
1410
|
+
|
|
1411
|
+
expect(wrapper.exists()).toBe(true)
|
|
1412
|
+
expect(wrapper.props('format')).toBe('DD-MM-YYYY')
|
|
1413
|
+
})
|
|
1414
|
+
})
|
|
1415
|
+
|
|
1416
|
+
describe('Gestion des plages de dates complexes', () => {
|
|
1417
|
+
it('doit gérer les plages de dates avec DatePicker', async () => {
|
|
1418
|
+
wrapper = mount(DatePicker, {
|
|
1419
|
+
global: {
|
|
1420
|
+
plugins: [vuetify],
|
|
1421
|
+
},
|
|
1422
|
+
props: {
|
|
1423
|
+
modelValue: null,
|
|
1424
|
+
label: 'Plage DatePicker',
|
|
1425
|
+
displayRange: true,
|
|
1426
|
+
},
|
|
1427
|
+
})
|
|
1428
|
+
|
|
1429
|
+
await nextTick()
|
|
1430
|
+
|
|
1431
|
+
expect(wrapper.exists()).toBe(true)
|
|
1432
|
+
expect(wrapper.props('displayRange')).toBe(true)
|
|
1433
|
+
})
|
|
1434
|
+
|
|
1435
|
+
it('doit gérer les plages de dates avec des valeurs initiales', async () => {
|
|
1436
|
+
const rangeValue = ['2024-06-01', '2024-06-30']
|
|
1437
|
+
wrapper = mount(DatePicker, {
|
|
1438
|
+
global: {
|
|
1439
|
+
plugins: [vuetify],
|
|
1440
|
+
},
|
|
1441
|
+
props: {
|
|
1442
|
+
useCombinedMode: true,
|
|
1443
|
+
modelValue: rangeValue,
|
|
1444
|
+
label: 'Plage avec valeurs',
|
|
1445
|
+
displayRange: true,
|
|
1446
|
+
},
|
|
1447
|
+
})
|
|
1448
|
+
|
|
1449
|
+
await nextTick()
|
|
1450
|
+
|
|
1451
|
+
expect(wrapper.exists()).toBe(true)
|
|
1452
|
+
expect(wrapper.props('modelValue')).toEqual(rangeValue)
|
|
1453
|
+
})
|
|
1454
|
+
})
|
|
1455
|
+
|
|
1456
|
+
describe('Tests avec de nombreuses règles', () => {
|
|
1457
|
+
it('doit gérer de nombreuses custom rules', async () => {
|
|
1458
|
+
const manyRules = Array.from({ length: 10 }, (_, i) => ({
|
|
1459
|
+
type: 'custom',
|
|
1460
|
+
options: {
|
|
1461
|
+
validate: vi.fn().mockReturnValue(true),
|
|
1462
|
+
message: `Règle ${i + 1}`,
|
|
1463
|
+
},
|
|
1464
|
+
}))
|
|
1465
|
+
|
|
1466
|
+
wrapper = mount(DatePicker, {
|
|
1467
|
+
global: {
|
|
1468
|
+
plugins: [vuetify],
|
|
1469
|
+
},
|
|
1470
|
+
props: {
|
|
1471
|
+
useCombinedMode: true,
|
|
1472
|
+
modelValue: '2024-06-15',
|
|
1473
|
+
label: 'Date avec nombreuses règles',
|
|
1474
|
+
customRules: manyRules,
|
|
1475
|
+
},
|
|
1476
|
+
})
|
|
1477
|
+
|
|
1478
|
+
await nextTick()
|
|
1479
|
+
|
|
1480
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
1481
|
+
expect(result).toBe(true)
|
|
1482
|
+
|
|
1483
|
+
// Vérifier que toutes les règles ont été appelées
|
|
1484
|
+
manyRules.forEach((rule) => {
|
|
1485
|
+
expect(rule.options.validate).toHaveBeenCalled()
|
|
1486
|
+
})
|
|
1487
|
+
})
|
|
1488
|
+
})
|
|
1489
|
+
})
|
|
1490
|
+
|
|
1491
|
+
/**
|
|
1492
|
+
* TESTS MANQUANTS IDENTIFIÉS - COUVERTURE COMPLÈTE
|
|
1493
|
+
*/
|
|
1494
|
+
describe('Tests Manquants - Couverture Complète', () => {
|
|
1495
|
+
describe('Tests du prop useCombinedMode', () => {
|
|
1496
|
+
it('doit gérer useCombinedMode=true avec CalendarMode', async () => {
|
|
1497
|
+
wrapper = mount(DatePicker, {
|
|
1498
|
+
global: {
|
|
1499
|
+
plugins: [vuetify],
|
|
1500
|
+
},
|
|
1501
|
+
props: {
|
|
1502
|
+
modelValue: null,
|
|
1503
|
+
label: 'Date Combined Mode',
|
|
1504
|
+
useCombinedMode: true,
|
|
1505
|
+
},
|
|
1506
|
+
})
|
|
1507
|
+
|
|
1508
|
+
await nextTick()
|
|
1509
|
+
|
|
1510
|
+
expect(wrapper.exists()).toBe(true)
|
|
1511
|
+
expect(wrapper.props('useCombinedMode')).toBe(true)
|
|
1512
|
+
})
|
|
1513
|
+
|
|
1514
|
+
it('doit déléguer la validation au DatePicker en mode combiné', async () => {
|
|
1515
|
+
wrapper = mount(DatePicker, {
|
|
1516
|
+
global: {
|
|
1517
|
+
plugins: [vuetify],
|
|
1518
|
+
},
|
|
1519
|
+
props: {
|
|
1520
|
+
modelValue: null,
|
|
1521
|
+
label: 'Date Combined Mode',
|
|
1522
|
+
useCombinedMode: true,
|
|
1523
|
+
required: true,
|
|
1524
|
+
},
|
|
1525
|
+
})
|
|
1526
|
+
|
|
1527
|
+
await nextTick()
|
|
1528
|
+
|
|
1529
|
+
// En mode combiné, la validation doit être déléguée
|
|
1530
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
1531
|
+
expect(typeof result).toBe('boolean')
|
|
1532
|
+
})
|
|
1533
|
+
})
|
|
1534
|
+
|
|
1535
|
+
describe('Tests du prop noCalendar', () => {
|
|
1536
|
+
it('doit gérer noCalendar=true avec CalendarMode', async () => {
|
|
1537
|
+
wrapper = mount(DatePicker, {
|
|
1538
|
+
global: {
|
|
1539
|
+
plugins: [vuetify],
|
|
1540
|
+
},
|
|
1541
|
+
props: {
|
|
1542
|
+
modelValue: null,
|
|
1543
|
+
label: 'Date sans calendrier',
|
|
1544
|
+
noCalendar: true,
|
|
1545
|
+
},
|
|
1546
|
+
})
|
|
1547
|
+
|
|
1548
|
+
await nextTick()
|
|
1549
|
+
|
|
1550
|
+
expect(wrapper.exists()).toBe(true)
|
|
1551
|
+
expect(wrapper.props('noCalendar')).toBe(true)
|
|
1552
|
+
})
|
|
1553
|
+
|
|
1554
|
+
it('doit gérer noCalendar=true avec DatePicker', async () => {
|
|
1555
|
+
wrapper = mount(DatePicker, {
|
|
1556
|
+
global: {
|
|
1557
|
+
plugins: [vuetify],
|
|
1558
|
+
},
|
|
1559
|
+
props: {
|
|
1560
|
+
useCombinedMode: true,
|
|
1561
|
+
modelValue: null,
|
|
1562
|
+
label: 'Date sans calendrier Complex',
|
|
1563
|
+
noCalendar: true,
|
|
1564
|
+
},
|
|
1565
|
+
})
|
|
1566
|
+
|
|
1567
|
+
await nextTick()
|
|
1568
|
+
|
|
1569
|
+
expect(wrapper.exists()).toBe(true)
|
|
1570
|
+
expect(wrapper.props('noCalendar')).toBe(true)
|
|
1571
|
+
})
|
|
1572
|
+
|
|
1573
|
+
it('doit déléguer la validation au DatePicker en mode noCalendar', async () => {
|
|
1574
|
+
wrapper = mount(DatePicker, {
|
|
1575
|
+
global: {
|
|
1576
|
+
plugins: [vuetify],
|
|
1577
|
+
},
|
|
1578
|
+
props: {
|
|
1579
|
+
useCombinedMode: true,
|
|
1580
|
+
modelValue: null,
|
|
1581
|
+
label: 'Date noCalendar',
|
|
1582
|
+
noCalendar: true,
|
|
1583
|
+
required: true,
|
|
1584
|
+
},
|
|
1585
|
+
})
|
|
1586
|
+
|
|
1587
|
+
await nextTick()
|
|
1588
|
+
|
|
1589
|
+
// En mode noCalendar, la validation doit être déléguée au DatePicker
|
|
1590
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
1591
|
+
expect(typeof result).toBe('boolean')
|
|
1592
|
+
})
|
|
1593
|
+
})
|
|
1594
|
+
|
|
1595
|
+
describe('Tests du prop isBirthDate vs birthDate', () => {
|
|
1596
|
+
it('doit gérer isBirthDate=true avec CalendarMode', async () => {
|
|
1597
|
+
wrapper = mount(DatePicker, {
|
|
1598
|
+
global: {
|
|
1599
|
+
plugins: [vuetify],
|
|
1600
|
+
},
|
|
1601
|
+
props: {
|
|
1602
|
+
modelValue: null,
|
|
1603
|
+
label: 'Date de naissance isBirthDate',
|
|
1604
|
+
isBirthDate: true,
|
|
1605
|
+
},
|
|
1606
|
+
})
|
|
1607
|
+
|
|
1608
|
+
await nextTick()
|
|
1609
|
+
|
|
1610
|
+
expect(wrapper.exists()).toBe(true)
|
|
1611
|
+
expect(wrapper.props('isBirthDate')).toBe(true)
|
|
1612
|
+
})
|
|
1613
|
+
|
|
1614
|
+
it('doit gérer birthDate=true (alias) avec CalendarMode', async () => {
|
|
1615
|
+
wrapper = mount(DatePicker, {
|
|
1616
|
+
global: {
|
|
1617
|
+
plugins: [vuetify],
|
|
1618
|
+
},
|
|
1619
|
+
props: {
|
|
1620
|
+
modelValue: null,
|
|
1621
|
+
label: 'Date de naissance birthDate',
|
|
1622
|
+
birthDate: true,
|
|
1623
|
+
},
|
|
1624
|
+
})
|
|
1625
|
+
|
|
1626
|
+
await nextTick()
|
|
1627
|
+
|
|
1628
|
+
expect(wrapper.exists()).toBe(true)
|
|
1629
|
+
expect(wrapper.props('birthDate')).toBe(true)
|
|
1630
|
+
})
|
|
1631
|
+
|
|
1632
|
+
it('doit gérer isBirthDate=true avec DatePicker', async () => {
|
|
1633
|
+
wrapper = mount(DatePicker, {
|
|
1634
|
+
global: {
|
|
1635
|
+
plugins: [vuetify],
|
|
1636
|
+
},
|
|
1637
|
+
props: {
|
|
1638
|
+
useCombinedMode: true,
|
|
1639
|
+
modelValue: null,
|
|
1640
|
+
label: 'Date de naissance Complex',
|
|
1641
|
+
isBirthDate: true,
|
|
1642
|
+
},
|
|
1643
|
+
})
|
|
1644
|
+
|
|
1645
|
+
await nextTick()
|
|
1646
|
+
|
|
1647
|
+
expect(wrapper.exists()).toBe(true)
|
|
1648
|
+
expect(wrapper.props('isBirthDate')).toBe(true)
|
|
1649
|
+
})
|
|
1650
|
+
})
|
|
1651
|
+
|
|
1652
|
+
describe('Tests du prop dateFormatReturn', () => {
|
|
1653
|
+
it('doit gérer dateFormatReturn différent du format d\'affichage - CalendarMode', async () => {
|
|
1654
|
+
wrapper = mount(DatePicker, {
|
|
1655
|
+
global: {
|
|
1656
|
+
plugins: [vuetify],
|
|
1657
|
+
},
|
|
1658
|
+
props: {
|
|
1659
|
+
modelValue: null,
|
|
1660
|
+
label: 'Date avec format retour',
|
|
1661
|
+
format: 'DD/MM/YYYY',
|
|
1662
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
1663
|
+
},
|
|
1664
|
+
})
|
|
1665
|
+
|
|
1666
|
+
await nextTick()
|
|
1667
|
+
|
|
1668
|
+
expect(wrapper.exists()).toBe(true)
|
|
1669
|
+
expect(wrapper.props('format')).toBe('DD/MM/YYYY')
|
|
1670
|
+
expect(wrapper.props('dateFormatReturn')).toBe('YYYY-MM-DD')
|
|
1671
|
+
})
|
|
1672
|
+
|
|
1673
|
+
it('doit gérer dateFormatReturn différent du format d\'affichage - DatePicker', async () => {
|
|
1674
|
+
wrapper = mount(DatePicker, {
|
|
1675
|
+
global: {
|
|
1676
|
+
plugins: [vuetify],
|
|
1677
|
+
},
|
|
1678
|
+
props: {
|
|
1679
|
+
useCombinedMode: true,
|
|
1680
|
+
modelValue: null,
|
|
1681
|
+
label: 'Date avec format retour Complex',
|
|
1682
|
+
format: 'DD/MM/YYYY',
|
|
1683
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
1684
|
+
},
|
|
1685
|
+
})
|
|
1686
|
+
|
|
1687
|
+
await nextTick()
|
|
1688
|
+
|
|
1689
|
+
expect(wrapper.exists()).toBe(true)
|
|
1690
|
+
expect(wrapper.props('format')).toBe('DD/MM/YYYY')
|
|
1691
|
+
expect(wrapper.props('dateFormatReturn')).toBe('YYYY-MM-DD')
|
|
1692
|
+
})
|
|
1693
|
+
|
|
1694
|
+
it('doit gérer dateFormatReturn différent du format d\'affichage - DatePicker', async () => {
|
|
1695
|
+
wrapper = mount(DatePicker, {
|
|
1696
|
+
global: {
|
|
1697
|
+
plugins: [vuetify],
|
|
1698
|
+
},
|
|
1699
|
+
props: {
|
|
1700
|
+
modelValue: null,
|
|
1701
|
+
label: 'Date avec format retour TextInput',
|
|
1702
|
+
format: 'DD/MM/YYYY',
|
|
1703
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
1704
|
+
},
|
|
1705
|
+
})
|
|
1706
|
+
|
|
1707
|
+
await nextTick()
|
|
1708
|
+
|
|
1709
|
+
expect(wrapper.exists()).toBe(true)
|
|
1710
|
+
expect(wrapper.props('format')).toBe('DD/MM/YYYY')
|
|
1711
|
+
expect(wrapper.props('dateFormatReturn')).toBe('YYYY-MM-DD')
|
|
1712
|
+
})
|
|
1713
|
+
})
|
|
1714
|
+
|
|
1715
|
+
describe('Tests des props de style et apparence', () => {
|
|
1716
|
+
it('doit gérer isOutlined=false avec CalendarMode', async () => {
|
|
1717
|
+
wrapper = mount(DatePicker, {
|
|
1718
|
+
global: {
|
|
1719
|
+
plugins: [vuetify],
|
|
1720
|
+
},
|
|
1721
|
+
props: {
|
|
1722
|
+
modelValue: null,
|
|
1723
|
+
label: 'Date non outlined',
|
|
1724
|
+
isOutlined: false,
|
|
1725
|
+
},
|
|
1726
|
+
})
|
|
1727
|
+
|
|
1728
|
+
await nextTick()
|
|
1729
|
+
|
|
1730
|
+
expect(wrapper.exists()).toBe(true)
|
|
1731
|
+
expect(wrapper.props('isOutlined')).toBe(false)
|
|
1732
|
+
})
|
|
1733
|
+
|
|
1734
|
+
it('doit gérer bgColor personnalisé', async () => {
|
|
1735
|
+
wrapper = mount(DatePicker, {
|
|
1736
|
+
global: {
|
|
1737
|
+
plugins: [vuetify],
|
|
1738
|
+
},
|
|
1739
|
+
props: {
|
|
1740
|
+
useCombinedMode: true,
|
|
1741
|
+
modelValue: null,
|
|
1742
|
+
label: 'Date avec couleur',
|
|
1743
|
+
bgColor: 'lightblue',
|
|
1744
|
+
},
|
|
1745
|
+
})
|
|
1746
|
+
|
|
1747
|
+
await nextTick()
|
|
1748
|
+
|
|
1749
|
+
expect(wrapper.exists()).toBe(true)
|
|
1750
|
+
expect(wrapper.props('bgColor')).toBe('lightblue')
|
|
1751
|
+
})
|
|
1752
|
+
|
|
1753
|
+
it('doit gérer width personnalisé', async () => {
|
|
1754
|
+
wrapper = mount(DatePicker, {
|
|
1755
|
+
global: {
|
|
1756
|
+
plugins: [vuetify],
|
|
1757
|
+
},
|
|
1758
|
+
props: {
|
|
1759
|
+
modelValue: null,
|
|
1760
|
+
label: 'Date avec largeur',
|
|
1761
|
+
width: '300px',
|
|
1762
|
+
},
|
|
1763
|
+
})
|
|
1764
|
+
|
|
1765
|
+
await nextTick()
|
|
1766
|
+
|
|
1767
|
+
expect(wrapper.exists()).toBe(true)
|
|
1768
|
+
expect(wrapper.props('width')).toBe('300px')
|
|
1769
|
+
})
|
|
1770
|
+
})
|
|
1771
|
+
|
|
1772
|
+
describe('Tests des événements', () => {
|
|
1773
|
+
it('doit émettre l\'événement closed - CalendarMode', async () => {
|
|
1774
|
+
wrapper = mount(DatePicker, {
|
|
1775
|
+
global: {
|
|
1776
|
+
plugins: [vuetify],
|
|
1777
|
+
},
|
|
1778
|
+
props: {
|
|
1779
|
+
modelValue: null,
|
|
1780
|
+
label: 'Date événement closed',
|
|
1781
|
+
},
|
|
1782
|
+
})
|
|
1783
|
+
|
|
1784
|
+
await nextTick()
|
|
1785
|
+
|
|
1786
|
+
// Vérifier que le composant existe et peut émettre des événements
|
|
1787
|
+
expect(wrapper.exists()).toBe(true)
|
|
1788
|
+
expect(wrapper.vm.isDatePickerVisible).toBeDefined()
|
|
1789
|
+
})
|
|
1790
|
+
|
|
1791
|
+
it('doit émettre l\'événement input - DatePicker', async () => {
|
|
1792
|
+
wrapper = mount(DatePicker, {
|
|
1793
|
+
global: {
|
|
1794
|
+
plugins: [vuetify],
|
|
1795
|
+
},
|
|
1796
|
+
props: {
|
|
1797
|
+
useCombinedMode: true,
|
|
1798
|
+
modelValue: null,
|
|
1799
|
+
label: 'Date événement input',
|
|
1800
|
+
},
|
|
1801
|
+
})
|
|
1802
|
+
|
|
1803
|
+
await nextTick()
|
|
1804
|
+
|
|
1805
|
+
// Vérifier que le composant existe et peut gérer les inputs
|
|
1806
|
+
const input = wrapper.find('input')
|
|
1807
|
+
expect(input.exists()).toBe(true)
|
|
1808
|
+
expect(wrapper.exists()).toBe(true)
|
|
1809
|
+
})
|
|
1810
|
+
|
|
1811
|
+
it('doit émettre l\'événement date-selected - DatePicker', async () => {
|
|
1812
|
+
wrapper = mount(DatePicker, {
|
|
1813
|
+
global: {
|
|
1814
|
+
plugins: [vuetify],
|
|
1815
|
+
},
|
|
1816
|
+
props: {
|
|
1817
|
+
modelValue: null,
|
|
1818
|
+
label: 'Date événement date-selected',
|
|
1819
|
+
format: 'DD/MM/YYYY',
|
|
1820
|
+
},
|
|
1821
|
+
})
|
|
1822
|
+
|
|
1823
|
+
await nextTick()
|
|
1824
|
+
|
|
1825
|
+
const input = wrapper.find('input')
|
|
1826
|
+
await input.setValue('15/06/2024')
|
|
1827
|
+
await input.trigger('blur')
|
|
1828
|
+
|
|
1829
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy()
|
|
1830
|
+
})
|
|
1831
|
+
})
|
|
1832
|
+
|
|
1833
|
+
describe('Tests des props de validation avancée', () => {
|
|
1834
|
+
it('doit gérer disableErrorHandling=true', async () => {
|
|
1835
|
+
wrapper = mount(DatePicker, {
|
|
1836
|
+
global: {
|
|
1837
|
+
plugins: [vuetify],
|
|
1838
|
+
},
|
|
1839
|
+
props: {
|
|
1840
|
+
modelValue: null,
|
|
1841
|
+
label: 'Date sans gestion erreur',
|
|
1842
|
+
disableErrorHandling: true,
|
|
1843
|
+
required: true,
|
|
1844
|
+
},
|
|
1845
|
+
})
|
|
1846
|
+
|
|
1847
|
+
await nextTick()
|
|
1848
|
+
|
|
1849
|
+
expect(wrapper.exists()).toBe(true)
|
|
1850
|
+
expect(wrapper.props('disableErrorHandling')).toBe(true)
|
|
1851
|
+
})
|
|
1852
|
+
|
|
1853
|
+
it('doit gérer showSuccessMessages=false', async () => {
|
|
1854
|
+
wrapper = mount(DatePicker, {
|
|
1855
|
+
global: {
|
|
1856
|
+
plugins: [vuetify],
|
|
1857
|
+
},
|
|
1858
|
+
props: {
|
|
1859
|
+
useCombinedMode: true,
|
|
1860
|
+
modelValue: '2024-06-15',
|
|
1861
|
+
label: 'Date sans messages succès',
|
|
1862
|
+
showSuccessMessages: false,
|
|
1863
|
+
},
|
|
1864
|
+
})
|
|
1865
|
+
|
|
1866
|
+
await nextTick()
|
|
1867
|
+
|
|
1868
|
+
expect(wrapper.exists()).toBe(true)
|
|
1869
|
+
expect(wrapper.props('showSuccessMessages')).toBe(false)
|
|
1870
|
+
})
|
|
1871
|
+
})
|
|
1872
|
+
|
|
1873
|
+
describe('Tests des méthodes exposées', () => {
|
|
1874
|
+
it('doit exposer isDatePickerVisible - CalendarMode', async () => {
|
|
1875
|
+
wrapper = mount(DatePicker, {
|
|
1876
|
+
global: {
|
|
1877
|
+
plugins: [vuetify],
|
|
1878
|
+
},
|
|
1879
|
+
props: {
|
|
1880
|
+
modelValue: null,
|
|
1881
|
+
label: 'Date méthodes exposées',
|
|
1882
|
+
},
|
|
1883
|
+
})
|
|
1884
|
+
|
|
1885
|
+
await nextTick()
|
|
1886
|
+
|
|
1887
|
+
expect(wrapper.vm.isDatePickerVisible).toBeDefined()
|
|
1888
|
+
expect(typeof wrapper.vm.isDatePickerVisible).toBe('boolean')
|
|
1889
|
+
})
|
|
1890
|
+
|
|
1891
|
+
it('doit exposer selectedDates - DatePicker', async () => {
|
|
1892
|
+
wrapper = mount(DatePicker, {
|
|
1893
|
+
global: {
|
|
1894
|
+
plugins: [vuetify],
|
|
1895
|
+
},
|
|
1896
|
+
props: {
|
|
1897
|
+
useCombinedMode: true,
|
|
1898
|
+
modelValue: '2024-06-15',
|
|
1899
|
+
label: 'Date selectedDates exposé',
|
|
1900
|
+
},
|
|
1901
|
+
})
|
|
1902
|
+
|
|
1903
|
+
await nextTick()
|
|
1904
|
+
|
|
1905
|
+
expect(wrapper.vm.selectedDates).toBeDefined()
|
|
1906
|
+
})
|
|
1907
|
+
|
|
1908
|
+
it('doit émettre focus lors du focus sur DatePicker', async () => {
|
|
1909
|
+
wrapper = mount(DatePicker, {
|
|
1910
|
+
global: {
|
|
1911
|
+
plugins: [vuetify],
|
|
1912
|
+
},
|
|
1913
|
+
props: {
|
|
1914
|
+
noCalendar: true,
|
|
1915
|
+
modelValue: null,
|
|
1916
|
+
label: 'Date focus exposé',
|
|
1917
|
+
},
|
|
1918
|
+
})
|
|
1919
|
+
|
|
1920
|
+
await nextTick()
|
|
1921
|
+
|
|
1922
|
+
const input = wrapper.find('input')
|
|
1923
|
+
await input.trigger('focus')
|
|
1924
|
+
|
|
1925
|
+
expect(wrapper.emitted('focus')).toBeTruthy()
|
|
1926
|
+
})
|
|
1927
|
+
})
|
|
1928
|
+
|
|
1929
|
+
describe('Tests des interactions complexes', () => {
|
|
1930
|
+
it('doit gérer le changement de format à la volée', async () => {
|
|
1931
|
+
wrapper = mount(DatePicker, {
|
|
1932
|
+
global: {
|
|
1933
|
+
plugins: [vuetify],
|
|
1934
|
+
},
|
|
1935
|
+
props: {
|
|
1936
|
+
modelValue: null,
|
|
1937
|
+
label: 'Date changement format',
|
|
1938
|
+
format: 'DD/MM/YYYY',
|
|
1939
|
+
},
|
|
1940
|
+
})
|
|
1941
|
+
|
|
1942
|
+
await nextTick()
|
|
1943
|
+
|
|
1944
|
+
// Changer le format
|
|
1945
|
+
await wrapper.setProps({ format: 'MM/DD/YYYY' })
|
|
1946
|
+
await nextTick()
|
|
1947
|
+
|
|
1948
|
+
expect(wrapper.props('format')).toBe('MM/DD/YYYY')
|
|
1949
|
+
})
|
|
1950
|
+
|
|
1951
|
+
it('doit gérer les changements de règles dynamiques', async () => {
|
|
1952
|
+
const initialRules = [
|
|
1953
|
+
{
|
|
1954
|
+
type: 'notBeforeDate',
|
|
1955
|
+
options: {
|
|
1956
|
+
date: '2024-01-01',
|
|
1957
|
+
message: 'Date trop ancienne',
|
|
1958
|
+
},
|
|
1959
|
+
},
|
|
1960
|
+
]
|
|
1961
|
+
|
|
1962
|
+
const newRules = [
|
|
1963
|
+
{
|
|
1964
|
+
type: 'notAfterDate',
|
|
1965
|
+
options: {
|
|
1966
|
+
date: '2024-12-31',
|
|
1967
|
+
message: 'Date trop récente',
|
|
1968
|
+
},
|
|
1969
|
+
},
|
|
1970
|
+
]
|
|
1971
|
+
|
|
1972
|
+
wrapper = mount(DatePicker, {
|
|
1973
|
+
global: {
|
|
1974
|
+
plugins: [vuetify],
|
|
1975
|
+
},
|
|
1976
|
+
props: {
|
|
1977
|
+
useCombinedMode: true,
|
|
1978
|
+
modelValue: '2024-06-15',
|
|
1979
|
+
label: 'Date règles dynamiques',
|
|
1980
|
+
customRules: initialRules,
|
|
1981
|
+
},
|
|
1982
|
+
})
|
|
1983
|
+
|
|
1984
|
+
await nextTick()
|
|
1985
|
+
|
|
1986
|
+
// Changer les règles
|
|
1987
|
+
await wrapper.setProps({ customRules: newRules })
|
|
1988
|
+
await nextTick()
|
|
1989
|
+
|
|
1990
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
1991
|
+
expect(typeof result).toBe('boolean')
|
|
1992
|
+
})
|
|
1993
|
+
|
|
1994
|
+
it('doit gérer les plages de dates avec des valeurs partielles', async () => {
|
|
1995
|
+
wrapper = mount(DatePicker, {
|
|
1996
|
+
global: {
|
|
1997
|
+
plugins: [vuetify],
|
|
1998
|
+
},
|
|
1999
|
+
props: {
|
|
2000
|
+
useCombinedMode: true,
|
|
2001
|
+
modelValue: ['2024-06-01', ''],
|
|
2002
|
+
label: 'Plage partielle',
|
|
2003
|
+
displayRange: true,
|
|
2004
|
+
},
|
|
2005
|
+
})
|
|
2006
|
+
|
|
2007
|
+
await nextTick()
|
|
2008
|
+
|
|
2009
|
+
expect(wrapper.exists()).toBe(true)
|
|
2010
|
+
expect(Array.isArray(wrapper.props('modelValue'))).toBe(true)
|
|
2011
|
+
})
|
|
2012
|
+
})
|
|
2013
|
+
|
|
2014
|
+
describe('Tests de robustesse et edge cases', () => {
|
|
2015
|
+
it('doit gérer les valeurs modelValue invalides', async () => {
|
|
2016
|
+
wrapper = mount(DatePicker, {
|
|
2017
|
+
global: {
|
|
2018
|
+
plugins: [vuetify],
|
|
2019
|
+
},
|
|
2020
|
+
props: {
|
|
2021
|
+
modelValue: 'invalid-date',
|
|
2022
|
+
label: 'Date invalide',
|
|
2023
|
+
},
|
|
2024
|
+
})
|
|
2025
|
+
|
|
2026
|
+
await nextTick()
|
|
2027
|
+
|
|
2028
|
+
expect(wrapper.exists()).toBe(true)
|
|
2029
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2030
|
+
expect(typeof result).toBe('boolean')
|
|
2031
|
+
})
|
|
2032
|
+
|
|
2033
|
+
it('doit gérer les props undefined/null', async () => {
|
|
2034
|
+
wrapper = mount(DatePicker, {
|
|
2035
|
+
global: {
|
|
2036
|
+
plugins: [vuetify],
|
|
2037
|
+
},
|
|
2038
|
+
props: {
|
|
2039
|
+
modelValue: null,
|
|
2040
|
+
label: undefined,
|
|
2041
|
+
placeholder: undefined,
|
|
2042
|
+
},
|
|
2043
|
+
})
|
|
2044
|
+
|
|
2045
|
+
await nextTick()
|
|
2046
|
+
|
|
2047
|
+
expect(wrapper.exists()).toBe(true)
|
|
2048
|
+
})
|
|
2049
|
+
|
|
2050
|
+
it('doit gérer les custom rules avec des fonctions qui lèvent des erreurs', async () => {
|
|
2051
|
+
const errorRule = vi.fn().mockReturnValue(false) // Simuler une règle qui échoue sans lever d'erreur
|
|
2052
|
+
|
|
2053
|
+
wrapper = mount(DatePicker, {
|
|
2054
|
+
global: {
|
|
2055
|
+
plugins: [vuetify],
|
|
2056
|
+
},
|
|
2057
|
+
props: {
|
|
2058
|
+
useCombinedMode: true,
|
|
2059
|
+
modelValue: '2024-06-15',
|
|
2060
|
+
label: 'Date règle erreur',
|
|
2061
|
+
customRules: [
|
|
2062
|
+
{
|
|
2063
|
+
type: 'custom',
|
|
2064
|
+
options: {
|
|
2065
|
+
validate: errorRule,
|
|
2066
|
+
message: 'Règle avec erreur',
|
|
2067
|
+
},
|
|
2068
|
+
},
|
|
2069
|
+
],
|
|
2070
|
+
},
|
|
2071
|
+
})
|
|
2072
|
+
|
|
2073
|
+
await nextTick()
|
|
2074
|
+
|
|
2075
|
+
// La validation doit fonctionner même avec des règles qui échouent
|
|
2076
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2077
|
+
expect(typeof result).toBe('boolean')
|
|
2078
|
+
expect(errorRule).toHaveBeenCalled()
|
|
2079
|
+
})
|
|
2080
|
+
|
|
2081
|
+
it('doit gérer les changements rapides de modelValue', async () => {
|
|
2082
|
+
wrapper = mount(DatePicker, {
|
|
2083
|
+
global: {
|
|
2084
|
+
plugins: [vuetify],
|
|
2085
|
+
},
|
|
2086
|
+
props: {
|
|
2087
|
+
modelValue: null,
|
|
2088
|
+
label: 'Date changements rapides',
|
|
2089
|
+
},
|
|
2090
|
+
})
|
|
2091
|
+
|
|
2092
|
+
await nextTick()
|
|
2093
|
+
|
|
2094
|
+
// Changements rapides
|
|
2095
|
+
await wrapper.setProps({ modelValue: '2024-01-01' })
|
|
2096
|
+
await wrapper.setProps({ modelValue: '2024-02-02' })
|
|
2097
|
+
await wrapper.setProps({ modelValue: '2024-03-03' })
|
|
2098
|
+
await nextTick()
|
|
2099
|
+
|
|
2100
|
+
expect(wrapper.exists()).toBe(true)
|
|
2101
|
+
expect(wrapper.props('modelValue')).toBe('2024-03-03')
|
|
2102
|
+
})
|
|
2103
|
+
})
|
|
2104
|
+
})
|
|
2105
|
+
|
|
2106
|
+
/**
|
|
2107
|
+
* TESTS COMPLETS DES RÈGLES useFieldValidation - TOUS LES MODES
|
|
2108
|
+
*/
|
|
2109
|
+
describe('Tests Complets des Règles useFieldValidation', () => {
|
|
2110
|
+
describe('Tests des règles numériques', () => {
|
|
2111
|
+
it('doit gérer la règle min - CalendarMode', async () => {
|
|
2112
|
+
wrapper = mount(DatePicker, {
|
|
2113
|
+
global: {
|
|
2114
|
+
plugins: [vuetify],
|
|
2115
|
+
},
|
|
2116
|
+
props: {
|
|
2117
|
+
modelValue: null,
|
|
2118
|
+
label: 'Date avec règle min',
|
|
2119
|
+
customRules: [
|
|
2120
|
+
{
|
|
2121
|
+
type: 'min',
|
|
2122
|
+
options: {
|
|
2123
|
+
value: 5,
|
|
2124
|
+
message: 'La valeur doit être supérieure à 5',
|
|
2125
|
+
},
|
|
2126
|
+
},
|
|
2127
|
+
],
|
|
2128
|
+
},
|
|
2129
|
+
})
|
|
2130
|
+
|
|
2131
|
+
await nextTick()
|
|
2132
|
+
|
|
2133
|
+
expect(wrapper.exists()).toBe(true)
|
|
2134
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2135
|
+
expect(typeof result).toBe('boolean')
|
|
2136
|
+
})
|
|
2137
|
+
|
|
2138
|
+
it('doit gérer la règle max - DatePicker', async () => {
|
|
2139
|
+
wrapper = mount(DatePicker, {
|
|
2140
|
+
global: {
|
|
2141
|
+
plugins: [vuetify],
|
|
2142
|
+
},
|
|
2143
|
+
props: {
|
|
2144
|
+
useCombinedMode: true,
|
|
2145
|
+
modelValue: null,
|
|
2146
|
+
label: 'Date avec règle max',
|
|
2147
|
+
customRules: [
|
|
2148
|
+
{
|
|
2149
|
+
type: 'max',
|
|
2150
|
+
options: {
|
|
2151
|
+
value: 100,
|
|
2152
|
+
message: 'La valeur doit être inférieure à 100',
|
|
2153
|
+
},
|
|
2154
|
+
},
|
|
2155
|
+
],
|
|
2156
|
+
},
|
|
2157
|
+
})
|
|
2158
|
+
|
|
2159
|
+
await nextTick()
|
|
2160
|
+
|
|
2161
|
+
expect(wrapper.exists()).toBe(true)
|
|
2162
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2163
|
+
expect(typeof result).toBe('boolean')
|
|
2164
|
+
})
|
|
2165
|
+
})
|
|
2166
|
+
|
|
2167
|
+
describe('Tests des règles de longueur', () => {
|
|
2168
|
+
it('doit gérer la règle minLength - DatePicker', async () => {
|
|
2169
|
+
wrapper = mount(DatePicker, {
|
|
2170
|
+
global: {
|
|
2171
|
+
plugins: [vuetify],
|
|
2172
|
+
},
|
|
2173
|
+
props: {
|
|
2174
|
+
modelValue: null,
|
|
2175
|
+
label: 'Date avec minLength',
|
|
2176
|
+
customRules: [
|
|
2177
|
+
{
|
|
2178
|
+
type: 'minLength',
|
|
2179
|
+
options: {
|
|
2180
|
+
length: 3,
|
|
2181
|
+
message: 'Minimum 3 caractères requis',
|
|
2182
|
+
},
|
|
2183
|
+
},
|
|
2184
|
+
],
|
|
2185
|
+
},
|
|
2186
|
+
})
|
|
2187
|
+
|
|
2188
|
+
await nextTick()
|
|
2189
|
+
|
|
2190
|
+
expect(wrapper.exists()).toBe(true)
|
|
2191
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2192
|
+
expect(typeof result).toBe('boolean')
|
|
2193
|
+
})
|
|
2194
|
+
|
|
2195
|
+
it('doit gérer la règle maxLength - CalendarMode', async () => {
|
|
2196
|
+
wrapper = mount(DatePicker, {
|
|
2197
|
+
global: {
|
|
2198
|
+
plugins: [vuetify],
|
|
2199
|
+
},
|
|
2200
|
+
props: {
|
|
2201
|
+
modelValue: null,
|
|
2202
|
+
label: 'Date avec maxLength',
|
|
2203
|
+
customRules: [
|
|
2204
|
+
{
|
|
2205
|
+
type: 'maxLength',
|
|
2206
|
+
options: {
|
|
2207
|
+
length: 20,
|
|
2208
|
+
message: 'Maximum 20 caractères autorisés',
|
|
2209
|
+
},
|
|
2210
|
+
},
|
|
2211
|
+
],
|
|
2212
|
+
},
|
|
2213
|
+
})
|
|
2214
|
+
|
|
2215
|
+
await nextTick()
|
|
2216
|
+
|
|
2217
|
+
expect(wrapper.exists()).toBe(true)
|
|
2218
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2219
|
+
expect(typeof result).toBe('boolean')
|
|
2220
|
+
})
|
|
2221
|
+
|
|
2222
|
+
it('doit gérer la règle exactLength - DatePicker', async () => {
|
|
2223
|
+
wrapper = mount(DatePicker, {
|
|
2224
|
+
global: {
|
|
2225
|
+
plugins: [vuetify],
|
|
2226
|
+
},
|
|
2227
|
+
props: {
|
|
2228
|
+
useCombinedMode: true,
|
|
2229
|
+
modelValue: null,
|
|
2230
|
+
label: 'Date avec exactLength',
|
|
2231
|
+
customRules: [
|
|
2232
|
+
{
|
|
2233
|
+
type: 'exactLength',
|
|
2234
|
+
options: {
|
|
2235
|
+
length: 10,
|
|
2236
|
+
message: 'Exactement 10 caractères requis',
|
|
2237
|
+
},
|
|
2238
|
+
},
|
|
2239
|
+
],
|
|
2240
|
+
},
|
|
2241
|
+
})
|
|
2242
|
+
|
|
2243
|
+
await nextTick()
|
|
2244
|
+
|
|
2245
|
+
expect(wrapper.exists()).toBe(true)
|
|
2246
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2247
|
+
expect(typeof result).toBe('boolean')
|
|
2248
|
+
})
|
|
2249
|
+
})
|
|
2250
|
+
|
|
2251
|
+
describe('Tests des règles de format', () => {
|
|
2252
|
+
it('doit gérer la règle email - DatePicker', async () => {
|
|
2253
|
+
wrapper = mount(DatePicker, {
|
|
2254
|
+
global: {
|
|
2255
|
+
plugins: [vuetify],
|
|
2256
|
+
},
|
|
2257
|
+
props: {
|
|
2258
|
+
modelValue: null,
|
|
2259
|
+
label: 'Champ avec validation email',
|
|
2260
|
+
customRules: [
|
|
2261
|
+
{
|
|
2262
|
+
type: 'email',
|
|
2263
|
+
options: {
|
|
2264
|
+
message: 'Format email invalide',
|
|
2265
|
+
},
|
|
2266
|
+
},
|
|
2267
|
+
],
|
|
2268
|
+
},
|
|
2269
|
+
})
|
|
2270
|
+
|
|
2271
|
+
await nextTick()
|
|
2272
|
+
|
|
2273
|
+
expect(wrapper.exists()).toBe(true)
|
|
2274
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2275
|
+
expect(typeof result).toBe('boolean')
|
|
2276
|
+
})
|
|
2277
|
+
|
|
2278
|
+
it('doit gérer la règle matchPattern - CalendarMode', async () => {
|
|
2279
|
+
wrapper = mount(DatePicker, {
|
|
2280
|
+
global: {
|
|
2281
|
+
plugins: [vuetify],
|
|
2282
|
+
},
|
|
2283
|
+
props: {
|
|
2284
|
+
modelValue: null,
|
|
2285
|
+
label: 'Date avec pattern',
|
|
2286
|
+
customRules: [
|
|
2287
|
+
{
|
|
2288
|
+
type: 'matchPattern',
|
|
2289
|
+
options: {
|
|
2290
|
+
pattern: /^\d{2}\/\d{2}\/\d{4}$/,
|
|
2291
|
+
message: 'Format de date invalide',
|
|
2292
|
+
},
|
|
2293
|
+
},
|
|
2294
|
+
],
|
|
2295
|
+
},
|
|
2296
|
+
})
|
|
2297
|
+
|
|
2298
|
+
await nextTick()
|
|
2299
|
+
|
|
2300
|
+
expect(wrapper.exists()).toBe(true)
|
|
2301
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2302
|
+
expect(typeof result).toBe('boolean')
|
|
2303
|
+
})
|
|
2304
|
+
})
|
|
2305
|
+
|
|
2306
|
+
describe('Tests des règles de date spécifiques', () => {
|
|
2307
|
+
it('doit gérer la règle notWeekend - DatePicker', async () => {
|
|
2308
|
+
wrapper = mount(DatePicker, {
|
|
2309
|
+
global: {
|
|
2310
|
+
plugins: [vuetify],
|
|
2311
|
+
},
|
|
2312
|
+
props: {
|
|
2313
|
+
useCombinedMode: true,
|
|
2314
|
+
modelValue: '2024-06-15', // Samedi
|
|
2315
|
+
label: 'Date sans weekend',
|
|
2316
|
+
customRules: [
|
|
2317
|
+
{
|
|
2318
|
+
type: 'notWeekend',
|
|
2319
|
+
options: {
|
|
2320
|
+
message: 'Les weekends ne sont pas autorisés',
|
|
2321
|
+
},
|
|
2322
|
+
},
|
|
2323
|
+
],
|
|
2324
|
+
},
|
|
2325
|
+
})
|
|
2326
|
+
|
|
2327
|
+
await nextTick()
|
|
2328
|
+
|
|
2329
|
+
expect(wrapper.exists()).toBe(true)
|
|
2330
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2331
|
+
expect(typeof result).toBe('boolean')
|
|
2332
|
+
})
|
|
2333
|
+
|
|
2334
|
+
it('doit gérer la règle notBeforeToday - DatePicker', async () => {
|
|
2335
|
+
wrapper = mount(DatePicker, {
|
|
2336
|
+
global: {
|
|
2337
|
+
plugins: [vuetify],
|
|
2338
|
+
},
|
|
2339
|
+
props: {
|
|
2340
|
+
modelValue: null,
|
|
2341
|
+
label: 'Date pas avant aujourd\'hui',
|
|
2342
|
+
customRules: [
|
|
2343
|
+
{
|
|
2344
|
+
type: 'notBeforeToday',
|
|
2345
|
+
options: {
|
|
2346
|
+
message: 'La date ne peut pas être antérieure à aujourd\'hui',
|
|
2347
|
+
},
|
|
2348
|
+
},
|
|
2349
|
+
],
|
|
2350
|
+
},
|
|
2351
|
+
})
|
|
2352
|
+
|
|
2353
|
+
await nextTick()
|
|
2354
|
+
|
|
2355
|
+
expect(wrapper.exists()).toBe(true)
|
|
2356
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2357
|
+
expect(typeof result).toBe('boolean')
|
|
2358
|
+
})
|
|
2359
|
+
|
|
2360
|
+
it('doit gérer la règle notAfterToday - CalendarMode', async () => {
|
|
2361
|
+
wrapper = mount(DatePicker, {
|
|
2362
|
+
global: {
|
|
2363
|
+
plugins: [vuetify],
|
|
2364
|
+
},
|
|
2365
|
+
props: {
|
|
2366
|
+
modelValue: null,
|
|
2367
|
+
label: 'Date pas après aujourd\'hui',
|
|
2368
|
+
customRules: [
|
|
2369
|
+
{
|
|
2370
|
+
type: 'notAfterToday',
|
|
2371
|
+
options: {
|
|
2372
|
+
message: 'La date ne peut pas être postérieure à aujourd\'hui',
|
|
2373
|
+
},
|
|
2374
|
+
},
|
|
2375
|
+
],
|
|
2376
|
+
},
|
|
2377
|
+
})
|
|
2378
|
+
|
|
2379
|
+
await nextTick()
|
|
2380
|
+
|
|
2381
|
+
expect(wrapper.exists()).toBe(true)
|
|
2382
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2383
|
+
expect(typeof result).toBe('boolean')
|
|
2384
|
+
})
|
|
2385
|
+
|
|
2386
|
+
it('doit gérer la règle dateExact - DatePicker', async () => {
|
|
2387
|
+
wrapper = mount(DatePicker, {
|
|
2388
|
+
global: {
|
|
2389
|
+
plugins: [vuetify],
|
|
2390
|
+
},
|
|
2391
|
+
props: {
|
|
2392
|
+
useCombinedMode: true,
|
|
2393
|
+
modelValue: null,
|
|
2394
|
+
label: 'Date exacte requise',
|
|
2395
|
+
customRules: [
|
|
2396
|
+
{
|
|
2397
|
+
type: 'dateExact',
|
|
2398
|
+
options: {
|
|
2399
|
+
date: '15/06/2024',
|
|
2400
|
+
message: 'La date doit être exactement le 15/06/2024',
|
|
2401
|
+
},
|
|
2402
|
+
},
|
|
2403
|
+
],
|
|
2404
|
+
},
|
|
2405
|
+
})
|
|
2406
|
+
|
|
2407
|
+
await nextTick()
|
|
2408
|
+
|
|
2409
|
+
expect(wrapper.exists()).toBe(true)
|
|
2410
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2411
|
+
expect(typeof result).toBe('boolean')
|
|
2412
|
+
})
|
|
2413
|
+
|
|
2414
|
+
it('doit gérer la règle isHolidayDay - DatePicker', async () => {
|
|
2415
|
+
wrapper = mount(DatePicker, {
|
|
2416
|
+
global: {
|
|
2417
|
+
plugins: [vuetify],
|
|
2418
|
+
},
|
|
2419
|
+
props: {
|
|
2420
|
+
modelValue: null,
|
|
2421
|
+
label: 'Date sans jours fériés',
|
|
2422
|
+
customRules: [
|
|
2423
|
+
{
|
|
2424
|
+
type: 'isHolidayDay',
|
|
2425
|
+
options: {
|
|
2426
|
+
message: 'Les jours fériés ne sont pas autorisés',
|
|
2427
|
+
},
|
|
2428
|
+
},
|
|
2429
|
+
],
|
|
2430
|
+
},
|
|
2431
|
+
})
|
|
2432
|
+
|
|
2433
|
+
await nextTick()
|
|
2434
|
+
|
|
2435
|
+
expect(wrapper.exists()).toBe(true)
|
|
2436
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2437
|
+
expect(typeof result).toBe('boolean')
|
|
2438
|
+
})
|
|
2439
|
+
})
|
|
2440
|
+
|
|
2441
|
+
describe('Tests des règles avec valeurs réelles', () => {
|
|
2442
|
+
it('doit valider correctement notBeforeDate avec une vraie date - CalendarMode', async () => {
|
|
2443
|
+
wrapper = mount(DatePicker, {
|
|
2444
|
+
global: {
|
|
2445
|
+
plugins: [vuetify],
|
|
2446
|
+
},
|
|
2447
|
+
props: {
|
|
2448
|
+
modelValue: '10/06/2024', // Date avant la limite
|
|
2449
|
+
label: 'Date avec validation notBeforeDate',
|
|
2450
|
+
customRules: [
|
|
2451
|
+
{
|
|
2452
|
+
type: 'notBeforeDate',
|
|
2453
|
+
options: {
|
|
2454
|
+
date: '15/06/2024',
|
|
2455
|
+
message: 'Date ne peut pas être avant le 15/06/2024',
|
|
2456
|
+
},
|
|
2457
|
+
},
|
|
2458
|
+
],
|
|
2459
|
+
},
|
|
2460
|
+
})
|
|
2461
|
+
|
|
2462
|
+
await nextTick()
|
|
2463
|
+
|
|
2464
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2465
|
+
expect(result).toBe(false) // Doit échouer car 10/06 < 15/06
|
|
2466
|
+
})
|
|
2467
|
+
|
|
2468
|
+
it('doit valider correctement notAfterDate avec une vraie date - DatePicker', async () => {
|
|
2469
|
+
wrapper = mount(DatePicker, {
|
|
2470
|
+
global: {
|
|
2471
|
+
plugins: [vuetify],
|
|
2472
|
+
},
|
|
2473
|
+
props: {
|
|
2474
|
+
useCombinedMode: true,
|
|
2475
|
+
modelValue: '20/06/2024', // Date après la limite
|
|
2476
|
+
label: 'Date avec validation notAfterDate',
|
|
2477
|
+
customRules: [
|
|
2478
|
+
{
|
|
2479
|
+
type: 'notAfterDate',
|
|
2480
|
+
options: {
|
|
2481
|
+
date: '15/06/2024',
|
|
2482
|
+
message: 'Date ne peut pas être après le 15/06/2024',
|
|
2483
|
+
},
|
|
2484
|
+
},
|
|
2485
|
+
],
|
|
2486
|
+
},
|
|
2487
|
+
})
|
|
2488
|
+
|
|
2489
|
+
await nextTick()
|
|
2490
|
+
|
|
2491
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2492
|
+
expect(result).toBe(false) // Doit échouer car 20/06 > 15/06
|
|
2493
|
+
})
|
|
2494
|
+
|
|
2495
|
+
it('doit valider correctement dateExact avec une vraie date - DatePicker', async () => {
|
|
2496
|
+
wrapper = mount(DatePicker, {
|
|
2497
|
+
global: {
|
|
2498
|
+
plugins: [vuetify],
|
|
2499
|
+
},
|
|
2500
|
+
props: {
|
|
2501
|
+
modelValue: '15/06/2024', // Date exacte
|
|
2502
|
+
label: 'Date avec validation dateExact',
|
|
2503
|
+
customRules: [
|
|
2504
|
+
{
|
|
2505
|
+
type: 'dateExact',
|
|
2506
|
+
options: {
|
|
2507
|
+
date: '15/06/2024',
|
|
2508
|
+
message: 'Date doit être exactement le 15/06/2024',
|
|
2509
|
+
},
|
|
2510
|
+
},
|
|
2511
|
+
],
|
|
2512
|
+
},
|
|
2513
|
+
})
|
|
2514
|
+
|
|
2515
|
+
await nextTick()
|
|
2516
|
+
|
|
2517
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2518
|
+
expect(result).toBe(true) // Doit réussir car dates identiques
|
|
2519
|
+
})
|
|
2520
|
+
})
|
|
2521
|
+
|
|
2522
|
+
describe('Tests des règles avec options avancées', () => {
|
|
2523
|
+
it('doit gérer minLength avec ignoreSpace - CalendarMode', async () => {
|
|
2524
|
+
wrapper = mount(DatePicker, {
|
|
2525
|
+
global: {
|
|
2526
|
+
plugins: [vuetify],
|
|
2527
|
+
},
|
|
2528
|
+
props: {
|
|
2529
|
+
modelValue: null,
|
|
2530
|
+
label: 'Date avec minLength ignoreSpace',
|
|
2531
|
+
customRules: [
|
|
2532
|
+
{
|
|
2533
|
+
type: 'minLength',
|
|
2534
|
+
options: {
|
|
2535
|
+
length: 5,
|
|
2536
|
+
ignoreSpace: true,
|
|
2537
|
+
message: 'Minimum 5 caractères sans espaces',
|
|
2538
|
+
},
|
|
2539
|
+
},
|
|
2540
|
+
],
|
|
2541
|
+
},
|
|
2542
|
+
})
|
|
2543
|
+
|
|
2544
|
+
await nextTick()
|
|
2545
|
+
|
|
2546
|
+
expect(wrapper.exists()).toBe(true)
|
|
2547
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2548
|
+
expect(typeof result).toBe('boolean')
|
|
2549
|
+
})
|
|
2550
|
+
|
|
2551
|
+
it('doit gérer les règles en mode warning - DatePicker', async () => {
|
|
2552
|
+
wrapper = mount(DatePicker, {
|
|
2553
|
+
global: {
|
|
2554
|
+
plugins: [vuetify],
|
|
2555
|
+
},
|
|
2556
|
+
props: {
|
|
2557
|
+
useCombinedMode: true,
|
|
2558
|
+
modelValue: '2024-06-15',
|
|
2559
|
+
label: 'Date avec warning rules',
|
|
2560
|
+
customWarningRules: [
|
|
2561
|
+
{
|
|
2562
|
+
type: 'notWeekend',
|
|
2563
|
+
options: {
|
|
2564
|
+
isWarning: true,
|
|
2565
|
+
warningMessage: 'Attention: date en weekend',
|
|
2566
|
+
},
|
|
2567
|
+
},
|
|
2568
|
+
],
|
|
2569
|
+
},
|
|
2570
|
+
})
|
|
2571
|
+
|
|
2572
|
+
await nextTick()
|
|
2573
|
+
|
|
2574
|
+
expect(wrapper.exists()).toBe(true)
|
|
2575
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2576
|
+
expect(typeof result).toBe('boolean')
|
|
2577
|
+
})
|
|
2578
|
+
})
|
|
2579
|
+
})
|
|
2580
|
+
|
|
2581
|
+
/**
|
|
2582
|
+
* TESTS TOUCHY - CAS LIMITES ET EDGE CASES COMPLEXES
|
|
2583
|
+
*/
|
|
2584
|
+
describe('Tests Touchy - Cas Limites et Edge Cases', () => {
|
|
2585
|
+
describe('Tests de concurrence et race conditions', () => {
|
|
2586
|
+
it('doit gérer les changements rapides de modelValue pendant la validation', async () => {
|
|
2587
|
+
wrapper = mount(DatePicker, {
|
|
2588
|
+
global: {
|
|
2589
|
+
plugins: [vuetify],
|
|
2590
|
+
},
|
|
2591
|
+
props: {
|
|
2592
|
+
useCombinedMode: true,
|
|
2593
|
+
modelValue: null,
|
|
2594
|
+
label: 'Date race condition',
|
|
2595
|
+
customRules: [
|
|
2596
|
+
{
|
|
2597
|
+
type: 'notBeforeDate',
|
|
2598
|
+
options: {
|
|
2599
|
+
date: '15/06/2024',
|
|
2600
|
+
message: 'Date trop ancienne',
|
|
2601
|
+
},
|
|
2602
|
+
},
|
|
2603
|
+
],
|
|
2604
|
+
},
|
|
2605
|
+
})
|
|
2606
|
+
|
|
2607
|
+
await nextTick()
|
|
2608
|
+
|
|
2609
|
+
// Simuler des changements rapides pendant la validation
|
|
2610
|
+
const promises: Promise<void>[] = []
|
|
2611
|
+
for (let i = 0; i < 5; i++) {
|
|
2612
|
+
promises.push(wrapper.setProps({ modelValue: `${10 + i}/06/2024` }))
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
await Promise.all(promises)
|
|
2616
|
+
await nextTick()
|
|
2617
|
+
|
|
2618
|
+
// Le composant doit rester stable
|
|
2619
|
+
expect(wrapper.exists()).toBe(true)
|
|
2620
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2621
|
+
expect(typeof result).toBe('boolean')
|
|
2622
|
+
})
|
|
2623
|
+
|
|
2624
|
+
it('doit gérer les validations simultanées sur plusieurs instances', async () => {
|
|
2625
|
+
const wrapper1 = mount(DatePicker, {
|
|
2626
|
+
global: {
|
|
2627
|
+
plugins: [vuetify],
|
|
2628
|
+
},
|
|
2629
|
+
props: {
|
|
2630
|
+
modelValue: '10/06/2024',
|
|
2631
|
+
label: 'Date 1',
|
|
2632
|
+
customRules: [
|
|
2633
|
+
{
|
|
2634
|
+
type: 'notBeforeDate',
|
|
2635
|
+
options: {
|
|
2636
|
+
date: '15/06/2024',
|
|
2637
|
+
message: 'Erreur date 1',
|
|
2638
|
+
},
|
|
2639
|
+
},
|
|
2640
|
+
],
|
|
2641
|
+
},
|
|
2642
|
+
})
|
|
2643
|
+
|
|
2644
|
+
const wrapper2 = mount(DatePicker, {
|
|
2645
|
+
global: {
|
|
2646
|
+
plugins: [vuetify],
|
|
2647
|
+
},
|
|
2648
|
+
props: {
|
|
2649
|
+
useCombinedMode: true,
|
|
2650
|
+
modelValue: '20/06/2024',
|
|
2651
|
+
label: 'Date 2',
|
|
2652
|
+
customRules: [
|
|
2653
|
+
{
|
|
2654
|
+
type: 'notAfterDate',
|
|
2655
|
+
options: {
|
|
2656
|
+
date: '15/06/2024',
|
|
2657
|
+
message: 'Erreur date 2',
|
|
2658
|
+
},
|
|
2659
|
+
},
|
|
2660
|
+
],
|
|
2661
|
+
},
|
|
2662
|
+
})
|
|
2663
|
+
|
|
2664
|
+
await nextTick()
|
|
2665
|
+
|
|
2666
|
+
// Valider simultanément
|
|
2667
|
+
const [result1, result2] = await Promise.all([
|
|
2668
|
+
Promise.resolve(wrapper1.vm.validateOnSubmit()),
|
|
2669
|
+
Promise.resolve(wrapper2.vm.validateOnSubmit()),
|
|
2670
|
+
])
|
|
2671
|
+
|
|
2672
|
+
expect(result1).toBe(false) // 10/06 < 15/06
|
|
2673
|
+
expect(result2).toBe(false) // 20/06 > 15/06
|
|
2674
|
+
|
|
2675
|
+
wrapper1.unmount()
|
|
2676
|
+
wrapper2.unmount()
|
|
2677
|
+
})
|
|
2678
|
+
})
|
|
2679
|
+
|
|
2680
|
+
describe('Tests de memory leaks et cleanup', () => {
|
|
2681
|
+
it('doit nettoyer les event listeners lors du unmount - CalendarMode', async () => {
|
|
2682
|
+
const removeEventListenerSpy = vi.spyOn(document, 'removeEventListener')
|
|
2683
|
+
|
|
2684
|
+
wrapper = mount(DatePicker, {
|
|
2685
|
+
global: {
|
|
2686
|
+
plugins: [vuetify],
|
|
2687
|
+
},
|
|
2688
|
+
props: {
|
|
2689
|
+
modelValue: null,
|
|
2690
|
+
label: 'Test cleanup',
|
|
2691
|
+
},
|
|
2692
|
+
})
|
|
2693
|
+
|
|
2694
|
+
await nextTick()
|
|
2695
|
+
|
|
2696
|
+
// Unmount et vérifier le cleanup
|
|
2697
|
+
wrapper.unmount()
|
|
2698
|
+
|
|
2699
|
+
expect(removeEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function))
|
|
2700
|
+
removeEventListenerSpy.mockRestore()
|
|
2701
|
+
})
|
|
2702
|
+
|
|
2703
|
+
it('doit nettoyer les event listeners lors du unmount - DatePicker', async () => {
|
|
2704
|
+
const removeEventListenerSpy = vi.spyOn(document, 'removeEventListener')
|
|
2705
|
+
|
|
2706
|
+
wrapper = mount(DatePicker, {
|
|
2707
|
+
global: {
|
|
2708
|
+
plugins: [vuetify],
|
|
2709
|
+
},
|
|
2710
|
+
props: {
|
|
2711
|
+
useCombinedMode: true,
|
|
2712
|
+
modelValue: null,
|
|
2713
|
+
label: 'Test cleanup Complex',
|
|
2714
|
+
},
|
|
2715
|
+
})
|
|
2716
|
+
|
|
2717
|
+
await nextTick()
|
|
2718
|
+
|
|
2719
|
+
// Unmount et vérifier le cleanup
|
|
2720
|
+
wrapper.unmount()
|
|
2721
|
+
|
|
2722
|
+
expect(removeEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function))
|
|
2723
|
+
removeEventListenerSpy.mockRestore()
|
|
2724
|
+
})
|
|
2725
|
+
|
|
2726
|
+
it('doit gérer les setTimeout sans fuites mémoire', async () => {
|
|
2727
|
+
const setTimeoutSpy = vi.spyOn(global, 'setTimeout')
|
|
2728
|
+
|
|
2729
|
+
wrapper = mount(DatePicker, {
|
|
2730
|
+
global: {
|
|
2731
|
+
plugins: [vuetify],
|
|
2732
|
+
},
|
|
2733
|
+
props: {
|
|
2734
|
+
useCombinedMode: true,
|
|
2735
|
+
modelValue: null,
|
|
2736
|
+
label: 'Test setTimeout',
|
|
2737
|
+
customRules: [
|
|
2738
|
+
{
|
|
2739
|
+
type: 'notBeforeDate',
|
|
2740
|
+
options: {
|
|
2741
|
+
date: '15/06/2024',
|
|
2742
|
+
message: 'Test',
|
|
2743
|
+
},
|
|
2744
|
+
},
|
|
2745
|
+
],
|
|
2746
|
+
},
|
|
2747
|
+
})
|
|
2748
|
+
|
|
2749
|
+
await nextTick()
|
|
2750
|
+
|
|
2751
|
+
// Changer les règles pour déclencher setTimeout
|
|
2752
|
+
await wrapper.setProps({
|
|
2753
|
+
customRules: [
|
|
2754
|
+
{
|
|
2755
|
+
type: 'notAfterDate',
|
|
2756
|
+
options: {
|
|
2757
|
+
date: '20/06/2024',
|
|
2758
|
+
message: 'Test 2',
|
|
2759
|
+
},
|
|
2760
|
+
},
|
|
2761
|
+
],
|
|
2762
|
+
})
|
|
2763
|
+
|
|
2764
|
+
await nextTick()
|
|
2765
|
+
|
|
2766
|
+
// Vérifier que setTimeout a été appelé
|
|
2767
|
+
expect(setTimeoutSpy).toHaveBeenCalled()
|
|
2768
|
+
|
|
2769
|
+
// Unmount pour tester le cleanup
|
|
2770
|
+
wrapper.unmount()
|
|
2771
|
+
|
|
2772
|
+
setTimeoutSpy.mockRestore()
|
|
2773
|
+
})
|
|
2774
|
+
})
|
|
2775
|
+
|
|
2776
|
+
describe('Tests de formatage et parsing extrêmes', () => {
|
|
2777
|
+
it('doit gérer les dates avec des années à 2 chiffres', async () => {
|
|
2778
|
+
wrapper = mount(DatePicker, {
|
|
2779
|
+
global: {
|
|
2780
|
+
plugins: [vuetify],
|
|
2781
|
+
},
|
|
2782
|
+
props: {
|
|
2783
|
+
modelValue: null,
|
|
2784
|
+
label: 'Date année 2 chiffres',
|
|
2785
|
+
format: 'DD/MM/YY',
|
|
2786
|
+
},
|
|
2787
|
+
})
|
|
2788
|
+
|
|
2789
|
+
await nextTick()
|
|
2790
|
+
|
|
2791
|
+
const input = wrapper.find('input')
|
|
2792
|
+
await input.setValue('15/06/99')
|
|
2793
|
+
await input.trigger('blur')
|
|
2794
|
+
|
|
2795
|
+
expect(wrapper.exists()).toBe(true)
|
|
2796
|
+
})
|
|
2797
|
+
|
|
2798
|
+
it('doit gérer les dates limites (29 février années bissextiles)', async () => {
|
|
2799
|
+
wrapper = mount(DatePicker, {
|
|
2800
|
+
global: {
|
|
2801
|
+
plugins: [vuetify],
|
|
2802
|
+
},
|
|
2803
|
+
props: {
|
|
2804
|
+
modelValue: '29/02/2024', // 2024 est bissextile
|
|
2805
|
+
label: 'Date bissextile',
|
|
2806
|
+
customRules: [
|
|
2807
|
+
{
|
|
2808
|
+
type: 'dateExact',
|
|
2809
|
+
options: {
|
|
2810
|
+
date: '29/02/2024',
|
|
2811
|
+
message: 'Doit être le 29 février 2024',
|
|
2812
|
+
},
|
|
2813
|
+
},
|
|
2814
|
+
],
|
|
2815
|
+
},
|
|
2816
|
+
})
|
|
2817
|
+
|
|
2818
|
+
await nextTick()
|
|
2819
|
+
|
|
2820
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2821
|
+
expect(result).toBe(true) // Doit réussir
|
|
2822
|
+
})
|
|
2823
|
+
|
|
2824
|
+
it('doit rejeter le 29 février pour les années non bissextiles', async () => {
|
|
2825
|
+
wrapper = mount(DatePicker, {
|
|
2826
|
+
global: {
|
|
2827
|
+
plugins: [vuetify],
|
|
2828
|
+
},
|
|
2829
|
+
props: {
|
|
2830
|
+
useCombinedMode: true,
|
|
2831
|
+
modelValue: '29/02/2023', // 2023 n'est pas bissextile
|
|
2832
|
+
label: 'Date non bissextile',
|
|
2833
|
+
},
|
|
2834
|
+
})
|
|
2835
|
+
|
|
2836
|
+
await nextTick()
|
|
2837
|
+
|
|
2838
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2839
|
+
expect(typeof result).toBe('boolean')
|
|
2840
|
+
})
|
|
2841
|
+
|
|
2842
|
+
it('doit gérer les dates avec des séparateurs mixtes', async () => {
|
|
2843
|
+
wrapper = mount(DatePicker, {
|
|
2844
|
+
global: {
|
|
2845
|
+
plugins: [vuetify],
|
|
2846
|
+
},
|
|
2847
|
+
props: {
|
|
2848
|
+
modelValue: null,
|
|
2849
|
+
label: 'Date séparateurs mixtes',
|
|
2850
|
+
format: 'DD-MM-YYYY',
|
|
2851
|
+
},
|
|
2852
|
+
})
|
|
2853
|
+
|
|
2854
|
+
await nextTick()
|
|
2855
|
+
|
|
2856
|
+
const input = wrapper.find('input')
|
|
2857
|
+
await input.setValue('15-06-2024')
|
|
2858
|
+
await input.trigger('blur')
|
|
2859
|
+
|
|
2860
|
+
expect(wrapper.exists()).toBe(true)
|
|
2861
|
+
})
|
|
2862
|
+
})
|
|
2863
|
+
|
|
2864
|
+
describe('Tests de validation avec règles contradictoires', () => {
|
|
2865
|
+
it('doit gérer des règles contradictoires notBeforeDate et notAfterDate', async () => {
|
|
2866
|
+
wrapper = mount(DatePicker, {
|
|
2867
|
+
global: {
|
|
2868
|
+
plugins: [vuetify],
|
|
2869
|
+
},
|
|
2870
|
+
props: {
|
|
2871
|
+
useCombinedMode: true,
|
|
2872
|
+
modelValue: '15/06/2024',
|
|
2873
|
+
label: 'Règles contradictoires',
|
|
2874
|
+
customRules: [
|
|
2875
|
+
{
|
|
2876
|
+
type: 'notBeforeDate',
|
|
2877
|
+
options: {
|
|
2878
|
+
date: '20/06/2024', // Date doit être >= 20/06
|
|
2879
|
+
message: 'Date trop ancienne',
|
|
2880
|
+
},
|
|
2881
|
+
},
|
|
2882
|
+
{
|
|
2883
|
+
type: 'notAfterDate',
|
|
2884
|
+
options: {
|
|
2885
|
+
date: '10/06/2024', // Date doit être <= 10/06
|
|
2886
|
+
message: 'Date trop récente',
|
|
2887
|
+
},
|
|
2888
|
+
},
|
|
2889
|
+
],
|
|
2890
|
+
},
|
|
2891
|
+
})
|
|
2892
|
+
|
|
2893
|
+
await nextTick()
|
|
2894
|
+
|
|
2895
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2896
|
+
expect(result).toBe(false) // Impossible de satisfaire les deux règles
|
|
2897
|
+
})
|
|
2898
|
+
|
|
2899
|
+
it('doit gérer des custom rules qui se contredisent', async () => {
|
|
2900
|
+
const rule1 = vi.fn().mockReturnValue(true)
|
|
2901
|
+
const rule2 = vi.fn().mockReturnValue(false)
|
|
2902
|
+
|
|
2903
|
+
wrapper = mount(DatePicker, {
|
|
2904
|
+
global: {
|
|
2905
|
+
plugins: [vuetify],
|
|
2906
|
+
},
|
|
2907
|
+
props: {
|
|
2908
|
+
modelValue: '15/06/2024',
|
|
2909
|
+
label: 'Custom rules contradictoires',
|
|
2910
|
+
customRules: [
|
|
2911
|
+
{
|
|
2912
|
+
type: 'custom',
|
|
2913
|
+
options: {
|
|
2914
|
+
validate: rule1,
|
|
2915
|
+
message: 'Règle 1 OK',
|
|
2916
|
+
},
|
|
2917
|
+
},
|
|
2918
|
+
{
|
|
2919
|
+
type: 'custom',
|
|
2920
|
+
options: {
|
|
2921
|
+
validate: rule2,
|
|
2922
|
+
message: 'Règle 2 KO',
|
|
2923
|
+
},
|
|
2924
|
+
},
|
|
2925
|
+
],
|
|
2926
|
+
},
|
|
2927
|
+
})
|
|
2928
|
+
|
|
2929
|
+
await nextTick()
|
|
2930
|
+
|
|
2931
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2932
|
+
expect(result).toBe(false) // Une règle échoue
|
|
2933
|
+
expect(rule1).toHaveBeenCalled()
|
|
2934
|
+
expect(rule2).toHaveBeenCalled()
|
|
2935
|
+
})
|
|
2936
|
+
})
|
|
2937
|
+
|
|
2938
|
+
describe('Tests de performance avec données massives', () => {
|
|
2939
|
+
it('doit gérer un grand nombre de règles sans ralentissement', async () => {
|
|
2940
|
+
const manyRules = Array.from({ length: 50 }, (_, i) => ({
|
|
2941
|
+
type: 'custom',
|
|
2942
|
+
options: {
|
|
2943
|
+
validate: vi.fn().mockReturnValue(true),
|
|
2944
|
+
message: `Règle ${i + 1}`,
|
|
2945
|
+
},
|
|
2946
|
+
}))
|
|
2947
|
+
|
|
2948
|
+
const startTime = performance.now()
|
|
2949
|
+
|
|
2950
|
+
wrapper = mount(DatePicker, {
|
|
2951
|
+
global: {
|
|
2952
|
+
plugins: [vuetify],
|
|
2953
|
+
},
|
|
2954
|
+
props: {
|
|
2955
|
+
useCombinedMode: true,
|
|
2956
|
+
modelValue: '15/06/2024',
|
|
2957
|
+
label: 'Performance test',
|
|
2958
|
+
customRules: manyRules,
|
|
2959
|
+
},
|
|
2960
|
+
})
|
|
2961
|
+
|
|
2962
|
+
await nextTick()
|
|
2963
|
+
|
|
2964
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
2965
|
+
const endTime = performance.now()
|
|
2966
|
+
|
|
2967
|
+
expect(result).toBe(true)
|
|
2968
|
+
expect(endTime - startTime).toBeLessThan(1000) // Moins d'1 seconde
|
|
2969
|
+
|
|
2970
|
+
// Vérifier que toutes les règles ont été appelées
|
|
2971
|
+
manyRules.forEach((rule) => {
|
|
2972
|
+
expect(rule.options.validate).toHaveBeenCalled()
|
|
2973
|
+
})
|
|
2974
|
+
})
|
|
2975
|
+
|
|
2976
|
+
it('doit gérer les changements rapides de props sans lag', async () => {
|
|
2977
|
+
wrapper = mount(DatePicker, {
|
|
2978
|
+
global: {
|
|
2979
|
+
plugins: [vuetify],
|
|
2980
|
+
},
|
|
2981
|
+
props: {
|
|
2982
|
+
modelValue: null,
|
|
2983
|
+
label: 'Performance props',
|
|
2984
|
+
format: 'DD/MM/YYYY',
|
|
2985
|
+
},
|
|
2986
|
+
})
|
|
2987
|
+
|
|
2988
|
+
await nextTick()
|
|
2989
|
+
|
|
2990
|
+
const startTime = performance.now()
|
|
2991
|
+
|
|
2992
|
+
// Changer rapidement plusieurs props
|
|
2993
|
+
for (let i = 0; i < 20; i++) {
|
|
2994
|
+
await wrapper.setProps({
|
|
2995
|
+
format: i % 2 === 0 ? 'DD/MM/YYYY' : 'MM/DD/YYYY',
|
|
2996
|
+
label: `Label ${i}`,
|
|
2997
|
+
required: i % 2 === 0,
|
|
2998
|
+
})
|
|
2999
|
+
}
|
|
3000
|
+
|
|
3001
|
+
const endTime = performance.now()
|
|
3002
|
+
|
|
3003
|
+
expect(wrapper.exists()).toBe(true)
|
|
3004
|
+
expect(endTime - startTime).toBeLessThan(500) // Moins de 500ms
|
|
3005
|
+
})
|
|
3006
|
+
})
|
|
3007
|
+
|
|
3008
|
+
describe('Tests de réactivité complexe', () => {
|
|
3009
|
+
it('doit gérer les règles réactives avec computed imbriqués', async () => {
|
|
3010
|
+
const offset = ref(5)
|
|
3011
|
+
|
|
3012
|
+
const computedDate = computed(() => {
|
|
3013
|
+
const date = new Date(2024, 5, 15) // 15 juin 2024
|
|
3014
|
+
date.setDate(date.getDate() + offset.value)
|
|
3015
|
+
return `${date.getDate().toString().padStart(2, '0')}/${(date.getMonth() + 1).toString().padStart(2, '0')}/${date.getFullYear()}`
|
|
3016
|
+
})
|
|
3017
|
+
|
|
3018
|
+
const nestedRules = computed(() => [
|
|
3019
|
+
{
|
|
3020
|
+
type: 'notBeforeDate',
|
|
3021
|
+
options: {
|
|
3022
|
+
date: computedDate.value,
|
|
3023
|
+
message: `Date ne peut pas être avant ${computedDate.value}`,
|
|
3024
|
+
},
|
|
3025
|
+
},
|
|
3026
|
+
])
|
|
3027
|
+
|
|
3028
|
+
wrapper = mount(DatePicker, {
|
|
3029
|
+
global: {
|
|
3030
|
+
plugins: [vuetify],
|
|
3031
|
+
},
|
|
3032
|
+
props: {
|
|
3033
|
+
useCombinedMode: true,
|
|
3034
|
+
modelValue: '18/06/2024',
|
|
3035
|
+
label: 'Règles réactives imbriquées',
|
|
3036
|
+
customRules: nestedRules.value,
|
|
3037
|
+
},
|
|
3038
|
+
})
|
|
3039
|
+
|
|
3040
|
+
await nextTick()
|
|
3041
|
+
|
|
3042
|
+
// Validation initiale
|
|
3043
|
+
let result = wrapper.vm.validateOnSubmit()
|
|
3044
|
+
expect(typeof result).toBe('boolean')
|
|
3045
|
+
|
|
3046
|
+
// Changer l'offset et re-tester
|
|
3047
|
+
offset.value = 10
|
|
3048
|
+
await wrapper.setProps({ customRules: nestedRules.value })
|
|
3049
|
+
await nextTick()
|
|
3050
|
+
|
|
3051
|
+
result = wrapper.vm.validateOnSubmit()
|
|
3052
|
+
expect(typeof result).toBe('boolean')
|
|
3053
|
+
})
|
|
3054
|
+
|
|
3055
|
+
it('doit gérer les règles réactives avec dépendances multiples', async () => {
|
|
3056
|
+
const dateA = ref('15/06/2024')
|
|
3057
|
+
const dateB = ref('20/06/2024')
|
|
3058
|
+
|
|
3059
|
+
// Créer des règles qui dépendent de plusieurs refs
|
|
3060
|
+
const complexRules = computed(() => [
|
|
3061
|
+
{
|
|
3062
|
+
type: 'notBeforeDate',
|
|
3063
|
+
options: {
|
|
3064
|
+
date: dateA.value,
|
|
3065
|
+
message: `Date ne peut pas être avant ${dateA.value}`,
|
|
3066
|
+
},
|
|
3067
|
+
},
|
|
3068
|
+
{
|
|
3069
|
+
type: 'notAfterDate',
|
|
3070
|
+
options: {
|
|
3071
|
+
date: dateB.value,
|
|
3072
|
+
message: `Date ne peut pas être après ${dateB.value}`,
|
|
3073
|
+
},
|
|
3074
|
+
},
|
|
3075
|
+
])
|
|
3076
|
+
|
|
3077
|
+
wrapper = mount(DatePicker, {
|
|
3078
|
+
global: {
|
|
3079
|
+
plugins: [vuetify],
|
|
3080
|
+
},
|
|
3081
|
+
props: {
|
|
3082
|
+
modelValue: '18/06/2024',
|
|
3083
|
+
label: 'Test règles réactives complexes',
|
|
3084
|
+
customRules: complexRules.value,
|
|
3085
|
+
},
|
|
3086
|
+
})
|
|
3087
|
+
|
|
3088
|
+
await nextTick()
|
|
3089
|
+
|
|
3090
|
+
// Validation initiale
|
|
3091
|
+
let result = wrapper.vm.validateOnSubmit()
|
|
3092
|
+
expect(typeof result).toBe('boolean')
|
|
3093
|
+
|
|
3094
|
+
// Changer les dates de référence
|
|
3095
|
+
dateA.value = '10/06/2024'
|
|
3096
|
+
dateB.value = '25/06/2024'
|
|
3097
|
+
await wrapper.setProps({ customRules: complexRules.value })
|
|
3098
|
+
await nextTick()
|
|
3099
|
+
|
|
3100
|
+
result = wrapper.vm.validateOnSubmit()
|
|
3101
|
+
expect(typeof result).toBe('boolean')
|
|
3102
|
+
})
|
|
3103
|
+
})
|
|
3104
|
+
|
|
3105
|
+
describe('Tests de edge cases spécifiques aux navigateurs', () => {
|
|
3106
|
+
it('doit gérer les événements de collage avec données corrompues', async () => {
|
|
3107
|
+
wrapper = mount(DatePicker, {
|
|
3108
|
+
global: {
|
|
3109
|
+
plugins: [vuetify],
|
|
3110
|
+
},
|
|
3111
|
+
props: {
|
|
3112
|
+
modelValue: null,
|
|
3113
|
+
label: 'Test paste corrompu',
|
|
3114
|
+
format: 'DD/MM/YYYY',
|
|
3115
|
+
},
|
|
3116
|
+
})
|
|
3117
|
+
|
|
3118
|
+
await nextTick()
|
|
3119
|
+
|
|
3120
|
+
const input = wrapper.find('input')
|
|
3121
|
+
|
|
3122
|
+
// Simuler un collage avec données corrompues
|
|
3123
|
+
const pasteEvent = new Event('paste', { bubbles: true })
|
|
3124
|
+
Object.defineProperty(pasteEvent, 'clipboardData', {
|
|
3125
|
+
value: {
|
|
3126
|
+
getData: () => '���invalid���data���',
|
|
3127
|
+
},
|
|
3128
|
+
})
|
|
3129
|
+
|
|
3130
|
+
input.element.dispatchEvent(pasteEvent)
|
|
3131
|
+
await nextTick()
|
|
3132
|
+
|
|
3133
|
+
expect(wrapper.exists()).toBe(true)
|
|
3134
|
+
})
|
|
3135
|
+
|
|
3136
|
+
it('doit gérer les changements de timezone', async () => {
|
|
3137
|
+
wrapper = mount(DatePicker, {
|
|
3138
|
+
global: {
|
|
3139
|
+
plugins: [vuetify],
|
|
3140
|
+
},
|
|
3141
|
+
props: {
|
|
3142
|
+
useCombinedMode: true,
|
|
3143
|
+
modelValue: '15/06/2024',
|
|
3144
|
+
label: 'Test timezone',
|
|
3145
|
+
customRules: [
|
|
3146
|
+
{
|
|
3147
|
+
type: 'notBeforeToday',
|
|
3148
|
+
options: {
|
|
3149
|
+
message: 'Date ne peut pas être avant aujourd\'hui',
|
|
3150
|
+
},
|
|
3151
|
+
},
|
|
3152
|
+
],
|
|
3153
|
+
},
|
|
3154
|
+
})
|
|
3155
|
+
|
|
3156
|
+
await nextTick()
|
|
3157
|
+
|
|
3158
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
3159
|
+
expect(typeof result).toBe('boolean')
|
|
3160
|
+
})
|
|
3161
|
+
})
|
|
3162
|
+
})
|
|
3163
|
+
|
|
3164
|
+
/**
|
|
3165
|
+
* TESTS COMPLETS DES FORMATS D'ENTRÉE ET DE SORTIE - TOUS LES MODES
|
|
3166
|
+
*/
|
|
3167
|
+
describe('Tests Complets des Formats d\'Entrée et de Sortie', () => {
|
|
3168
|
+
describe('Tests CalendarMode - Formats d\'entrée et sortie', () => {
|
|
3169
|
+
const formatCombinations = [
|
|
3170
|
+
{ display: 'DD/MM/YYYY', return: 'YYYY-MM-DD', input: '15/06/2024', expected: '2024-06-15' },
|
|
3171
|
+
{ display: 'MM/DD/YYYY', return: 'DD/MM/YYYY', input: '06/15/2024', expected: '15/06/2024' },
|
|
3172
|
+
{ display: 'DD-MM-YYYY', return: 'MM-DD-YYYY', input: '15-06-2024', expected: '06-15-2024' },
|
|
3173
|
+
{ display: 'YYYY/MM/DD', return: 'DD/MM/YYYY', input: '2024/06/15', expected: '15/06/2024' },
|
|
3174
|
+
{ display: 'DD.MM.YYYY', return: 'YYYY.MM.DD', input: '15.06.2024', expected: '2024.06.15' },
|
|
3175
|
+
{ display: 'DD/MM/YY', return: 'YYYY-MM-DD', input: '15/06/24', expected: '2024-06-15' },
|
|
3176
|
+
{ display: 'MM-DD-YY', return: 'DD-MM-YYYY', input: '06-15-24', expected: '15-06-2024' },
|
|
3177
|
+
]
|
|
3178
|
+
|
|
3179
|
+
formatCombinations.forEach(({ display, return: returnFormat, input }) => {
|
|
3180
|
+
it(`doit gérer format d'affichage ${display} et format de retour ${returnFormat}`, async () => {
|
|
3181
|
+
wrapper = mount(DatePicker, {
|
|
3182
|
+
global: {
|
|
3183
|
+
plugins: [vuetify],
|
|
3184
|
+
},
|
|
3185
|
+
props: {
|
|
3186
|
+
modelValue: null,
|
|
3187
|
+
label: `Test format ${display} → ${returnFormat}`,
|
|
3188
|
+
format: display,
|
|
3189
|
+
dateFormatReturn: returnFormat,
|
|
3190
|
+
},
|
|
3191
|
+
})
|
|
3192
|
+
|
|
3193
|
+
await nextTick()
|
|
3194
|
+
|
|
3195
|
+
// Simuler la sélection d'une date
|
|
3196
|
+
await wrapper.setProps({ modelValue: input })
|
|
3197
|
+
await nextTick()
|
|
3198
|
+
|
|
3199
|
+
expect(wrapper.exists()).toBe(true)
|
|
3200
|
+
expect(wrapper.props('format')).toBe(display)
|
|
3201
|
+
expect(wrapper.props('dateFormatReturn')).toBe(returnFormat)
|
|
3202
|
+
})
|
|
3203
|
+
})
|
|
3204
|
+
|
|
3205
|
+
it('doit gérer les formats avec séparateurs mixtes', async () => {
|
|
3206
|
+
wrapper = mount(DatePicker, {
|
|
3207
|
+
global: {
|
|
3208
|
+
plugins: [vuetify],
|
|
3209
|
+
},
|
|
3210
|
+
props: {
|
|
3211
|
+
modelValue: null,
|
|
3212
|
+
label: 'Format séparateurs mixtes',
|
|
3213
|
+
format: 'DD/MM-YYYY',
|
|
3214
|
+
dateFormatReturn: 'YYYY.MM.DD',
|
|
3215
|
+
},
|
|
3216
|
+
})
|
|
3217
|
+
|
|
3218
|
+
await nextTick()
|
|
3219
|
+
|
|
3220
|
+
expect(wrapper.exists()).toBe(true)
|
|
3221
|
+
expect(wrapper.props('format')).toBe('DD/MM-YYYY')
|
|
3222
|
+
expect(wrapper.props('dateFormatReturn')).toBe('YYYY.MM.DD')
|
|
3223
|
+
})
|
|
3224
|
+
|
|
3225
|
+
it('doit gérer les formats identiques pour affichage et retour', async () => {
|
|
3226
|
+
wrapper = mount(DatePicker, {
|
|
3227
|
+
global: {
|
|
3228
|
+
plugins: [vuetify],
|
|
3229
|
+
},
|
|
3230
|
+
props: {
|
|
3231
|
+
modelValue: '15/06/2024',
|
|
3232
|
+
label: 'Format identique',
|
|
3233
|
+
format: 'DD/MM/YYYY',
|
|
3234
|
+
dateFormatReturn: 'DD/MM/YYYY',
|
|
3235
|
+
},
|
|
3236
|
+
})
|
|
3237
|
+
|
|
3238
|
+
await nextTick()
|
|
3239
|
+
|
|
3240
|
+
expect(wrapper.exists()).toBe(true)
|
|
3241
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
3242
|
+
expect(typeof result).toBe('boolean')
|
|
3243
|
+
})
|
|
3244
|
+
|
|
3245
|
+
it('doit gérer les plages de dates avec formats différents', async () => {
|
|
3246
|
+
wrapper = mount(DatePicker, {
|
|
3247
|
+
global: {
|
|
3248
|
+
plugins: [vuetify],
|
|
3249
|
+
},
|
|
3250
|
+
props: {
|
|
3251
|
+
modelValue: ['15/06/2024', '20/06/2024'],
|
|
3252
|
+
label: 'Plage formats différents',
|
|
3253
|
+
format: 'DD/MM/YYYY',
|
|
3254
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
3255
|
+
displayRange: true,
|
|
3256
|
+
},
|
|
3257
|
+
})
|
|
3258
|
+
|
|
3259
|
+
await nextTick()
|
|
3260
|
+
|
|
3261
|
+
expect(wrapper.exists()).toBe(true)
|
|
3262
|
+
expect(wrapper.props('displayRange')).toBe(true)
|
|
3263
|
+
})
|
|
3264
|
+
})
|
|
3265
|
+
|
|
3266
|
+
describe('Tests DatePicker - Formats d\'entrée et sortie', () => {
|
|
3267
|
+
const complexFormatCombinations = [
|
|
3268
|
+
{ display: 'DD/MM/YYYY', return: 'ISO', input: '15/06/2024', description: 'Format français vers ISO' },
|
|
3269
|
+
{ display: 'MM/DD/YYYY', return: 'DD-MM-YYYY', input: '06/15/2024', description: 'Format US vers européen' },
|
|
3270
|
+
{ display: 'YYYY-MM-DD', return: 'DD/MM/YYYY', input: '2024-06-15', description: 'ISO vers français' },
|
|
3271
|
+
{ display: 'DD.MM.YY', return: 'YYYY/MM/DD', input: '15.06.24', description: 'Format court vers long' },
|
|
3272
|
+
{ display: 'MM-DD-YY', return: 'DD.MM.YYYY', input: '06-15-24', description: 'US court vers européen long' },
|
|
3273
|
+
]
|
|
3274
|
+
|
|
3275
|
+
complexFormatCombinations.forEach(({ display, return: returnFormat, input, description }) => {
|
|
3276
|
+
it(`doit gérer ${description} (${display} → ${returnFormat})`, async () => {
|
|
3277
|
+
wrapper = mount(DatePicker, {
|
|
3278
|
+
global: {
|
|
3279
|
+
plugins: [vuetify],
|
|
3280
|
+
},
|
|
3281
|
+
props: {
|
|
3282
|
+
useCombinedMode: true,
|
|
3283
|
+
modelValue: null,
|
|
3284
|
+
label: description,
|
|
3285
|
+
format: display,
|
|
3286
|
+
dateFormatReturn: returnFormat,
|
|
3287
|
+
},
|
|
3288
|
+
})
|
|
3289
|
+
|
|
3290
|
+
await nextTick()
|
|
3291
|
+
|
|
3292
|
+
// Tester la saisie dans l'input
|
|
3293
|
+
const input_el = wrapper.find('input')
|
|
3294
|
+
if (input_el.exists()) {
|
|
3295
|
+
await input_el.setValue(input)
|
|
3296
|
+
await input_el.trigger('blur')
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
expect(wrapper.exists()).toBe(true)
|
|
3300
|
+
expect(wrapper.props('format')).toBe(display)
|
|
3301
|
+
expect(wrapper.props('dateFormatReturn')).toBe(returnFormat)
|
|
3302
|
+
})
|
|
3303
|
+
})
|
|
3304
|
+
|
|
3305
|
+
it('doit gérer le mode avec TextFieldActivator et formats différents', async () => {
|
|
3306
|
+
wrapper = mount(DatePicker, {
|
|
3307
|
+
global: {
|
|
3308
|
+
plugins: [vuetify],
|
|
3309
|
+
},
|
|
3310
|
+
props: {
|
|
3311
|
+
useCombinedMode: true,
|
|
3312
|
+
modelValue: null,
|
|
3313
|
+
label: 'Mode TextFieldActivator formats',
|
|
3314
|
+
format: 'DD/MM/YYYY',
|
|
3315
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
3316
|
+
textFieldActivator: true,
|
|
3317
|
+
},
|
|
3318
|
+
})
|
|
3319
|
+
|
|
3320
|
+
await nextTick()
|
|
3321
|
+
|
|
3322
|
+
expect(wrapper.exists()).toBe(true)
|
|
3323
|
+
expect(wrapper.props('textFieldActivator')).toBe(true)
|
|
3324
|
+
expect(wrapper.props('format')).toBe('DD/MM/YYYY')
|
|
3325
|
+
expect(wrapper.props('dateFormatReturn')).toBe('YYYY-MM-DD')
|
|
3326
|
+
})
|
|
3327
|
+
|
|
3328
|
+
it('doit gérer les plages avec TextFieldActivator et formats différents', async () => {
|
|
3329
|
+
wrapper = mount(DatePicker, {
|
|
3330
|
+
global: {
|
|
3331
|
+
plugins: [vuetify],
|
|
3332
|
+
},
|
|
3333
|
+
props: {
|
|
3334
|
+
useCombinedMode: true,
|
|
3335
|
+
modelValue: null,
|
|
3336
|
+
label: 'Plage TextFieldActivator',
|
|
3337
|
+
format: 'MM/DD/YYYY',
|
|
3338
|
+
dateFormatReturn: 'DD-MM-YYYY',
|
|
3339
|
+
displayRange: true,
|
|
3340
|
+
textFieldActivator: true,
|
|
3341
|
+
},
|
|
3342
|
+
})
|
|
3343
|
+
|
|
3344
|
+
await nextTick()
|
|
3345
|
+
|
|
3346
|
+
expect(wrapper.exists()).toBe(true)
|
|
3347
|
+
expect(wrapper.props('textFieldActivator')).toBe(true)
|
|
3348
|
+
expect(wrapper.props('displayRange')).toBe(true)
|
|
3349
|
+
})
|
|
3350
|
+
|
|
3351
|
+
it('doit valider avec des règles et formats différents', async () => {
|
|
3352
|
+
wrapper = mount(DatePicker, {
|
|
3353
|
+
global: {
|
|
3354
|
+
plugins: [vuetify],
|
|
3355
|
+
},
|
|
3356
|
+
props: {
|
|
3357
|
+
useCombinedMode: true,
|
|
3358
|
+
modelValue: '15/06/2024',
|
|
3359
|
+
label: 'Validation formats différents',
|
|
3360
|
+
format: 'DD/MM/YYYY',
|
|
3361
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
3362
|
+
customRules: [
|
|
3363
|
+
{
|
|
3364
|
+
type: 'notBeforeDate',
|
|
3365
|
+
options: {
|
|
3366
|
+
date: '10/06/2024', // Format d'affichage
|
|
3367
|
+
message: 'Date trop ancienne',
|
|
3368
|
+
},
|
|
3369
|
+
},
|
|
3370
|
+
],
|
|
3371
|
+
},
|
|
3372
|
+
})
|
|
3373
|
+
|
|
3374
|
+
await nextTick()
|
|
3375
|
+
|
|
3376
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
3377
|
+
expect(result).toBe(true) // 15/06 > 10/06
|
|
3378
|
+
})
|
|
3379
|
+
})
|
|
3380
|
+
|
|
3381
|
+
describe('Tests DatePicker - Formats d\'entrée et sortie', () => {
|
|
3382
|
+
const textInputFormats = [
|
|
3383
|
+
{ display: 'DD/MM/YYYY', return: 'YYYY-MM-DD', mask: '##/##/####' },
|
|
3384
|
+
{ display: 'MM/DD/YYYY', return: 'DD/MM/YYYY', mask: '##/##/####' },
|
|
3385
|
+
{ display: 'DD-MM-YYYY', return: 'MM-DD-YYYY', mask: '##-##-####' },
|
|
3386
|
+
{ display: 'YYYY/MM/DD', return: 'DD/MM/YYYY', mask: '####/##/##' },
|
|
3387
|
+
{ display: 'DD.MM.YY', return: 'YYYY-MM-DD', mask: '##.##.##' },
|
|
3388
|
+
]
|
|
3389
|
+
|
|
3390
|
+
textInputFormats.forEach(({ display, return: returnFormat }) => {
|
|
3391
|
+
it(`doit gérer la saisie avec format ${display} et retour ${returnFormat}`, async () => {
|
|
3392
|
+
wrapper = mount(DatePicker, {
|
|
3393
|
+
global: {
|
|
3394
|
+
plugins: [vuetify],
|
|
3395
|
+
},
|
|
3396
|
+
props: {
|
|
3397
|
+
modelValue: null,
|
|
3398
|
+
label: `Saisie ${display}`,
|
|
3399
|
+
format: display,
|
|
3400
|
+
dateFormatReturn: returnFormat,
|
|
3401
|
+
},
|
|
3402
|
+
})
|
|
3403
|
+
|
|
3404
|
+
await nextTick()
|
|
3405
|
+
|
|
3406
|
+
const input = wrapper.find('input')
|
|
3407
|
+
expect(input.exists()).toBe(true)
|
|
3408
|
+
expect(wrapper.props('format')).toBe(display)
|
|
3409
|
+
expect(wrapper.props('dateFormatReturn')).toBe(returnFormat)
|
|
3410
|
+
})
|
|
3411
|
+
})
|
|
3412
|
+
|
|
3413
|
+
it('doit gérer la saisie de plages avec formats différents', async () => {
|
|
3414
|
+
wrapper = mount(DatePicker, {
|
|
3415
|
+
global: {
|
|
3416
|
+
plugins: [vuetify],
|
|
3417
|
+
},
|
|
3418
|
+
props: {
|
|
3419
|
+
modelValue: null,
|
|
3420
|
+
label: 'Plage DatePicker',
|
|
3421
|
+
format: 'DD/MM/YYYY',
|
|
3422
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
3423
|
+
displayRange: true,
|
|
3424
|
+
},
|
|
3425
|
+
})
|
|
3426
|
+
|
|
3427
|
+
await nextTick()
|
|
3428
|
+
|
|
3429
|
+
const input = wrapper.find('input')
|
|
3430
|
+
expect(input.exists()).toBe(true)
|
|
3431
|
+
expect(wrapper.props('displayRange')).toBe(true)
|
|
3432
|
+
|
|
3433
|
+
// Tester la saisie d'une plage
|
|
3434
|
+
await input.setValue('15/06/2024 - 20/06/2024')
|
|
3435
|
+
await input.trigger('blur')
|
|
3436
|
+
|
|
3437
|
+
expect(wrapper.exists()).toBe(true)
|
|
3438
|
+
})
|
|
3439
|
+
|
|
3440
|
+
it('doit gérer les formats avec validation en temps réel', async () => {
|
|
3441
|
+
wrapper = mount(DatePicker, {
|
|
3442
|
+
global: {
|
|
3443
|
+
plugins: [vuetify],
|
|
3444
|
+
},
|
|
3445
|
+
props: {
|
|
3446
|
+
modelValue: null,
|
|
3447
|
+
label: 'Validation temps réel',
|
|
3448
|
+
format: 'MM/DD/YYYY',
|
|
3449
|
+
dateFormatReturn: 'DD-MM-YYYY',
|
|
3450
|
+
customRules: [
|
|
3451
|
+
{
|
|
3452
|
+
type: 'notAfterToday',
|
|
3453
|
+
options: {
|
|
3454
|
+
message: 'Date ne peut pas être future',
|
|
3455
|
+
},
|
|
3456
|
+
},
|
|
3457
|
+
],
|
|
3458
|
+
},
|
|
3459
|
+
})
|
|
3460
|
+
|
|
3461
|
+
await nextTick()
|
|
3462
|
+
|
|
3463
|
+
const input = wrapper.find('input')
|
|
3464
|
+
await input.setValue('12/15/2024')
|
|
3465
|
+
await input.trigger('input')
|
|
3466
|
+
await input.trigger('blur')
|
|
3467
|
+
|
|
3468
|
+
expect(wrapper.exists()).toBe(true)
|
|
3469
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
3470
|
+
expect(typeof result).toBe('boolean')
|
|
3471
|
+
})
|
|
3472
|
+
|
|
3473
|
+
it('doit gérer les formats courts avec années à 2 chiffres', async () => {
|
|
3474
|
+
wrapper = mount(DatePicker, {
|
|
3475
|
+
global: {
|
|
3476
|
+
plugins: [vuetify],
|
|
3477
|
+
},
|
|
3478
|
+
props: {
|
|
3479
|
+
modelValue: null,
|
|
3480
|
+
label: 'Format court YY',
|
|
3481
|
+
format: 'DD/MM/YY',
|
|
3482
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
3483
|
+
},
|
|
3484
|
+
})
|
|
3485
|
+
|
|
3486
|
+
await nextTick()
|
|
3487
|
+
|
|
3488
|
+
const input = wrapper.find('input')
|
|
3489
|
+
await input.setValue('15/06/24')
|
|
3490
|
+
await input.trigger('blur')
|
|
3491
|
+
|
|
3492
|
+
expect(wrapper.exists()).toBe(true)
|
|
3493
|
+
expect(wrapper.props('format')).toBe('DD/MM/YY')
|
|
3494
|
+
})
|
|
3495
|
+
})
|
|
3496
|
+
|
|
3497
|
+
describe('Tests de conversion et cohérence entre formats', () => {
|
|
3498
|
+
it('doit maintenir la cohérence lors du changement de format à la volée - CalendarMode', async () => {
|
|
3499
|
+
wrapper = mount(DatePicker, {
|
|
3500
|
+
global: {
|
|
3501
|
+
plugins: [vuetify],
|
|
3502
|
+
},
|
|
3503
|
+
props: {
|
|
3504
|
+
modelValue: '15/06/2024',
|
|
3505
|
+
label: 'Changement format dynamique',
|
|
3506
|
+
format: 'DD/MM/YYYY',
|
|
3507
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
3508
|
+
},
|
|
3509
|
+
})
|
|
3510
|
+
|
|
3511
|
+
await nextTick()
|
|
3512
|
+
|
|
3513
|
+
// Changer le format d'affichage
|
|
3514
|
+
await wrapper.setProps({ format: 'MM/DD/YYYY' })
|
|
3515
|
+
await nextTick()
|
|
3516
|
+
|
|
3517
|
+
// Changer le format de retour
|
|
3518
|
+
await wrapper.setProps({ dateFormatReturn: 'DD-MM-YYYY' })
|
|
3519
|
+
await nextTick()
|
|
3520
|
+
|
|
3521
|
+
expect(wrapper.exists()).toBe(true)
|
|
3522
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
3523
|
+
expect(typeof result).toBe('boolean')
|
|
3524
|
+
})
|
|
3525
|
+
|
|
3526
|
+
it('doit gérer les conversions complexes avec validation - DatePicker', async () => {
|
|
3527
|
+
wrapper = mount(DatePicker, {
|
|
3528
|
+
global: {
|
|
3529
|
+
plugins: [vuetify],
|
|
3530
|
+
},
|
|
3531
|
+
props: {
|
|
3532
|
+
useCombinedMode: true,
|
|
3533
|
+
modelValue: '2024-06-15', // Format ISO en entrée
|
|
3534
|
+
label: 'Conversion complexe',
|
|
3535
|
+
format: 'DD/MM/YYYY', // Affichage français
|
|
3536
|
+
dateFormatReturn: 'MM-DD-YYYY', // Retour US
|
|
3537
|
+
customRules: [
|
|
3538
|
+
{
|
|
3539
|
+
type: 'dateExact',
|
|
3540
|
+
options: {
|
|
3541
|
+
date: '15/06/2024', // Date en format d'affichage
|
|
3542
|
+
message: 'Date doit être exactement le 15/06/2024',
|
|
3543
|
+
},
|
|
3544
|
+
},
|
|
3545
|
+
],
|
|
3546
|
+
},
|
|
3547
|
+
})
|
|
3548
|
+
|
|
3549
|
+
await nextTick()
|
|
3550
|
+
|
|
3551
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
3552
|
+
expect(result).toBe(true) // Doit réussir car dates identiques
|
|
3553
|
+
})
|
|
3554
|
+
|
|
3555
|
+
it('doit gérer les erreurs de format invalide - DatePicker', async () => {
|
|
3556
|
+
wrapper = mount(DatePicker, {
|
|
3557
|
+
global: {
|
|
3558
|
+
plugins: [vuetify],
|
|
3559
|
+
},
|
|
3560
|
+
props: {
|
|
3561
|
+
modelValue: null,
|
|
3562
|
+
label: 'Test format invalide',
|
|
3563
|
+
format: 'DD/MM/YYYY',
|
|
3564
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
3565
|
+
},
|
|
3566
|
+
})
|
|
3567
|
+
|
|
3568
|
+
await nextTick()
|
|
3569
|
+
|
|
3570
|
+
const input = wrapper.find('input')
|
|
3571
|
+
|
|
3572
|
+
// Saisir un format invalide
|
|
3573
|
+
await input.setValue('32/13/2024') // Jour et mois invalides
|
|
3574
|
+
await input.trigger('blur')
|
|
3575
|
+
|
|
3576
|
+
expect(wrapper.exists()).toBe(true)
|
|
3577
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
3578
|
+
expect(typeof result).toBe('boolean')
|
|
3579
|
+
})
|
|
3580
|
+
|
|
3581
|
+
it('doit gérer les plages avec formats mixtes - Tous les modes', async () => {
|
|
3582
|
+
const modes = [
|
|
3583
|
+
{ component: DatePicker, name: 'CalendarMode' },
|
|
3584
|
+
{ component: DatePicker, name: 'DatePicker' },
|
|
3585
|
+
{ component: DatePicker, name: 'DatePicker' },
|
|
3586
|
+
]
|
|
3587
|
+
|
|
3588
|
+
for (const mode of modes) {
|
|
3589
|
+
const testWrapper = mount(mode.component, {
|
|
3590
|
+
global: {
|
|
3591
|
+
plugins: [vuetify],
|
|
3592
|
+
},
|
|
3593
|
+
props: {
|
|
3594
|
+
modelValue: null,
|
|
3595
|
+
label: `Plage formats mixtes ${mode.name}`,
|
|
3596
|
+
format: 'DD/MM/YYYY',
|
|
3597
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
3598
|
+
displayRange: true,
|
|
3599
|
+
},
|
|
3600
|
+
})
|
|
3601
|
+
|
|
3602
|
+
await nextTick()
|
|
3603
|
+
|
|
3604
|
+
expect(testWrapper.exists()).toBe(true)
|
|
3605
|
+
expect(testWrapper.props('displayRange')).toBe(true)
|
|
3606
|
+
|
|
3607
|
+
testWrapper.unmount()
|
|
3608
|
+
}
|
|
3609
|
+
})
|
|
3610
|
+
})
|
|
3611
|
+
|
|
3612
|
+
describe('Tests de edge cases avec formats spéciaux', () => {
|
|
3613
|
+
it('doit gérer les formats avec caractères spéciaux', async () => {
|
|
3614
|
+
const specialFormats = [
|
|
3615
|
+
'DD|MM|YYYY',
|
|
3616
|
+
'DD\\MM\\YYYY',
|
|
3617
|
+
'DD MM YYYY',
|
|
3618
|
+
'DD_MM_YYYY',
|
|
3619
|
+
]
|
|
3620
|
+
|
|
3621
|
+
for (const format of specialFormats) {
|
|
3622
|
+
wrapper = mount(DatePicker, {
|
|
3623
|
+
global: {
|
|
3624
|
+
plugins: [vuetify],
|
|
3625
|
+
},
|
|
3626
|
+
props: {
|
|
3627
|
+
useCombinedMode: true,
|
|
3628
|
+
modelValue: null,
|
|
3629
|
+
label: `Format spécial ${format}`,
|
|
3630
|
+
format: format,
|
|
3631
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
3632
|
+
},
|
|
3633
|
+
})
|
|
3634
|
+
|
|
3635
|
+
await nextTick()
|
|
3636
|
+
|
|
3637
|
+
expect(wrapper.exists()).toBe(true)
|
|
3638
|
+
expect(wrapper.props('format')).toBe(format)
|
|
3639
|
+
|
|
3640
|
+
wrapper.unmount()
|
|
3641
|
+
}
|
|
3642
|
+
})
|
|
3643
|
+
|
|
3644
|
+
it('doit gérer les formats avec ordres non-standards', async () => {
|
|
3645
|
+
const nonStandardFormats = [
|
|
3646
|
+
{ format: 'YYYY/DD/MM', description: 'Année/Jour/Mois' },
|
|
3647
|
+
{ format: 'MM/YYYY/DD', description: 'Mois/Année/Jour' },
|
|
3648
|
+
{ format: 'DD/YYYY/MM', description: 'Jour/Année/Mois' },
|
|
3649
|
+
]
|
|
3650
|
+
|
|
3651
|
+
for (const { format, description } of nonStandardFormats) {
|
|
3652
|
+
wrapper = mount(DatePicker, {
|
|
3653
|
+
global: {
|
|
3654
|
+
plugins: [vuetify],
|
|
3655
|
+
},
|
|
3656
|
+
props: {
|
|
3657
|
+
modelValue: null,
|
|
3658
|
+
label: description,
|
|
3659
|
+
format: format,
|
|
3660
|
+
dateFormatReturn: 'DD/MM/YYYY',
|
|
3661
|
+
},
|
|
3662
|
+
})
|
|
3663
|
+
|
|
3664
|
+
await nextTick()
|
|
3665
|
+
|
|
3666
|
+
expect(wrapper.exists()).toBe(true)
|
|
3667
|
+
expect(wrapper.props('format')).toBe(format)
|
|
3668
|
+
|
|
3669
|
+
wrapper.unmount()
|
|
3670
|
+
}
|
|
3671
|
+
})
|
|
3672
|
+
|
|
3673
|
+
it('doit gérer les formats avec précision différente', async () => {
|
|
3674
|
+
const precisionFormats = [
|
|
3675
|
+
{ format: 'DD/MM/YYYY HH:mm', return: 'YYYY-MM-DD', description: 'Avec heures/minutes' },
|
|
3676
|
+
{ format: 'DD/MM/YYYY HH:mm:ss', return: 'YYYY-MM-DD HH:mm:ss', description: 'Avec secondes' },
|
|
3677
|
+
{ format: 'DD/MM', return: 'MM/DD', description: 'Sans année' },
|
|
3678
|
+
]
|
|
3679
|
+
|
|
3680
|
+
for (const { format, return: returnFormat, description } of precisionFormats) {
|
|
3681
|
+
wrapper = mount(DatePicker, {
|
|
3682
|
+
global: {
|
|
3683
|
+
plugins: [vuetify],
|
|
3684
|
+
},
|
|
3685
|
+
props: {
|
|
3686
|
+
modelValue: null,
|
|
3687
|
+
label: description,
|
|
3688
|
+
format: format,
|
|
3689
|
+
dateFormatReturn: returnFormat,
|
|
3690
|
+
},
|
|
3691
|
+
})
|
|
3692
|
+
|
|
3693
|
+
await nextTick()
|
|
3694
|
+
|
|
3695
|
+
expect(wrapper.exists()).toBe(true)
|
|
3696
|
+
expect(wrapper.props('format')).toBe(format)
|
|
3697
|
+
expect(wrapper.props('dateFormatReturn')).toBe(returnFormat)
|
|
3698
|
+
|
|
3699
|
+
wrapper.unmount()
|
|
3700
|
+
}
|
|
3701
|
+
})
|
|
3702
|
+
})
|
|
3703
|
+
})
|
|
3704
|
+
|
|
3705
|
+
/**
|
|
3706
|
+
* TESTS DES ÉVÉNEMENTS (EVENTS) - TOUS LES MODES
|
|
3707
|
+
*/
|
|
3708
|
+
describe('Tests des Événements (Events)', () => {
|
|
3709
|
+
describe('Tests des événements CalendarMode', () => {
|
|
3710
|
+
it('doit émettre update:modelValue lors de la sélection d\'une date', async () => {
|
|
3711
|
+
wrapper = mount(DatePicker, {
|
|
3712
|
+
global: {
|
|
3713
|
+
plugins: [vuetify],
|
|
3714
|
+
},
|
|
3715
|
+
props: {
|
|
3716
|
+
modelValue: null,
|
|
3717
|
+
label: 'Test événement update:modelValue',
|
|
3718
|
+
},
|
|
3719
|
+
})
|
|
3720
|
+
|
|
3721
|
+
await nextTick()
|
|
3722
|
+
|
|
3723
|
+
// Vérifier que le composant est monté et peut émettre des événements
|
|
3724
|
+
expect(wrapper.exists()).toBe(true)
|
|
3725
|
+
expect(wrapper.props('modelValue')).toBe(null)
|
|
3726
|
+
|
|
3727
|
+
// Simuler la sélection d'une date via l'API du composant
|
|
3728
|
+
await wrapper.setProps({ modelValue: '15/06/2024' })
|
|
3729
|
+
await nextTick()
|
|
3730
|
+
|
|
3731
|
+
// Le composant doit exister et avoir la bonne valeur
|
|
3732
|
+
expect(wrapper.props('modelValue')).toBe('15/06/2024')
|
|
3733
|
+
})
|
|
3734
|
+
|
|
3735
|
+
it('doit émettre focus lors du focus sur l\'input', async () => {
|
|
3736
|
+
wrapper = mount(DatePicker, {
|
|
3737
|
+
global: {
|
|
3738
|
+
plugins: [vuetify],
|
|
3739
|
+
},
|
|
3740
|
+
props: {
|
|
3741
|
+
modelValue: null,
|
|
3742
|
+
label: 'Test événement focus',
|
|
3743
|
+
},
|
|
3744
|
+
})
|
|
3745
|
+
|
|
3746
|
+
await nextTick()
|
|
3747
|
+
|
|
3748
|
+
// Simuler le focus
|
|
3749
|
+
wrapper.vm.$emit('focus')
|
|
3750
|
+
await nextTick()
|
|
3751
|
+
|
|
3752
|
+
expect(wrapper.emitted('focus')).toBeTruthy()
|
|
3753
|
+
})
|
|
3754
|
+
|
|
3755
|
+
it('doit émettre blur lors de la perte de focus', async () => {
|
|
3756
|
+
wrapper = mount(DatePicker, {
|
|
3757
|
+
global: {
|
|
3758
|
+
plugins: [vuetify],
|
|
3759
|
+
},
|
|
3760
|
+
props: {
|
|
3761
|
+
modelValue: null,
|
|
3762
|
+
label: 'Test événement blur',
|
|
3763
|
+
},
|
|
3764
|
+
})
|
|
3765
|
+
|
|
3766
|
+
await nextTick()
|
|
3767
|
+
|
|
3768
|
+
// Simuler le blur
|
|
3769
|
+
wrapper.vm.$emit('blur')
|
|
3770
|
+
await nextTick()
|
|
3771
|
+
|
|
3772
|
+
expect(wrapper.emitted('blur')).toBeTruthy()
|
|
3773
|
+
})
|
|
3774
|
+
|
|
3775
|
+
it('doit émettre date-selected avec la bonne valeur', async () => {
|
|
3776
|
+
wrapper = mount(DatePicker, {
|
|
3777
|
+
global: {
|
|
3778
|
+
plugins: [vuetify],
|
|
3779
|
+
},
|
|
3780
|
+
props: {
|
|
3781
|
+
modelValue: null,
|
|
3782
|
+
label: 'Test événement date-selected',
|
|
3783
|
+
format: 'DD/MM/YYYY',
|
|
3784
|
+
},
|
|
3785
|
+
})
|
|
3786
|
+
|
|
3787
|
+
await nextTick()
|
|
3788
|
+
|
|
3789
|
+
// Simuler la sélection d'une date
|
|
3790
|
+
wrapper.vm.$emit('date-selected', '15/06/2024')
|
|
3791
|
+
await nextTick()
|
|
3792
|
+
|
|
3793
|
+
expect(wrapper.emitted('date-selected')).toBeTruthy()
|
|
3794
|
+
expect(wrapper.emitted('date-selected')[0]).toEqual(['15/06/2024'])
|
|
3795
|
+
})
|
|
3796
|
+
})
|
|
3797
|
+
|
|
3798
|
+
describe('Tests des événements DatePicker', () => {
|
|
3799
|
+
it('doit émettre update:modelValue avec le bon format', async () => {
|
|
3800
|
+
wrapper = mount(DatePicker, {
|
|
3801
|
+
global: {
|
|
3802
|
+
plugins: [vuetify],
|
|
3803
|
+
},
|
|
3804
|
+
props: {
|
|
3805
|
+
useCombinedMode: true,
|
|
3806
|
+
modelValue: null,
|
|
3807
|
+
label: 'Test événement DatePicker',
|
|
3808
|
+
format: 'DD/MM/YYYY',
|
|
3809
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
3810
|
+
},
|
|
3811
|
+
})
|
|
3812
|
+
|
|
3813
|
+
await nextTick()
|
|
3814
|
+
|
|
3815
|
+
// Simuler la sélection
|
|
3816
|
+
await wrapper.setProps({ modelValue: '15/06/2024' })
|
|
3817
|
+
await nextTick()
|
|
3818
|
+
|
|
3819
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy()
|
|
3820
|
+
})
|
|
3821
|
+
|
|
3822
|
+
it('doit émettre closed lors de la fermeture du calendrier', async () => {
|
|
3823
|
+
wrapper = mount(DatePicker, {
|
|
3824
|
+
global: {
|
|
3825
|
+
plugins: [vuetify],
|
|
3826
|
+
},
|
|
3827
|
+
props: {
|
|
3828
|
+
useCombinedMode: true,
|
|
3829
|
+
modelValue: null,
|
|
3830
|
+
label: 'Test événement closed',
|
|
3831
|
+
},
|
|
3832
|
+
})
|
|
3833
|
+
|
|
3834
|
+
await nextTick()
|
|
3835
|
+
|
|
3836
|
+
// Simuler la fermeture
|
|
3837
|
+
wrapper.vm.$emit('closed')
|
|
3838
|
+
await nextTick()
|
|
3839
|
+
|
|
3840
|
+
expect(wrapper.emitted('closed')).toBeTruthy()
|
|
3841
|
+
})
|
|
3842
|
+
|
|
3843
|
+
it('doit émettre les événements dans le bon ordre', async () => {
|
|
3844
|
+
wrapper = mount(DatePicker, {
|
|
3845
|
+
global: {
|
|
3846
|
+
plugins: [vuetify],
|
|
3847
|
+
},
|
|
3848
|
+
props: {
|
|
3849
|
+
useCombinedMode: true,
|
|
3850
|
+
modelValue: null,
|
|
3851
|
+
label: 'Test ordre événements',
|
|
3852
|
+
},
|
|
3853
|
+
})
|
|
3854
|
+
|
|
3855
|
+
await nextTick()
|
|
3856
|
+
|
|
3857
|
+
// Simuler une séquence d'événements
|
|
3858
|
+
wrapper.vm.$emit('focus')
|
|
3859
|
+
wrapper.vm.$emit('date-selected', '15/06/2024')
|
|
3860
|
+
wrapper.vm.$emit('update:modelValue', '15/06/2024')
|
|
3861
|
+
wrapper.vm.$emit('blur')
|
|
3862
|
+
await nextTick()
|
|
3863
|
+
|
|
3864
|
+
expect(wrapper.emitted('focus')).toBeTruthy()
|
|
3865
|
+
expect(wrapper.emitted('date-selected')).toBeTruthy()
|
|
3866
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy()
|
|
3867
|
+
expect(wrapper.emitted('blur')).toBeTruthy()
|
|
3868
|
+
})
|
|
3869
|
+
})
|
|
3870
|
+
|
|
3871
|
+
describe('Tests des événements DatePicker', () => {
|
|
3872
|
+
it('doit émettre update:model-value lors de la saisie', async () => {
|
|
3873
|
+
wrapper = mount(DatePicker, {
|
|
3874
|
+
global: {
|
|
3875
|
+
plugins: [vuetify],
|
|
3876
|
+
},
|
|
3877
|
+
props: {
|
|
3878
|
+
modelValue: null,
|
|
3879
|
+
label: 'Test événement DatePicker',
|
|
3880
|
+
},
|
|
3881
|
+
})
|
|
3882
|
+
|
|
3883
|
+
await nextTick()
|
|
3884
|
+
|
|
3885
|
+
const input = wrapper.find('input')
|
|
3886
|
+
await input.setValue('15/06/2024')
|
|
3887
|
+
await input.trigger('blur')
|
|
3888
|
+
|
|
3889
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy()
|
|
3890
|
+
})
|
|
3891
|
+
|
|
3892
|
+
it('doit émettre input lors de la frappe', async () => {
|
|
3893
|
+
wrapper = mount(DatePicker, {
|
|
3894
|
+
global: {
|
|
3895
|
+
plugins: [vuetify],
|
|
3896
|
+
},
|
|
3897
|
+
props: {
|
|
3898
|
+
modelValue: null,
|
|
3899
|
+
label: 'Test événement input',
|
|
3900
|
+
},
|
|
3901
|
+
})
|
|
3902
|
+
|
|
3903
|
+
await nextTick()
|
|
3904
|
+
|
|
3905
|
+
const input = wrapper.find('input')
|
|
3906
|
+
expect(input.exists()).toBe(true)
|
|
3907
|
+
|
|
3908
|
+
await input.setValue('15')
|
|
3909
|
+
await input.trigger('input')
|
|
3910
|
+
|
|
3911
|
+
// Vérifier que l'input a bien la valeur
|
|
3912
|
+
expect(input.element.value).toContain('15')
|
|
3913
|
+
})
|
|
3914
|
+
|
|
3915
|
+
it('doit émettre focus et blur dans le bon ordre', async () => {
|
|
3916
|
+
wrapper = mount(DatePicker, {
|
|
3917
|
+
global: {
|
|
3918
|
+
plugins: [vuetify],
|
|
3919
|
+
},
|
|
3920
|
+
props: {
|
|
3921
|
+
modelValue: null,
|
|
3922
|
+
label: 'Test focus/blur ordre',
|
|
3923
|
+
},
|
|
3924
|
+
})
|
|
3925
|
+
|
|
3926
|
+
await nextTick()
|
|
3927
|
+
|
|
3928
|
+
const input = wrapper.find('input')
|
|
3929
|
+
await input.trigger('focus')
|
|
3930
|
+
await input.trigger('blur')
|
|
3931
|
+
|
|
3932
|
+
expect(wrapper.emitted('focus')).toBeTruthy()
|
|
3933
|
+
expect(wrapper.emitted('blur')).toBeTruthy()
|
|
3934
|
+
})
|
|
3935
|
+
})
|
|
3936
|
+
})
|
|
3937
|
+
|
|
3938
|
+
/**
|
|
3939
|
+
* TESTS D'ACCESSIBILITÉ (A11Y)
|
|
3940
|
+
*/
|
|
3941
|
+
describe('Tests d\'Accessibilité (A11y)', () => {
|
|
3942
|
+
describe('Tests de navigation au clavier', () => {
|
|
3943
|
+
it('doit gérer la navigation au clavier dans DatePicker', async () => {
|
|
3944
|
+
wrapper = mount(DatePicker, {
|
|
3945
|
+
global: {
|
|
3946
|
+
plugins: [vuetify],
|
|
3947
|
+
},
|
|
3948
|
+
props: {
|
|
3949
|
+
modelValue: null,
|
|
3950
|
+
label: 'Test navigation clavier',
|
|
3951
|
+
format: 'DD/MM/YYYY',
|
|
3952
|
+
},
|
|
3953
|
+
})
|
|
3954
|
+
|
|
3955
|
+
await nextTick()
|
|
3956
|
+
|
|
3957
|
+
const input = wrapper.find('input')
|
|
3958
|
+
|
|
3959
|
+
// Test des touches de navigation
|
|
3960
|
+
await input.trigger('keydown', { key: 'ArrowLeft' })
|
|
3961
|
+
await input.trigger('keydown', { key: 'ArrowRight' })
|
|
3962
|
+
await input.trigger('keydown', { key: 'Home' })
|
|
3963
|
+
await input.trigger('keydown', { key: 'End' })
|
|
3964
|
+
await input.trigger('keydown', { key: 'Tab' })
|
|
3965
|
+
|
|
3966
|
+
expect(wrapper.exists()).toBe(true)
|
|
3967
|
+
})
|
|
3968
|
+
|
|
3969
|
+
it('doit gérer la saisie de chiffres au clavier', async () => {
|
|
3970
|
+
wrapper = mount(DatePicker, {
|
|
3971
|
+
global: {
|
|
3972
|
+
plugins: [vuetify],
|
|
3973
|
+
},
|
|
3974
|
+
props: {
|
|
3975
|
+
modelValue: null,
|
|
3976
|
+
label: 'Test saisie chiffres',
|
|
3977
|
+
format: 'DD/MM/YYYY',
|
|
3978
|
+
},
|
|
3979
|
+
})
|
|
3980
|
+
|
|
3981
|
+
await nextTick()
|
|
3982
|
+
|
|
3983
|
+
const input = wrapper.find('input')
|
|
3984
|
+
|
|
3985
|
+
// Test de saisie de chiffres
|
|
3986
|
+
await input.trigger('keydown', { key: '1' })
|
|
3987
|
+
await input.trigger('keydown', { key: '5' })
|
|
3988
|
+
await input.trigger('keydown', { key: '0' })
|
|
3989
|
+
await input.trigger('keydown', { key: '6' })
|
|
3990
|
+
|
|
3991
|
+
expect(wrapper.exists()).toBe(true)
|
|
3992
|
+
})
|
|
3993
|
+
|
|
3994
|
+
it('doit gérer la touche Backspace', async () => {
|
|
3995
|
+
wrapper = mount(DatePicker, {
|
|
3996
|
+
global: {
|
|
3997
|
+
plugins: [vuetify],
|
|
3998
|
+
},
|
|
3999
|
+
props: {
|
|
4000
|
+
modelValue: '15/06/2024',
|
|
4001
|
+
label: 'Test Backspace',
|
|
4002
|
+
format: 'DD/MM/YYYY',
|
|
4003
|
+
},
|
|
4004
|
+
})
|
|
4005
|
+
|
|
4006
|
+
await nextTick()
|
|
4007
|
+
|
|
4008
|
+
const input = wrapper.find('input')
|
|
4009
|
+
await input.trigger('keydown', { key: 'Backspace' })
|
|
4010
|
+
|
|
4011
|
+
expect(wrapper.exists()).toBe(true)
|
|
4012
|
+
})
|
|
4013
|
+
})
|
|
4014
|
+
|
|
4015
|
+
describe('Tests de focus management', () => {
|
|
4016
|
+
it('doit émettre les événements focus et blur - DatePicker', async () => {
|
|
4017
|
+
wrapper = mount(DatePicker, {
|
|
4018
|
+
global: {
|
|
4019
|
+
plugins: [vuetify],
|
|
4020
|
+
},
|
|
4021
|
+
props: {
|
|
4022
|
+
noCalendar: true,
|
|
4023
|
+
modelValue: null,
|
|
4024
|
+
label: 'Test focus methods',
|
|
4025
|
+
},
|
|
4026
|
+
})
|
|
4027
|
+
|
|
4028
|
+
await nextTick()
|
|
4029
|
+
|
|
4030
|
+
const input = wrapper.find('input')
|
|
4031
|
+
|
|
4032
|
+
// Tester l'événement focus
|
|
4033
|
+
await input.trigger('focus')
|
|
4034
|
+
expect(wrapper.emitted('focus')).toBeTruthy()
|
|
4035
|
+
|
|
4036
|
+
// Tester l'événement blur
|
|
4037
|
+
await input.trigger('blur')
|
|
4038
|
+
expect(wrapper.emitted('blur')).toBeTruthy()
|
|
4039
|
+
|
|
4040
|
+
expect(wrapper.exists()).toBe(true)
|
|
4041
|
+
})
|
|
4042
|
+
|
|
4043
|
+
it('doit gérer le focus initial correctement', async () => {
|
|
4044
|
+
wrapper = mount(DatePicker, {
|
|
4045
|
+
global: {
|
|
4046
|
+
plugins: [vuetify],
|
|
4047
|
+
},
|
|
4048
|
+
props: {
|
|
4049
|
+
useCombinedMode: true,
|
|
4050
|
+
modelValue: null,
|
|
4051
|
+
label: 'Test focus initial',
|
|
4052
|
+
autofocus: true,
|
|
4053
|
+
},
|
|
4054
|
+
})
|
|
4055
|
+
|
|
4056
|
+
await nextTick()
|
|
4057
|
+
|
|
4058
|
+
expect(wrapper.exists()).toBe(true)
|
|
4059
|
+
})
|
|
4060
|
+
})
|
|
4061
|
+
|
|
4062
|
+
describe('Tests des attributs ARIA et rôles', () => {
|
|
4063
|
+
it('doit avoir les bons attributs ARIA - CalendarMode', async () => {
|
|
4064
|
+
wrapper = mount(DatePicker, {
|
|
4065
|
+
global: {
|
|
4066
|
+
plugins: [vuetify],
|
|
4067
|
+
},
|
|
4068
|
+
props: {
|
|
4069
|
+
modelValue: null,
|
|
4070
|
+
label: 'Test ARIA',
|
|
4071
|
+
required: true,
|
|
4072
|
+
},
|
|
4073
|
+
})
|
|
4074
|
+
|
|
4075
|
+
await nextTick()
|
|
4076
|
+
|
|
4077
|
+
const input = wrapper.find('input')
|
|
4078
|
+
if (input.exists()) {
|
|
4079
|
+
expect(input.attributes()).toBeDefined()
|
|
4080
|
+
}
|
|
4081
|
+
expect(wrapper.exists()).toBe(true)
|
|
4082
|
+
})
|
|
4083
|
+
|
|
4084
|
+
it('doit supporter les labels et descriptions', async () => {
|
|
4085
|
+
wrapper = mount(DatePicker, {
|
|
4086
|
+
global: {
|
|
4087
|
+
plugins: [vuetify],
|
|
4088
|
+
},
|
|
4089
|
+
props: {
|
|
4090
|
+
modelValue: null,
|
|
4091
|
+
label: 'Date de naissance',
|
|
4092
|
+
required: true,
|
|
4093
|
+
},
|
|
4094
|
+
})
|
|
4095
|
+
|
|
4096
|
+
await nextTick()
|
|
4097
|
+
|
|
4098
|
+
expect(wrapper.props('label')).toBe('Date de naissance')
|
|
4099
|
+
expect(wrapper.props('required')).toBe(true)
|
|
4100
|
+
expect(wrapper.exists()).toBe(true)
|
|
4101
|
+
})
|
|
4102
|
+
})
|
|
4103
|
+
})
|
|
4104
|
+
|
|
4105
|
+
/**
|
|
4106
|
+
* TESTS DES ÉTATS D'ERREUR/WARNING/SUCCESS
|
|
4107
|
+
*/
|
|
4108
|
+
describe('Tests des États de Validation', () => {
|
|
4109
|
+
describe('Tests des messages d\'erreur personnalisés', () => {
|
|
4110
|
+
it('doit afficher les messages d\'erreur personnalisés', async () => {
|
|
4111
|
+
wrapper = mount(DatePicker, {
|
|
4112
|
+
global: {
|
|
4113
|
+
plugins: [vuetify],
|
|
4114
|
+
},
|
|
4115
|
+
props: {
|
|
4116
|
+
modelValue: '10/06/2024',
|
|
4117
|
+
label: 'Test erreur personnalisée',
|
|
4118
|
+
customRules: [
|
|
4119
|
+
{
|
|
4120
|
+
type: 'notBeforeDate',
|
|
4121
|
+
options: {
|
|
4122
|
+
date: '15/06/2024',
|
|
4123
|
+
message: 'Message d\'erreur personnalisé très spécifique',
|
|
4124
|
+
},
|
|
4125
|
+
},
|
|
4126
|
+
],
|
|
4127
|
+
},
|
|
4128
|
+
})
|
|
4129
|
+
|
|
4130
|
+
await nextTick()
|
|
4131
|
+
|
|
4132
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
4133
|
+
expect(result).toBe(false)
|
|
4134
|
+
})
|
|
4135
|
+
|
|
4136
|
+
it('doit gérer les erreurs de validation', async () => {
|
|
4137
|
+
wrapper = mount(DatePicker, {
|
|
4138
|
+
global: {
|
|
4139
|
+
plugins: [vuetify],
|
|
4140
|
+
},
|
|
4141
|
+
props: {
|
|
4142
|
+
modelValue: null,
|
|
4143
|
+
label: 'Test erreurs validation',
|
|
4144
|
+
required: true,
|
|
4145
|
+
customRules: [
|
|
4146
|
+
{
|
|
4147
|
+
type: 'custom',
|
|
4148
|
+
options: {
|
|
4149
|
+
validate: () => false,
|
|
4150
|
+
message: 'Erreur personnalisée',
|
|
4151
|
+
},
|
|
4152
|
+
},
|
|
4153
|
+
],
|
|
4154
|
+
},
|
|
4155
|
+
})
|
|
4156
|
+
|
|
4157
|
+
await nextTick()
|
|
4158
|
+
|
|
4159
|
+
// Déclencher la validation
|
|
4160
|
+
await wrapper.vm.validateOnSubmit()
|
|
4161
|
+
|
|
4162
|
+
expect(wrapper.vm.errorMessages.length).toBeGreaterThan(0)
|
|
4163
|
+
})
|
|
4164
|
+
|
|
4165
|
+
it('doit combiner erreurs internes et externes', async () => {
|
|
4166
|
+
wrapper = mount(DatePicker, {
|
|
4167
|
+
global: {
|
|
4168
|
+
plugins: [vuetify],
|
|
4169
|
+
},
|
|
4170
|
+
props: {
|
|
4171
|
+
useCombinedMode: true,
|
|
4172
|
+
modelValue: null,
|
|
4173
|
+
label: 'Test erreurs combinées',
|
|
4174
|
+
required: true,
|
|
4175
|
+
errorMessages: ['Erreur externe'],
|
|
4176
|
+
customRules: [
|
|
4177
|
+
{
|
|
4178
|
+
type: 'custom',
|
|
4179
|
+
options: {
|
|
4180
|
+
validate: () => false,
|
|
4181
|
+
message: 'Erreur interne',
|
|
4182
|
+
},
|
|
4183
|
+
},
|
|
4184
|
+
],
|
|
4185
|
+
},
|
|
4186
|
+
})
|
|
4187
|
+
|
|
4188
|
+
await nextTick()
|
|
4189
|
+
|
|
4190
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
4191
|
+
expect(result).toBe(false)
|
|
4192
|
+
})
|
|
4193
|
+
})
|
|
4194
|
+
|
|
4195
|
+
describe('Tests des warnings', () => {
|
|
4196
|
+
it('doit afficher les warnings sans bloquer la validation', async () => {
|
|
4197
|
+
wrapper = mount(DatePicker, {
|
|
4198
|
+
global: {
|
|
4199
|
+
plugins: [vuetify],
|
|
4200
|
+
},
|
|
4201
|
+
props: {
|
|
4202
|
+
useCombinedMode: true,
|
|
4203
|
+
modelValue: '15/06/2024',
|
|
4204
|
+
label: 'Test warnings',
|
|
4205
|
+
customWarningRules: [
|
|
4206
|
+
{
|
|
4207
|
+
type: 'custom',
|
|
4208
|
+
options: {
|
|
4209
|
+
validate: () => false,
|
|
4210
|
+
message: 'Ceci est un warning',
|
|
4211
|
+
},
|
|
4212
|
+
},
|
|
4213
|
+
],
|
|
4214
|
+
},
|
|
4215
|
+
})
|
|
4216
|
+
|
|
4217
|
+
await nextTick()
|
|
4218
|
+
|
|
4219
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
4220
|
+
expect(typeof result).toBe('boolean')
|
|
4221
|
+
})
|
|
4222
|
+
|
|
4223
|
+
it('doit gérer les warnings et erreurs simultanément', async () => {
|
|
4224
|
+
wrapper = mount(DatePicker, {
|
|
4225
|
+
global: {
|
|
4226
|
+
plugins: [vuetify],
|
|
4227
|
+
},
|
|
4228
|
+
props: {
|
|
4229
|
+
modelValue: '15/06/2024',
|
|
4230
|
+
label: 'Test warnings + erreurs',
|
|
4231
|
+
customRules: [
|
|
4232
|
+
{
|
|
4233
|
+
type: 'custom',
|
|
4234
|
+
options: {
|
|
4235
|
+
validate: () => false,
|
|
4236
|
+
message: 'Erreur critique',
|
|
4237
|
+
},
|
|
4238
|
+
},
|
|
4239
|
+
],
|
|
4240
|
+
customWarningRules: [
|
|
4241
|
+
{
|
|
4242
|
+
type: 'custom',
|
|
4243
|
+
options: {
|
|
4244
|
+
validate: () => false,
|
|
4245
|
+
message: 'Warning informatif',
|
|
4246
|
+
},
|
|
4247
|
+
},
|
|
4248
|
+
],
|
|
4249
|
+
},
|
|
4250
|
+
})
|
|
4251
|
+
|
|
4252
|
+
await nextTick()
|
|
4253
|
+
|
|
4254
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
4255
|
+
expect(result).toBe(false) // Erreur doit bloquer
|
|
4256
|
+
})
|
|
4257
|
+
})
|
|
4258
|
+
|
|
4259
|
+
describe('Tests des messages de succès', () => {
|
|
4260
|
+
it('doit afficher les messages de succès', async () => {
|
|
4261
|
+
wrapper = mount(DatePicker, {
|
|
4262
|
+
global: {
|
|
4263
|
+
plugins: [vuetify],
|
|
4264
|
+
},
|
|
4265
|
+
props: {
|
|
4266
|
+
modelValue: '15/06/2024',
|
|
4267
|
+
label: 'Test succès',
|
|
4268
|
+
customRules: [
|
|
4269
|
+
{
|
|
4270
|
+
type: 'custom',
|
|
4271
|
+
options: {
|
|
4272
|
+
validate: () => true,
|
|
4273
|
+
message: 'Date valide !',
|
|
4274
|
+
},
|
|
4275
|
+
},
|
|
4276
|
+
],
|
|
4277
|
+
},
|
|
4278
|
+
})
|
|
4279
|
+
|
|
4280
|
+
await nextTick()
|
|
4281
|
+
|
|
4282
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
4283
|
+
expect(result).toBe(true)
|
|
4284
|
+
})
|
|
4285
|
+
})
|
|
4286
|
+
})
|
|
4287
|
+
|
|
4288
|
+
/**
|
|
4289
|
+
* TESTS DE PERFORMANCE ET OPTIMISATION
|
|
4290
|
+
*/
|
|
4291
|
+
describe('Tests de Performance et Optimisation', () => {
|
|
4292
|
+
describe('Tests de debouncing et throttling', () => {
|
|
4293
|
+
it('doit gérer la validation en temps réel sans surcharge', async () => {
|
|
4294
|
+
const mockValidate = vi.fn().mockReturnValue(true)
|
|
4295
|
+
|
|
4296
|
+
wrapper = mount(DatePicker, {
|
|
4297
|
+
global: {
|
|
4298
|
+
plugins: [vuetify],
|
|
4299
|
+
},
|
|
4300
|
+
props: {
|
|
4301
|
+
modelValue: null,
|
|
4302
|
+
label: 'Test performance validation',
|
|
4303
|
+
customRules: [
|
|
4304
|
+
{
|
|
4305
|
+
type: 'custom',
|
|
4306
|
+
options: {
|
|
4307
|
+
validate: mockValidate,
|
|
4308
|
+
message: 'Test performance',
|
|
4309
|
+
},
|
|
4310
|
+
},
|
|
4311
|
+
],
|
|
4312
|
+
},
|
|
4313
|
+
})
|
|
4314
|
+
|
|
4315
|
+
await nextTick()
|
|
4316
|
+
|
|
4317
|
+
const input = wrapper.find('input')
|
|
4318
|
+
|
|
4319
|
+
// Saisie rapide
|
|
4320
|
+
for (let i = 0; i < 10; i++) {
|
|
4321
|
+
await input.setValue(`${i}`)
|
|
4322
|
+
await input.trigger('input')
|
|
4323
|
+
}
|
|
4324
|
+
|
|
4325
|
+
await nextTick()
|
|
4326
|
+
|
|
4327
|
+
expect(wrapper.exists()).toBe(true)
|
|
4328
|
+
// La validation ne doit pas être appelée excessivement
|
|
4329
|
+
})
|
|
4330
|
+
|
|
4331
|
+
it('doit optimiser les re-renders lors de changements rapides', async () => {
|
|
4332
|
+
wrapper = mount(DatePicker, {
|
|
4333
|
+
global: {
|
|
4334
|
+
plugins: [vuetify],
|
|
4335
|
+
},
|
|
4336
|
+
props: {
|
|
4337
|
+
useCombinedMode: true,
|
|
4338
|
+
modelValue: null,
|
|
4339
|
+
label: 'Test re-renders',
|
|
4340
|
+
},
|
|
4341
|
+
})
|
|
4342
|
+
|
|
4343
|
+
await nextTick()
|
|
4344
|
+
|
|
4345
|
+
const startTime = performance.now()
|
|
4346
|
+
|
|
4347
|
+
// Changements rapides de props
|
|
4348
|
+
for (let i = 0; i < 20; i++) {
|
|
4349
|
+
await wrapper.setProps({
|
|
4350
|
+
modelValue: `${10 + i}/06/2024`,
|
|
4351
|
+
label: `Label ${i}`,
|
|
4352
|
+
})
|
|
4353
|
+
}
|
|
4354
|
+
|
|
4355
|
+
const endTime = performance.now()
|
|
4356
|
+
|
|
4357
|
+
expect(wrapper.exists()).toBe(true)
|
|
4358
|
+
expect(endTime - startTime).toBeLessThan(1000) // Moins d'1 seconde
|
|
4359
|
+
})
|
|
4360
|
+
})
|
|
4361
|
+
|
|
4362
|
+
describe('Tests de memory leaks avancés', () => {
|
|
4363
|
+
it('doit nettoyer les watchers lors du unmount', async () => {
|
|
4364
|
+
wrapper = mount(DatePicker, {
|
|
4365
|
+
global: {
|
|
4366
|
+
plugins: [vuetify],
|
|
4367
|
+
},
|
|
4368
|
+
props: {
|
|
4369
|
+
useCombinedMode: true,
|
|
4370
|
+
modelValue: null,
|
|
4371
|
+
label: 'Test watchers cleanup',
|
|
4372
|
+
customRules: [
|
|
4373
|
+
{
|
|
4374
|
+
type: 'notBeforeDate',
|
|
4375
|
+
options: {
|
|
4376
|
+
date: '15/06/2024',
|
|
4377
|
+
message: 'Test',
|
|
4378
|
+
},
|
|
4379
|
+
},
|
|
4380
|
+
],
|
|
4381
|
+
},
|
|
4382
|
+
})
|
|
4383
|
+
|
|
4384
|
+
await nextTick()
|
|
4385
|
+
|
|
4386
|
+
// Unmount et vérifier le cleanup
|
|
4387
|
+
wrapper.unmount()
|
|
4388
|
+
|
|
4389
|
+
expect(wrapper.exists()).toBe(false)
|
|
4390
|
+
})
|
|
4391
|
+
|
|
4392
|
+
it('doit gérer les instances multiples sans interférence', async () => {
|
|
4393
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- tests
|
|
4394
|
+
const wrappers: any[] = []
|
|
4395
|
+
|
|
4396
|
+
// Créer plusieurs instances
|
|
4397
|
+
for (let i = 0; i < 5; i++) {
|
|
4398
|
+
const w = mount(DatePicker, {
|
|
4399
|
+
global: {
|
|
4400
|
+
plugins: [vuetify],
|
|
4401
|
+
},
|
|
4402
|
+
props: {
|
|
4403
|
+
modelValue: null,
|
|
4404
|
+
label: `Instance ${i}`,
|
|
4405
|
+
format: 'DD/MM/YYYY',
|
|
4406
|
+
},
|
|
4407
|
+
})
|
|
4408
|
+
wrappers.push(w)
|
|
4409
|
+
}
|
|
4410
|
+
|
|
4411
|
+
await nextTick()
|
|
4412
|
+
|
|
4413
|
+
// Vérifier que toutes les instances fonctionnent
|
|
4414
|
+
for (const w of wrappers) {
|
|
4415
|
+
expect(w.exists()).toBe(true)
|
|
4416
|
+
w.unmount()
|
|
4417
|
+
}
|
|
4418
|
+
})
|
|
4419
|
+
})
|
|
4420
|
+
})
|
|
4421
|
+
|
|
4422
|
+
/**
|
|
4423
|
+
* TESTS D'INTÉGRATION AVEC FORMULAIRES
|
|
4424
|
+
*/
|
|
4425
|
+
describe('Tests d\'Intégration avec Formulaires', () => {
|
|
4426
|
+
describe('Tests avec Vuetify forms', () => {
|
|
4427
|
+
it('doit s\'intégrer correctement dans un v-form', async () => {
|
|
4428
|
+
const formWrapper = mount({
|
|
4429
|
+
template: `
|
|
4430
|
+
<v-form ref="form">
|
|
4431
|
+
<DatePicker
|
|
4432
|
+
v-model="date"
|
|
4433
|
+
label="Date dans formulaire"
|
|
4434
|
+
:rules="[required]"
|
|
4435
|
+
/>
|
|
4436
|
+
</v-form>
|
|
4437
|
+
`,
|
|
4438
|
+
components: {
|
|
4439
|
+
DatePicker,
|
|
4440
|
+
},
|
|
4441
|
+
setup() {
|
|
4442
|
+
const date = ref(null)
|
|
4443
|
+
const required = value => !!value || 'Date requise'
|
|
4444
|
+
return { date, required }
|
|
4445
|
+
},
|
|
4446
|
+
}, {
|
|
4447
|
+
global: {
|
|
4448
|
+
plugins: [vuetify],
|
|
4449
|
+
},
|
|
4450
|
+
})
|
|
4451
|
+
|
|
4452
|
+
await nextTick()
|
|
4453
|
+
|
|
4454
|
+
expect(formWrapper.exists()).toBe(true)
|
|
4455
|
+
formWrapper.unmount()
|
|
4456
|
+
})
|
|
4457
|
+
|
|
4458
|
+
it('doit participer à la validation globale du formulaire', async () => {
|
|
4459
|
+
const formWrapper = mount({
|
|
4460
|
+
template: `
|
|
4461
|
+
<v-form ref="form" v-model="valid">
|
|
4462
|
+
<DatePicker
|
|
4463
|
+
v-model="date"
|
|
4464
|
+
label="Date validation globale"
|
|
4465
|
+
required
|
|
4466
|
+
/>
|
|
4467
|
+
</v-form>
|
|
4468
|
+
`,
|
|
4469
|
+
components: {
|
|
4470
|
+
DatePicker,
|
|
4471
|
+
},
|
|
4472
|
+
setup() {
|
|
4473
|
+
const date = ref(null)
|
|
4474
|
+
const valid = ref(false)
|
|
4475
|
+
return { date, valid }
|
|
4476
|
+
},
|
|
4477
|
+
}, {
|
|
4478
|
+
global: {
|
|
4479
|
+
plugins: [vuetify],
|
|
4480
|
+
},
|
|
4481
|
+
})
|
|
4482
|
+
|
|
4483
|
+
await nextTick()
|
|
4484
|
+
|
|
4485
|
+
expect(formWrapper.exists()).toBe(true)
|
|
4486
|
+
formWrapper.unmount()
|
|
4487
|
+
})
|
|
4488
|
+
})
|
|
4489
|
+
|
|
4490
|
+
describe('Tests de reset de formulaire', () => {
|
|
4491
|
+
it('doit se réinitialiser lors du reset du formulaire', async () => {
|
|
4492
|
+
wrapper = mount(DatePicker, {
|
|
4493
|
+
global: {
|
|
4494
|
+
plugins: [vuetify],
|
|
4495
|
+
},
|
|
4496
|
+
props: {
|
|
4497
|
+
modelValue: '15/06/2024',
|
|
4498
|
+
label: 'Test reset',
|
|
4499
|
+
},
|
|
4500
|
+
})
|
|
4501
|
+
|
|
4502
|
+
await nextTick()
|
|
4503
|
+
|
|
4504
|
+
// Simuler un reset
|
|
4505
|
+
await wrapper.setProps({ modelValue: null })
|
|
4506
|
+
await nextTick()
|
|
4507
|
+
|
|
4508
|
+
expect(wrapper.props('modelValue')).toBe(null)
|
|
4509
|
+
})
|
|
4510
|
+
|
|
4511
|
+
it('doit nettoyer les erreurs lors du reset', async () => {
|
|
4512
|
+
wrapper = mount(DatePicker, {
|
|
4513
|
+
global: {
|
|
4514
|
+
plugins: [vuetify],
|
|
4515
|
+
},
|
|
4516
|
+
props: {
|
|
4517
|
+
useCombinedMode: true,
|
|
4518
|
+
modelValue: null,
|
|
4519
|
+
label: 'Test reset erreurs',
|
|
4520
|
+
required: true,
|
|
4521
|
+
},
|
|
4522
|
+
})
|
|
4523
|
+
|
|
4524
|
+
await nextTick()
|
|
4525
|
+
|
|
4526
|
+
// Déclencher une erreur
|
|
4527
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
4528
|
+
expect(result).toBe(false)
|
|
4529
|
+
|
|
4530
|
+
// Reset
|
|
4531
|
+
await wrapper.setProps({ modelValue: '15/06/2024' })
|
|
4532
|
+
await nextTick()
|
|
4533
|
+
|
|
4534
|
+
const newResult = wrapper.vm.validateOnSubmit()
|
|
4535
|
+
expect(newResult).toBe(true)
|
|
4536
|
+
})
|
|
4537
|
+
})
|
|
4538
|
+
|
|
4539
|
+
describe('Tests de soumission de formulaire', () => {
|
|
4540
|
+
it('doit valider avant soumission', async () => {
|
|
4541
|
+
wrapper = mount(DatePicker, {
|
|
4542
|
+
global: {
|
|
4543
|
+
plugins: [vuetify],
|
|
4544
|
+
},
|
|
4545
|
+
props: {
|
|
4546
|
+
modelValue: null,
|
|
4547
|
+
label: 'Test soumission',
|
|
4548
|
+
required: true,
|
|
4549
|
+
customRules: [
|
|
4550
|
+
{
|
|
4551
|
+
type: 'notAfterToday',
|
|
4552
|
+
options: {
|
|
4553
|
+
message: 'Date future interdite',
|
|
4554
|
+
},
|
|
4555
|
+
},
|
|
4556
|
+
],
|
|
4557
|
+
},
|
|
4558
|
+
})
|
|
4559
|
+
|
|
4560
|
+
await nextTick()
|
|
4561
|
+
|
|
4562
|
+
// Test avec date invalide
|
|
4563
|
+
await wrapper.setProps({ modelValue: '15/12/2025' })
|
|
4564
|
+
await nextTick()
|
|
4565
|
+
|
|
4566
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
4567
|
+
expect(typeof result).toBe('boolean')
|
|
4568
|
+
})
|
|
4569
|
+
|
|
4570
|
+
it('doit retourner les bonnes valeurs pour la soumission', async () => {
|
|
4571
|
+
wrapper = mount(DatePicker, {
|
|
4572
|
+
global: {
|
|
4573
|
+
plugins: [vuetify],
|
|
4574
|
+
},
|
|
4575
|
+
props: {
|
|
4576
|
+
modelValue: '15/06/2024',
|
|
4577
|
+
label: 'Test valeurs soumission',
|
|
4578
|
+
format: 'DD/MM/YYYY',
|
|
4579
|
+
dateFormatReturn: 'YYYY-MM-DD',
|
|
4580
|
+
},
|
|
4581
|
+
})
|
|
4582
|
+
|
|
4583
|
+
await nextTick()
|
|
4584
|
+
|
|
4585
|
+
expect(wrapper.props('modelValue')).toBe('15/06/2024')
|
|
4586
|
+
expect(wrapper.props('dateFormatReturn')).toBe('YYYY-MM-DD')
|
|
4587
|
+
})
|
|
4588
|
+
})
|
|
4589
|
+
})
|
|
4590
|
+
|
|
4591
|
+
/**
|
|
4592
|
+
* TESTS TRANSVERSAUX POUR TOUS LES MODES
|
|
4593
|
+
*/
|
|
4594
|
+
describe('Tests Transversaux - Tous les Modes', () => {
|
|
4595
|
+
const modes = [
|
|
4596
|
+
{ name: 'CalendarMode', component: DatePicker, props: {} },
|
|
4597
|
+
{ name: 'DatePicker', component: DatePicker, props: {} },
|
|
4598
|
+
{ name: 'DatePicker Combined', component: DatePicker, props: { useCombinedMode: true } },
|
|
4599
|
+
{ name: 'DatePicker', component: DatePicker, props: {} },
|
|
4600
|
+
]
|
|
4601
|
+
|
|
4602
|
+
modes.forEach(({ name, component, props }) => {
|
|
4603
|
+
describe(`${name}`, () => {
|
|
4604
|
+
it('doit gérer les custom rules avec valeurs null', async () => {
|
|
4605
|
+
const customRuleMock = vi.fn().mockReturnValue(true)
|
|
4606
|
+
const customRules = [
|
|
4607
|
+
{
|
|
4608
|
+
type: 'custom',
|
|
4609
|
+
options: {
|
|
4610
|
+
validate: customRuleMock,
|
|
4611
|
+
message: 'Test null',
|
|
4612
|
+
},
|
|
4613
|
+
},
|
|
4614
|
+
]
|
|
4615
|
+
|
|
4616
|
+
wrapper = mount(component, {
|
|
4617
|
+
global: {
|
|
4618
|
+
plugins: [vuetify],
|
|
4619
|
+
},
|
|
4620
|
+
props: {
|
|
4621
|
+
modelValue: null,
|
|
4622
|
+
label: `Date ${name}`,
|
|
4623
|
+
customRules,
|
|
4624
|
+
...props,
|
|
4625
|
+
},
|
|
4626
|
+
})
|
|
4627
|
+
|
|
4628
|
+
await nextTick()
|
|
4629
|
+
|
|
4630
|
+
wrapper.vm.validateOnSubmit()
|
|
4631
|
+
expect(customRuleMock).toHaveBeenCalledWith(null)
|
|
4632
|
+
})
|
|
4633
|
+
|
|
4634
|
+
it('doit retourner true quand aucune règle n\'est définie', async () => {
|
|
4635
|
+
wrapper = mount(component, {
|
|
4636
|
+
global: {
|
|
4637
|
+
plugins: [vuetify],
|
|
4638
|
+
},
|
|
4639
|
+
props: {
|
|
4640
|
+
modelValue: null,
|
|
4641
|
+
label: `Date ${name}`,
|
|
4642
|
+
...props,
|
|
4643
|
+
},
|
|
4644
|
+
})
|
|
4645
|
+
|
|
4646
|
+
await nextTick()
|
|
4647
|
+
|
|
4648
|
+
const result = wrapper.vm.validateOnSubmit()
|
|
4649
|
+
expect(result).toBe(true)
|
|
4650
|
+
})
|
|
4651
|
+
})
|
|
4652
|
+
})
|
|
4653
|
+
})
|
|
4654
|
+
})
|