diff --git a/documentation/html/ExternalRESTClients.html b/documentation/html/ExternalRESTClients.html index 10fc104964..937351fefe 100644 --- a/documentation/html/ExternalRESTClients.html +++ b/documentation/html/ExternalRESTClients.html @@ -414,7 +414,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/GraphQLClient.html b/documentation/html/GraphQLClient.html index e29141b167..79ddd85de6 100644 --- a/documentation/html/GraphQLClient.html +++ b/documentation/html/GraphQLClient.html @@ -912,7 +912,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/RESTClient.html b/documentation/html/RESTClient.html index 87d44c61ce..e24372e1d8 100644 --- a/documentation/html/RESTClient.html +++ b/documentation/html/RESTClient.html @@ -10217,7 +10217,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/Static.html b/documentation/html/Static.html index ae4d56fcf6..bbfe91e8fb 100644 --- a/documentation/html/Static.html +++ b/documentation/html/Static.html @@ -391,7 +391,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/classes.list.html b/documentation/html/classes.list.html index c803560872..04cfe29bae 100644 --- a/documentation/html/classes.list.html +++ b/documentation/html/classes.list.html @@ -2984,7 +2984,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Curators_CuratorRecordsAwaitingApproval.vue.html b/documentation/html/components_Curators_CuratorRecordsAwaitingApproval.vue.html index cfdccb8660..2bebd1b06f 100644 --- a/documentation/html/components_Curators_CuratorRecordsAwaitingApproval.vue.html +++ b/documentation/html/components_Curators_CuratorRecordsAwaitingApproval.vue.html @@ -833,7 +833,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Curators_DownLoadRecordsComponents_CuratorSummaryStatistics.vue.html b/documentation/html/components_Curators_DownLoadRecordsComponents_CuratorSummaryStatistics.vue.html index b96ea4f24a..6be409a62d 100644 --- a/documentation/html/components_Curators_DownLoadRecordsComponents_CuratorSummaryStatistics.vue.html +++ b/documentation/html/components_Curators_DownLoadRecordsComponents_CuratorSummaryStatistics.vue.html @@ -199,7 +199,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Curators_DownLoadRecordsComponents_RecordEditsByMonth.vue.html b/documentation/html/components_Curators_DownLoadRecordsComponents_RecordEditsByMonth.vue.html index fbab801f3b..935f0c3f20 100644 --- a/documentation/html/components_Curators_DownLoadRecordsComponents_RecordEditsByMonth.vue.html +++ b/documentation/html/components_Curators_DownLoadRecordsComponents_RecordEditsByMonth.vue.html @@ -202,7 +202,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Curators_DownLoadRecordsComponents_RecordsCreatedByMonth.vue.html b/documentation/html/components_Curators_DownLoadRecordsComponents_RecordsCreatedByMonth.vue.html index b0d3006869..15f3a147ce 100644 --- a/documentation/html/components_Curators_DownLoadRecordsComponents_RecordsCreatedByMonth.vue.html +++ b/documentation/html/components_Curators_DownLoadRecordsComponents_RecordsCreatedByMonth.vue.html @@ -204,7 +204,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Curators_DownLoadRecordsComponents_RecordsNeedingReview.vue.html b/documentation/html/components_Curators_DownLoadRecordsComponents_RecordsNeedingReview.vue.html index 47eb81cb89..03ced4b9c8 100644 --- a/documentation/html/components_Curators_DownLoadRecordsComponents_RecordsNeedingReview.vue.html +++ b/documentation/html/components_Curators_DownLoadRecordsComponents_RecordsNeedingReview.vue.html @@ -199,7 +199,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Curators_DownLoadRecordsComponents_RecordsWithoutDois.vue.html b/documentation/html/components_Curators_DownLoadRecordsComponents_RecordsWithoutDois.vue.html index d455277d69..be409a71ae 100644 --- a/documentation/html/components_Curators_DownLoadRecordsComponents_RecordsWithoutDois.vue.html +++ b/documentation/html/components_Curators_DownLoadRecordsComponents_RecordsWithoutDois.vue.html @@ -205,7 +205,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Curators_HiddenRecords.vue.html b/documentation/html/components_Curators_HiddenRecords.vue.html index 043c22f32a..825d42136d 100644 --- a/documentation/html/components_Curators_HiddenRecords.vue.html +++ b/documentation/html/components_Curators_HiddenRecords.vue.html @@ -299,7 +299,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Curators_IncompleteRecords.vue.html b/documentation/html/components_Curators_IncompleteRecords.vue.html index 56b951ebed..fbc9d8f8d9 100644 --- a/documentation/html/components_Curators_IncompleteRecords.vue.html +++ b/documentation/html/components_Curators_IncompleteRecords.vue.html @@ -385,7 +385,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Curators_MaintenanceRequests.vue.html b/documentation/html/components_Curators_MaintenanceRequests.vue.html index b9205b32e6..cc802db9a7 100644 --- a/documentation/html/components_Curators_MaintenanceRequests.vue.html +++ b/documentation/html/components_Curators_MaintenanceRequests.vue.html @@ -672,7 +672,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Curators_RecentCuratorCreation.vue.html b/documentation/html/components_Curators_RecentCuratorCreation.vue.html index 57ae88787f..7592d43952 100644 --- a/documentation/html/components_Curators_RecentCuratorCreation.vue.html +++ b/documentation/html/components_Curators_RecentCuratorCreation.vue.html @@ -294,7 +294,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Curators_SystemMessages.vue.html b/documentation/html/components_Curators_SystemMessages.vue.html index 2d2d70c097..87f30e59a2 100644 --- a/documentation/html/components_Curators_SystemMessages.vue.html +++ b/documentation/html/components_Curators_SystemMessages.vue.html @@ -474,7 +474,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Curators_UserRecordsAwaitingApproval.vue.html b/documentation/html/components_Curators_UserRecordsAwaitingApproval.vue.html index bc03f58468..e128d59c00 100644 --- a/documentation/html/components_Curators_UserRecordsAwaitingApproval.vue.html +++ b/documentation/html/components_Curators_UserRecordsAwaitingApproval.vue.html @@ -839,7 +839,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Record_Collections.vue.html b/documentation/html/components_Records_Record_Collections.vue.html index 2f7262bd8d..355305c0a0 100644 --- a/documentation/html/components_Records_Record_Collections.vue.html +++ b/documentation/html/components_Records_Record_Collections.vue.html @@ -462,7 +462,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Record_GeneralInfo_SavedSearches.vue.html b/documentation/html/components_Records_Record_GeneralInfo_SavedSearches.vue.html index a7c154da7b..79c1a46ee6 100644 --- a/documentation/html/components_Records_Record_GeneralInfo_SavedSearches.vue.html +++ b/documentation/html/components_Records_Record_GeneralInfo_SavedSearches.vue.html @@ -319,7 +319,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Record_RelatedContent.vue.html b/documentation/html/components_Records_Record_RelatedContent.vue.html index bfe443255c..60f228344b 100644 --- a/documentation/html/components_Records_Record_RelatedContent.vue.html +++ b/documentation/html/components_Records_Record_RelatedContent.vue.html @@ -454,7 +454,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Header_FilterChips.vue.html b/documentation/html/components_Records_Search_Header_FilterChips.vue.html index 4eb5c670e2..76bed49902 100644 --- a/documentation/html/components_Records_Search_Header_FilterChips.vue.html +++ b/documentation/html/components_Records_Search_Header_FilterChips.vue.html @@ -251,7 +251,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Header_Pagination.vue.html b/documentation/html/components_Records_Search_Header_Pagination.vue.html index 2cbd765b3e..66572d54c7 100644 --- a/documentation/html/components_Records_Search_Header_Pagination.vue.html +++ b/documentation/html/components_Records_Search_Header_Pagination.vue.html @@ -262,7 +262,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Header_Sorting.vue.html b/documentation/html/components_Records_Search_Header_Sorting.vue.html index 7e7c9ddcba..76321fa7f6 100644 --- a/documentation/html/components_Records_Search_Header_Sorting.vue.html +++ b/documentation/html/components_Records_Search_Header_Sorting.vue.html @@ -219,7 +219,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_AdvancedSearchDialogBox.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_AdvancedSearchDialogBox.vue.html index c8e4973227..034bd24ec2 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_AdvancedSearchDialogBox.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_AdvancedSearchDialogBox.vue.html @@ -487,7 +487,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Countries.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Countries.vue.html index a203a04ed4..5caad10fe2 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Countries.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Countries.vue.html @@ -225,7 +225,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Domains.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Domains.vue.html index e759f31cb9..57c9129579 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Domains.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Domains.vue.html @@ -218,7 +218,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Licences.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Licences.vue.html index 3a3e5fe5a3..27f67ba891 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Licences.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Licences.vue.html @@ -218,7 +218,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_ObjectTypes.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_ObjectTypes.vue.html index 020c3665ca..431b8ebd41 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_ObjectTypes.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_ObjectTypes.vue.html @@ -220,7 +220,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Organisations.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Organisations.vue.html index f051ddfca1..fe647c3c86 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Organisations.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Organisations.vue.html @@ -229,7 +229,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Subject.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Subject.vue.html index 3010e0a0a0..13494c9f07 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Subject.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Subject.vue.html @@ -218,7 +218,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Taxonomies.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Taxonomies.vue.html index 6b99f20938..a04916de20 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Taxonomies.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_Taxonomies.vue.html @@ -224,7 +224,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_UserDefinedTag.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_UserDefinedTag.vue.html index e26686168f..f7cf8af867 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_UserDefinedTag.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GeneralComponents_UserDefinedTag.vue.html @@ -224,7 +224,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_DatabaseRule.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_DatabaseRule.vue.html index 28edb01249..132627d34e 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_DatabaseRule.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_DatabaseRule.vue.html @@ -315,7 +315,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_FairassistRule.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_FairassistRule.vue.html index f6a04f88f2..4e214dde44 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_FairassistRule.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_FairassistRule.vue.html @@ -252,7 +252,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_GeneralRule.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_GeneralRule.vue.html index 6092e2cbce..8f71a07faf 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_GeneralRule.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_GeneralRule.vue.html @@ -272,7 +272,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_GroupCtrlSlot.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_GroupCtrlSlot.vue.html index 44be1009b4..155bbf9311 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_GroupCtrlSlot.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_GroupCtrlSlot.vue.html @@ -199,7 +199,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_PolicyRule.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_PolicyRule.vue.html index ac79a5c303..0bd0cac247 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_PolicyRule.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_PolicyRule.vue.html @@ -328,7 +328,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_StandardRule.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_StandardRule.vue.html index 3f5979be98..e6f0b286ff 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_StandardRule.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderComponents_GroupCtrlSlot_StandardRule.vue.html @@ -230,7 +230,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderView.vue.html b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderView.vue.html index 7d1cdcdd38..763461866b 100644 --- a/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderView.vue.html +++ b/documentation/html/components_Records_Search_Input_AdvancedSearch_QueryBuilderView.vue.html @@ -676,7 +676,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_FilterAutocomplete.vue.html b/documentation/html/components_Records_Search_Input_FilterAutocomplete.vue.html index 950f4d0b2f..40ba5b84ab 100644 --- a/documentation/html/components_Records_Search_Input_FilterAutocomplete.vue.html +++ b/documentation/html/components_Records_Search_Input_FilterAutocomplete.vue.html @@ -376,7 +376,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_FilterButton.vue.html b/documentation/html/components_Records_Search_Input_FilterButton.vue.html index a448b2ac84..26440398a5 100644 --- a/documentation/html/components_Records_Search_Input_FilterButton.vue.html +++ b/documentation/html/components_Records_Search_Input_FilterButton.vue.html @@ -287,7 +287,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_Input_SearchInput.vue.html b/documentation/html/components_Records_Search_Input_SearchInput.vue.html index 9d8a522d27..a55bf493eb 100644 --- a/documentation/html/components_Records_Search_Input_SearchInput.vue.html +++ b/documentation/html/components_Records_Search_Input_SearchInput.vue.html @@ -284,7 +284,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_SaveSearch_SaveSearchButton.vue.html b/documentation/html/components_Records_Search_SaveSearch_SaveSearchButton.vue.html index 8c222b410a..01e9d276fc 100644 --- a/documentation/html/components_Records_Search_SaveSearch_SaveSearchButton.vue.html +++ b/documentation/html/components_Records_Search_SaveSearch_SaveSearchButton.vue.html @@ -182,7 +182,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_SaveSearch_SaveSearchStepper.vue.html b/documentation/html/components_Records_Search_SaveSearch_SaveSearchStepper.vue.html index 98d419e011..862352eb21 100644 --- a/documentation/html/components_Records_Search_SaveSearch_SaveSearchStepper.vue.html +++ b/documentation/html/components_Records_Search_SaveSearch_SaveSearchStepper.vue.html @@ -464,7 +464,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_SaveSearch_StepperComponents_OrganisationStepper.vue.html b/documentation/html/components_Records_Search_SaveSearch_StepperComponents_OrganisationStepper.vue.html index f0c0237794..be81b14644 100644 --- a/documentation/html/components_Records_Search_SaveSearch_StepperComponents_OrganisationStepper.vue.html +++ b/documentation/html/components_Records_Search_SaveSearch_StepperComponents_OrganisationStepper.vue.html @@ -259,7 +259,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_SaveSearch_StepperComponents_PolicyStepper.vue.html b/documentation/html/components_Records_Search_SaveSearch_StepperComponents_PolicyStepper.vue.html index 032b16b49b..1624444bac 100644 --- a/documentation/html/components_Records_Search_SaveSearch_StepperComponents_PolicyStepper.vue.html +++ b/documentation/html/components_Records_Search_SaveSearch_StepperComponents_PolicyStepper.vue.html @@ -259,7 +259,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_SaveSearch_StepperComponents_ResultCard.vue.html b/documentation/html/components_Records_Search_SaveSearch_StepperComponents_ResultCard.vue.html index efdea90e51..8b52dca4bc 100644 --- a/documentation/html/components_Records_Search_SaveSearch_StepperComponents_ResultCard.vue.html +++ b/documentation/html/components_Records_Search_SaveSearch_StepperComponents_ResultCard.vue.html @@ -259,7 +259,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_SaveSearch_StepperComponents_StepperDialogHeader.vue.html b/documentation/html/components_Records_Search_SaveSearch_StepperComponents_StepperDialogHeader.vue.html index 510f82584d..0589679282 100644 --- a/documentation/html/components_Records_Search_SaveSearch_StepperComponents_StepperDialogHeader.vue.html +++ b/documentation/html/components_Records_Search_SaveSearch_StepperComponents_StepperDialogHeader.vue.html @@ -182,7 +182,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Records_Search_SaveSearch_StepperComponents_UserStepper.vue.html b/documentation/html/components_Records_Search_SaveSearch_StepperComponents_UserStepper.vue.html index 29d7b64173..8f8ef85f8f 100644 --- a/documentation/html/components_Records_Search_SaveSearch_StepperComponents_UserStepper.vue.html +++ b/documentation/html/components_Records_Search_SaveSearch_StepperComponents_UserStepper.vue.html @@ -211,7 +211,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/components_Users_Profiles_Private_ViewSavedSearchesTable.vue.html b/documentation/html/components_Users_Profiles_Private_ViewSavedSearchesTable.vue.html index 9e3b9726e3..44f80458e9 100644 --- a/documentation/html/components_Users_Profiles_Private_ViewSavedSearchesTable.vue.html +++ b/documentation/html/components_Users_Profiles_Private_ViewSavedSearchesTable.vue.html @@ -509,7 +509,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/global.html b/documentation/html/global.html index 5d7c0f624f..4f6c4faa00 100644 --- a/documentation/html/global.html +++ b/documentation/html/global.html @@ -2964,7 +2964,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/index.html b/documentation/html/index.html index 14c5709d59..4252cde104 100644 --- a/documentation/html/index.html +++ b/documentation/html/index.html @@ -216,7 +216,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/lib_Client_ExternalClients.js.html b/documentation/html/lib_Client_ExternalClients.js.html index ad87fa86ca..a8fd4a9792 100644 --- a/documentation/html/lib_Client_ExternalClients.js.html +++ b/documentation/html/lib_Client_ExternalClients.js.html @@ -256,7 +256,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/lib_Client_RESTClient.js.html b/documentation/html/lib_Client_RESTClient.js.html index ce0a02737b..d520e4818b 100644 --- a/documentation/html/lib_Client_RESTClient.js.html +++ b/documentation/html/lib_Client_RESTClient.js.html @@ -1284,7 +1284,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/lib_GraphClient_GraphClient.js.html b/documentation/html/lib_GraphClient_GraphClient.js.html index 51d6c37cb4..203765670b 100644 --- a/documentation/html/lib_GraphClient_GraphClient.js.html +++ b/documentation/html/lib_GraphClient_GraphClient.js.html @@ -285,7 +285,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/lib_GraphClient_GraphClientSEO.js.html b/documentation/html/lib_GraphClient_GraphClientSEO.js.html index 207f0fbec1..138198ffb3 100644 --- a/documentation/html/lib_GraphClient_GraphClientSEO.js.html +++ b/documentation/html/lib_GraphClient_GraphClientSEO.js.html @@ -286,7 +286,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/module-Home.html b/documentation/html/module-Home.html index 5c22b1c6ff..a50b095197 100644 --- a/documentation/html/module-Home.html +++ b/documentation/html/module-Home.html @@ -220,7 +220,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/module-Login.html b/documentation/html/module-Login.html index 262cb08329..88c320c669 100644 --- a/documentation/html/module-Login.html +++ b/documentation/html/module-Login.html @@ -220,7 +220,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/module-NewRecord.html b/documentation/html/module-NewRecord.html index b59425fc4c..e7e3892713 100644 --- a/documentation/html/module-NewRecord.html +++ b/documentation/html/module-NewRecord.html @@ -220,7 +220,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/module-Pagination.html b/documentation/html/module-Pagination.html index 9f2505ffd7..ef08864178 100644 --- a/documentation/html/module-Pagination.html +++ b/documentation/html/module-Pagination.html @@ -527,7 +527,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/module-Signup.html b/documentation/html/module-Signup.html index a720d14734..faf41c1bfb 100644 --- a/documentation/html/module-Signup.html +++ b/documentation/html/module-Signup.html @@ -220,7 +220,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/module-User.html b/documentation/html/module-User.html index ba94522cc7..a3df91ad22 100644 --- a/documentation/html/module-User.html +++ b/documentation/html/module-User.html @@ -228,7 +228,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/modules.list.html b/documentation/html/modules.list.html index 1089d26429..a45d2d1e5f 100644 --- a/documentation/html/modules.list.html +++ b/documentation/html/modules.list.html @@ -2984,7 +2984,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/namespaces.list.html b/documentation/html/namespaces.list.html index 07891c03fe..38922a7a27 100644 --- a/documentation/html/namespaces.list.html +++ b/documentation/html/namespaces.list.html @@ -2984,7 +2984,7 @@ Documentation generated by JSDoc 4.0.5 - on Thu Jul 16th 2026 + on Tue Jul 28th 2026 using the DocStrap template. diff --git a/documentation/html/quicksearch.html b/documentation/html/quicksearch.html index c101744fc1..d1c81c13ec 100644 --- a/documentation/html/quicksearch.html +++ b/documentation/html/quicksearch.html @@ -7,7 +7,7 @@ + + diff --git a/tests/setup.js b/tests/setup.js index c160aa508f..92f5360909 100644 --- a/tests/setup.js +++ b/tests/setup.js @@ -190,19 +190,21 @@ global.IntersectionObserver = class IntersectionObserver { // --- 3. window.matchMedia Polyfill --- // CRITICAL for $vuetify.display (mdAndDown, lgAndUp, etc.) // We default 'matches' to false, meaning the test assumes "Desktop" view by default. -Object.defineProperty(window, "matchMedia", { - writable: true, - value: vi.fn().mockImplementation((query) => ({ - matches: false, - media: query, - onchange: null, - addListener: vi.fn(), // deprecated - removeListener: vi.fn(), // deprecated - addEventListener: vi.fn(), - removeEventListener: vi.fn(), - dispatchEvent: vi.fn(), - })), -}); +if (typeof window !== "undefined") { + Object.defineProperty(window, "matchMedia", { + writable: true, + value: vi.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), // deprecated + removeListener: vi.fn(), // deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), + }); +} // --- 4. Mock global CSS support --- // Prevents errors in some Vuetify computed properties @@ -224,14 +226,16 @@ if (!Object.groupBy) { }; } -// Prevent accidental network access to local API endpoints in unit tests. +// Prevent unit tests from reaching API and embedded-service endpoints. const nativeFetch = globalThis.fetch ? globalThis.fetch.bind(globalThis) : null; const mockedFetch = async (input, init) => { const url = typeof input === "string" ? input : (input && input.url) || ""; if ( url.includes("localhost:3000") || url.includes("127.0.0.1:3000") || - url.includes("undefined/graphql") + url.includes("undefined/graphql") || + url.includes("dev-api.fairsharing.org") || + url.includes("aicc.uksouth.cloudapp.azure.com") ) { return new Response(JSON.stringify({}), { status: 200, @@ -246,14 +250,15 @@ if (typeof window !== "undefined") { window.fetch = globalThis.fetch; } -// Short-circuit GraphQL requests that would otherwise target localhost in tests. +// Short-circuit GraphQL requests to configured development endpoints in tests. const originalGetData = GraphQLClient.prototype.getData; GraphQLClient.prototype.getData = async function (queryString) { const url = this.url || ""; if ( url.includes("localhost:3000") || url.includes("127.0.0.1:3000") || - url.includes("undefined/graphql") + url.includes("undefined/graphql") || + url.includes("dev-api.fairsharing.org") ) { return { data: { data: {} } }; } @@ -266,6 +271,7 @@ RESTClient.prototype.executeQuery = async function (query) { if ( url.includes("localhost:3000") || url.includes("127.0.0.1:3000") || + url.includes("dev-api.fairsharing.org") || url.startsWith("undefined") || url.includes("/undefined/") ) { diff --git a/tests/unit/components/ChatBot/FionaChat.spec.js b/tests/unit/components/ChatBot/FionaChat.spec.js index 926e6f9911..80d4aa1c2e 100644 --- a/tests/unit/components/ChatBot/FionaChat.spec.js +++ b/tests/unit/components/ChatBot/FionaChat.spec.js @@ -12,6 +12,9 @@ describe("FionaChat", () => { document.body.innerHTML = '
'; wrapper = mount(FionaChat, { attachTo: "#app", + data: () => ({ + chatUrl: "about:blank#", + }), global: { stubs: { VBtn: { diff --git a/tests/unit/components/Curators/DownLoadRecordComponents/CuratorSummaryStatistics.spec.js b/tests/unit/components/Curators/DownLoadRecordComponents/CuratorSummaryStatistics.spec.js index c149ffa408..8df7f01867 100644 --- a/tests/unit/components/Curators/DownLoadRecordComponents/CuratorSummaryStatistics.spec.js +++ b/tests/unit/components/Curators/DownLoadRecordComponents/CuratorSummaryStatistics.spec.js @@ -15,7 +15,9 @@ const { mockClientInstance } = vi.hoisted(() => { vi.mock("@/lib/GraphClient/GraphClient", () => { return { - default: vi.fn().mockImplementation(() => mockClientInstance), + default: vi.fn(function () { + return mockClientInstance; + }), }; }); diff --git a/tests/unit/components/Curators/DownLoadRecordComponents/RecordEditsByMonth.spec.js b/tests/unit/components/Curators/DownLoadRecordComponents/RecordEditsByMonth.spec.js index f4eb14cbcc..f2c70c5e98 100644 --- a/tests/unit/components/Curators/DownLoadRecordComponents/RecordEditsByMonth.spec.js +++ b/tests/unit/components/Curators/DownLoadRecordComponents/RecordEditsByMonth.spec.js @@ -10,9 +10,11 @@ const { mockGetEditByMonth } = vi.hoisted(() => ({ // 2. Mock RestClient vi.mock("@/lib/Client/RESTClient", () => { return { - default: vi.fn().mockImplementation(() => ({ - getEditByMonth: mockGetEditByMonth, - })), + default: vi.fn(function () { + return { + getEditByMonth: mockGetEditByMonth, + }; + }), }; }); diff --git a/tests/unit/components/Curators/DownLoadRecordComponents/RecordsCreatedByMonth.spec.js b/tests/unit/components/Curators/DownLoadRecordComponents/RecordsCreatedByMonth.spec.js index f169466e4e..9746ded3d1 100644 --- a/tests/unit/components/Curators/DownLoadRecordComponents/RecordsCreatedByMonth.spec.js +++ b/tests/unit/components/Curators/DownLoadRecordComponents/RecordsCreatedByMonth.spec.js @@ -9,9 +9,11 @@ const { mockGetRecordCreatedByMonth } = vi.hoisted(() => ({ vi.mock("@/lib/Client/RESTClient", () => { return { - default: vi.fn().mockImplementation(() => ({ - getRecordCreatedByMonth: mockGetRecordCreatedByMonth, - })), + default: vi.fn(function () { + return { + getRecordCreatedByMonth: mockGetRecordCreatedByMonth, + }; + }), }; }); diff --git a/tests/unit/components/Curators/DownLoadRecordComponents/RecordsNeedingReview.spec.js b/tests/unit/components/Curators/DownLoadRecordComponents/RecordsNeedingReview.spec.js index f5970fba10..3b363a0d9c 100644 --- a/tests/unit/components/Curators/DownLoadRecordComponents/RecordsNeedingReview.spec.js +++ b/tests/unit/components/Curators/DownLoadRecordComponents/RecordsNeedingReview.spec.js @@ -13,7 +13,9 @@ const { mockClientInstance } = vi.hoisted(() => ({ vi.mock("@/lib/GraphClient/GraphClient", () => { return { - default: vi.fn().mockImplementation(() => mockClientInstance), + default: vi.fn(function () { + return mockClientInstance; + }), }; }); diff --git a/tests/unit/components/Curators/DownLoadRecordComponents/RecordsWithoutDois.spec.js b/tests/unit/components/Curators/DownLoadRecordComponents/RecordsWithoutDois.spec.js index 1736be80fc..858e322d52 100644 --- a/tests/unit/components/Curators/DownLoadRecordComponents/RecordsWithoutDois.spec.js +++ b/tests/unit/components/Curators/DownLoadRecordComponents/RecordsWithoutDois.spec.js @@ -9,9 +9,11 @@ const { mockGetRecordsWoDOIs } = vi.hoisted(() => ({ vi.mock("@/lib/Client/RESTClient", () => { return { - default: vi.fn().mockImplementation(() => ({ - getRecordsWoDOIs: mockGetRecordsWoDOIs, - })), + default: vi.fn(function () { + return { + getRecordsWoDOIs: mockGetRecordsWoDOIs, + }; + }), }; }); diff --git a/tests/unit/components/Curators/MaintenanceRequests.spec.js b/tests/unit/components/Curators/MaintenanceRequests.spec.js index 9f065d5fce..5635086f63 100644 --- a/tests/unit/components/Curators/MaintenanceRequests.spec.js +++ b/tests/unit/components/Curators/MaintenanceRequests.spec.js @@ -24,13 +24,17 @@ const restClientMock = vi.hoisted(() => ({ // Mock RESTClient and GraphClient classes vi.mock("@/lib/Client/RESTClient.js", () => { return { - default: vi.fn().mockImplementation(() => restClientMock), + default: vi.fn(function () { + return restClientMock; + }), }; }); vi.mock("@/lib/GraphClient/GraphClient", () => { return { - default: vi.fn().mockImplementation(() => graphClientMock), + default: vi.fn(function () { + return graphClientMock; + }), }; }); diff --git a/tests/unit/components/Curators/UserRecordsAwaitingApproval.spec.js b/tests/unit/components/Curators/UserRecordsAwaitingApproval.spec.js index 37d758281f..53849f3769 100644 --- a/tests/unit/components/Curators/UserRecordsAwaitingApproval.spec.js +++ b/tests/unit/components/Curators/UserRecordsAwaitingApproval.spec.js @@ -1,4 +1,4 @@ -import { afterEach, beforeAll, describe, expect, it, vi } from "vitest"; +import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import { shallowMount } from "@vue/test-utils"; import sinon from "sinon"; import Vuex from "vuex"; @@ -119,7 +119,7 @@ describe("Curator -> UserRecordsAwaitingApproval.vue", () => { }); }); - afterEach(() => { + afterAll(() => { graphStub.restore(); restStub.restore(); }); @@ -168,7 +168,6 @@ describe("Curator -> UserRecordsAwaitingApproval.vue", () => { expect(wrapper.vm.approvalRequiredProcessed[0].curator).toMatch("Michae"); // TODO: Check that the curator are updated in the record - restStub = sinon.stub(Client.prototype, "executeQuery"); restStub.returns({ data: { error: { response: "Im an error" } } }); await wrapper.vm.assignCurator(11, 1, "Michael Smith"); expect(wrapper.vm.error.recordID).toBe(11); @@ -179,7 +178,6 @@ describe("Curator -> UserRecordsAwaitingApproval.vue", () => { it("can approve a record", async () => { //Correct approval wrapper.vm.dialogs.recordID = 100; - restStub = sinon.stub(Client.prototype, "executeQuery"); restStub.returns({ data: { error: false } }); await wrapper.vm.confirmApproval(); expect(wrapper.vm.approvalRequiredProcessed.length).toBe(2); @@ -193,9 +191,7 @@ describe("Curator -> UserRecordsAwaitingApproval.vue", () => { expect(wrapper.vm.dialogs.approveChanges).toBe(false); expect(wrapper.vm.approvalRequiredProcessed[0].id).toBe(11); //There is an error in the Client query - restStub.restore(); wrapper.vm.dialogs.recordID = 101; - restStub = sinon.stub(Client.prototype, "executeQuery"); restStub.returns({ data: { error: { response: { data: "error" } } } }); await wrapper.vm.confirmApproval(); expect(wrapper.vm.approvalRequiredProcessed.length).toBe(1); @@ -208,9 +204,7 @@ describe("Curator -> UserRecordsAwaitingApproval.vue", () => { expect(wrapper.vm.approvalRequiredProcessed.length).toBe(1); expect(wrapper.vm.dialogs.approveChanges).toBe(false); - restStub.restore(); wrapper.vm.dialogs.recordID = 102; - restStub = sinon.stub(Client.prototype, "executeQuery"); restStub.returns({ data: { error: { response: { data: "error" } } } }); await wrapper.vm.confirmApproval(); expect(wrapper.vm.approvalRequiredProcessed.length).toBe(1); @@ -220,7 +214,6 @@ describe("Curator -> UserRecordsAwaitingApproval.vue", () => { it("can delete a record", async () => { //There is an error in the Client query wrapper.vm.dialogs.recordID = 102; - restStub = sinon.stub(Client.prototype, "executeQuery"); restStub.returns({ data: { error: { response: { data: "error" } } } }); await wrapper.vm.confirmDelete(); expect(wrapper.vm.approvalRequiredProcessed.length).toBe(1); @@ -230,8 +223,6 @@ describe("Curator -> UserRecordsAwaitingApproval.vue", () => { //Correct deleted wrapper.vm.dialogs.recordID = 102; - restStub.restore(); - restStub = sinon.stub(Client.prototype, "executeQuery"); restStub.returns({ data: { error: false } }); await wrapper.vm.confirmDelete(); expect(wrapper.vm.approvalRequiredProcessed.length).toBe(0); diff --git a/tests/unit/components/Editor/DataAccess/EditDataAccess.spec.js b/tests/unit/components/Editor/DataAccess/EditDataAccess.spec.js index 8f484e8eab..39a119533f 100644 --- a/tests/unit/components/Editor/DataAccess/EditDataAccess.spec.js +++ b/tests/unit/components/Editor/DataAccess/EditDataAccess.spec.js @@ -165,6 +165,8 @@ describe("Edit -> DataAccess.vue", function () { it("handles save and exit with redirect", async () => { const btn = { textContent: "Save and exit" }; const pushCalls = $router.push.mock.calls.length; + restStub = sinon.stub(RestClient.prototype, "executeQuery"); + restStub.returns({ data: "GG!" }); await wrapper.vm.saveRecord(true, btn); expect($router.push).toHaveBeenCalledTimes(pushCalls + 1); }); diff --git a/tests/unit/components/Navigation/Header.spec.js b/tests/unit/components/Navigation/Header.spec.js index 5a587035a9..fa97f0dad7 100644 --- a/tests/unit/components/Navigation/Header.spec.js +++ b/tests/unit/components/Navigation/Header.spec.js @@ -4,6 +4,7 @@ import {createVuetify} from "vuetify"; import Vuex from "vuex"; import Header from "@/components/Navigation/Header.vue"; +import RESTClient from "@/lib/Client/RESTClient.js"; import uiControllerStore from "@/store/uiController.js"; import usersStore from "@/store/users.js"; @@ -120,6 +121,9 @@ describe("Header.vue", function () { it("logs out and redirects to Login", async () => { const push = vi.fn(); + const logoutSpy = vi + .spyOn(RESTClient.prototype, "logout") + .mockResolvedValue({ error: false }); const localStore = new Vuex.Store({ modules: { @@ -143,5 +147,6 @@ describe("Header.vue", function () { await localWrapper.vm.logoutUser(); expect(push).toHaveBeenCalledWith({ name: "Login" }); + logoutSpy.mockRestore(); }); }); diff --git a/tests/unit/components/Records/Record/GeneralInfo/DOITitle.spec.js b/tests/unit/components/Records/Record/GeneralInfo/DOITitle.spec.js index 9ab6ff76ff..29fe04f424 100644 --- a/tests/unit/components/Records/Record/GeneralInfo/DOITitle.spec.js +++ b/tests/unit/components/Records/Record/GeneralInfo/DOITitle.spec.js @@ -37,7 +37,9 @@ describe("DOITitle.vue", function () { readAsDataURL, target: fileContents, }; - window.Image = vi.fn(() => dummyFileReader); + window.Image = vi.fn(function () { + return dummyFileReader; + }); }); it("can be instantiated", async () => { diff --git a/tests/unit/components/Records/Record/GeneralInfo/SavedSearches.spec.js b/tests/unit/components/Records/Record/GeneralInfo/SavedSearches.spec.js index 4afdcd90ec..4d66d1e09c 100644 --- a/tests/unit/components/Records/Record/GeneralInfo/SavedSearches.spec.js +++ b/tests/unit/components/Records/Record/GeneralInfo/SavedSearches.spec.js @@ -33,9 +33,11 @@ const { mockUpdateSaveSearch } = vi.hoisted(() => { // Now Vitest can safely use it here! vi.mock("@/lib/Client/RESTClient.js", () => ({ - default: vi.fn().mockImplementation(() => ({ - updateSaveSearch: mockUpdateSaveSearch, - })), + default: vi.fn(function () { + return { + updateSaveSearch: mockUpdateSaveSearch, + }; + }), })); describe("SavedSearches.vue", () => { diff --git a/tests/unit/components/Records/Search/SaveSearch/SaveSearchStepper.spec.js b/tests/unit/components/Records/Search/SaveSearch/SaveSearchStepper.spec.js index 74507fdc0c..b6f1f75b6f 100644 --- a/tests/unit/components/Records/Search/SaveSearch/SaveSearchStepper.spec.js +++ b/tests/unit/components/Records/Search/SaveSearch/SaveSearchStepper.spec.js @@ -11,9 +11,11 @@ const { mockSaveSearchAPI } = vi.hoisted(() => ({ vi.mock("@/lib/Client/RESTClient", () => { return { - default: vi.fn(() => ({ - saveSearch: mockSaveSearchAPI, - })), + default: vi.fn(function () { + return { + saveSearch: mockSaveSearchAPI, + }; + }), }; }); diff --git a/tests/unit/components/Records/Search/SaveSearch/StepperComponents/PolicyStepper.spec.js b/tests/unit/components/Records/Search/SaveSearch/StepperComponents/PolicyStepper.spec.js index 1c4a5c7791..7e9c10633f 100644 --- a/tests/unit/components/Records/Search/SaveSearch/StepperComponents/PolicyStepper.spec.js +++ b/tests/unit/components/Records/Search/SaveSearch/StepperComponents/PolicyStepper.spec.js @@ -48,6 +48,9 @@ describe("PolicyStepper.vue", () => { }, saveSearch: { namespaced: true, + mutations: { + setPolicySelected: vi.fn(), + }, getters: { getPolicyRecords: getters.getPolicyRecords, getLoadingStatus: getters.getLoadingStatus, diff --git a/tests/unit/components/Users/Profiles/Private/ViewSavedSearchesTable.spec.js b/tests/unit/components/Users/Profiles/Private/ViewSavedSearchesTable.spec.js index 764784a4f3..724d153c46 100644 --- a/tests/unit/components/Users/Profiles/Private/ViewSavedSearchesTable.spec.js +++ b/tests/unit/components/Users/Profiles/Private/ViewSavedSearchesTable.spec.js @@ -13,10 +13,12 @@ const { mockDelete, mockUpdate } = vi.hoisted(() => { vi.mock("@/lib/Client/RESTClient", () => { return { - default: vi.fn(() => ({ - deleteSavedSearch: mockDelete, - updateSaveSearch: mockUpdate, - })), + default: vi.fn(function () { + return { + deleteSavedSearch: mockDelete, + updateSaveSearch: mockUpdate, + }; + }), }; }); diff --git a/tests/unit/lib/GraphClient/GraphClientSEO.spec.js b/tests/unit/lib/GraphClient/GraphClientSEO.spec.js new file mode 100644 index 0000000000..5dda924373 --- /dev/null +++ b/tests/unit/lib/GraphClient/GraphClientSEO.spec.js @@ -0,0 +1,91 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import axios from "axios"; +import GraphClientSEO from "@/lib/GraphClient/GraphClientSEO.js"; + +vi.mock("axios", () => ({ + default: vi.fn(), +})); + +describe("GraphClientSEO", () => { + let client; + + beforeEach(() => { + GraphClientSEO._instance = undefined; + process.env.VITE_API_ENDPOINT = "https://api.example.org/"; + process.env.VITE_CLIENT_ID = "client-id"; + axios.mockReset(); + client = new GraphClientSEO(); + }); + + it("initializes headers, normalizes the endpoint, and remains a singleton", () => { + expect(client.url).toBe("https://api.example.org/graphql"); + expect(client.headers["X-Client-Id"]).toBe("client-id"); + expect(new GraphClientSEO()).toBe(client); + + client.setHeader("token"); + expect(client.headers.Authorization).toBe("Bearer token"); + }); + + it("omits the optional client ID header", () => { + GraphClientSEO._instance = undefined; + delete process.env.VITE_CLIENT_ID; + + const clientWithoutId = new GraphClientSEO(); + + expect(clientWithoutId.headers).not.toHaveProperty("X-Client-Id"); + }); + + it("builds parameters, fragments, and nested fields", () => { + const query = { + queryName: "records", + queryParam: { + active: true, + page: 2, + name: "Example", + filter: '{status: "ready"}', + ids: [1, "two"], + }, + fields: [ + "id", + { $ref: "keywords" }, + { $ref: "objectTypes" }, + { + name: "owner", + fields: ["name", { queryName: "profile", fields: ["id"] }], + }, + ], + }; + + const output = client.buildQuery(query); + + expect(output).toContain("records("); + expect(output).toContain("active:true"); + expect(output).toContain("page:2"); + expect(output).toContain('name:"Example"'); + expect(output).toContain('filter:{status: "ready"}'); + expect(output).toContain('ids:[1,"two"]'); + expect(output).toContain("owner{name profile{ id}}"); + expect(output).toContain("objectTypes{"); + expect(client.buildQuery({ queryName: "ping" })).toBe("ping"); + }); + + it("posts queries and returns GraphQL data or errors", async () => { + axios.mockResolvedValueOnce({ data: { data: { records: [1] } } }); + + await expect( + client.executeQuery({ queryName: "records", fields: ["id"] }), + ).resolves.toEqual({ records: [1] }); + expect(axios).toHaveBeenCalledWith({ + method: "post", + url: "https://api.example.org/graphql", + data: { query: "{records{ id}}" }, + headers: client.headers, + }); + + axios.mockResolvedValueOnce({ data: { errors: [{ message: "bad query" }] } }); + await expect(client.executeQuery({ queryName: "broken" })).resolves.toEqual([ + { message: "bad query" }, + ]); + }); +}); diff --git a/tests/unit/lib/Prerender/prerenderUtils.spec.js b/tests/unit/lib/Prerender/prerenderUtils.spec.js new file mode 100644 index 0000000000..3c6f95a979 --- /dev/null +++ b/tests/unit/lib/Prerender/prerenderUtils.spec.js @@ -0,0 +1,74 @@ +// @vitest-environment node + +import fs from "node:fs"; +import path from "node:path"; +import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; + +const mockPaths = vi.hoisted(() => { + const root = "/tmp/fairsharing-prerender-utils-tests"; + return { + root, + records: `${root}/records.json`, + organisations: `${root}/organisations.json`, + jsonld: `${root}/jsonld`, + }; +}); + +vi.mock("@/lib/Prerender/build-context.json", () => ({ + default: { + recordsFile: mockPaths.records, + organisationsFile: mockPaths.organisations, + jsonldDir: mockPaths.jsonld, + }, +})); + +import { + readGeneratedOrganisations, + readGeneratedRecords, + readGeneratedSchemaOrg, +} from "@/lib/Prerender/prerenderUtils.server.js"; +import { normalizeDoi } from "@/lib/Prerender/prerenderUtils.shared.js"; + +describe("prerender utilities", () => { + beforeAll(() => { + fs.mkdirSync(mockPaths.jsonld, { recursive: true }); + fs.writeFileSync(mockPaths.records, JSON.stringify([{ id: 1 }])); + fs.writeFileSync( + mockPaths.organisations, + JSON.stringify([{ id: 2, name: "Example" }]), + ); + fs.writeFileSync( + path.join(mockPaths.jsonld, "1.jsonld"), + JSON.stringify({ "@type": "Dataset" }), + ); + }); + + afterAll(() => { + fs.rmSync(mockPaths.root, { recursive: true, force: true }); + }); + + it("reads generated records, organisations, and schema.org data", () => { + expect(readGeneratedRecords()).toEqual([{ id: 1 }]); + expect(readGeneratedOrganisations()).toEqual([{ id: 2, name: "Example" }]); + expect(readGeneratedSchemaOrg(1)).toEqual({ "@type": "Dataset" }); + }); + + it("returns the schema fallback when a generated file is absent", () => { + const warning = vi.spyOn(console, "warn").mockImplementation(() => {}); + + expect(readGeneratedSchemaOrg("missing")).toBeNull(); + expect(warning).toHaveBeenCalledWith( + expect.stringContaining("missing.jsonld"), + ); + + warning.mockRestore(); + }); + + it.each([ + [" https://doi.org/10.1234/example/ ", "10.1234/example"], + ["http://dx.doi.org/10.1234%2Fencoded", "10.1234/encoded"], + ["doi:/10.1234/example/", "10.1234/example"], + ])("normalizes DOI value %s", (input, expected) => { + expect(normalizeDoi(input)).toBe(expected); + }); +}); diff --git a/tests/unit/pages/data.spec.js b/tests/unit/pages/data.spec.js new file mode 100644 index 0000000000..f9115ec730 --- /dev/null +++ b/tests/unit/pages/data.spec.js @@ -0,0 +1,119 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const fixtures = vi.hoisted(() => ({ + records: [ + { + id: 1, + doi: "10.1234/example", + name: "Example record", + description: "Record description", + }, + { id: 2, doi: "", name: "Second record", description: "" }, + { id: "invalid", doi: "10.1234/other", name: "Other record" }, + ], + organisations: [ + { id: 1, name: "First organisation" }, + { id: 2, name: "Second organisation" }, + ], + schemaOrg: { "@type": "Dataset" }, +})); + +vi.mock("@/lib/Prerender/build-context.json", () => ({ + default: { skipFull: false, batch: 1, batchSize: 2 }, +})); +vi.mock("@/lib/Prerender/prerenderUtils.server.js", () => ({ + readGeneratedRecords: vi.fn(async () => fixtures.records), + readGeneratedOrganisations: vi.fn(async () => fixtures.organisations), + readGeneratedSchemaOrg: vi.fn(() => fixtures.schemaOrg), +})); + +import { data as recordData } from "@/pages/all/+data.js"; +import { onBeforePrerenderStart } from "@/pages/all/+onBeforePrerenderStart.js"; +import { data as organisationsData } from "@/pages/organisations/+data.js"; +import { data as organisationData } from "@/pages/organisations/@id/+data.js"; + +describe("prerender page data", () => { + beforeEach(() => { + vi.stubEnv("SSR", true); + }); + + it("returns empty metadata for empty and unknown record routes", async () => { + await expect( + recordData({ routeParams: { "*": "index" } }), + ).resolves.toMatchObject({ record: null, schemaOrg: null }); + await expect( + recordData({ routeParams: { "*": "not-found" } }), + ).resolves.toMatchObject({ record: null, canonicalUrl: null }); + }); + + it("finds numeric and DOI record routes and builds canonical metadata", async () => { + const numeric = await recordData({ routeParams: { "*": "1" } }); + const doiAlias = await recordData({ routeParams: { "*": "example" } }); + + expect(numeric).toMatchObject({ + record: fixtures.records[0], + schemaOrg: fixtures.schemaOrg, + canonicalUrl: "https://fairsharing.org/10.1234/example", + seoTitle: "Example record | FAIRsharing", + seoDescription: "Record description", + }); + expect(doiAlias.record).toEqual(fixtures.records[0]); + }); + + it("returns record-only data in the browser", async () => { + vi.stubEnv("SSR", false); + + await expect(recordData({ routeParams: { "*": "2" } })).resolves.toEqual({ + record: fixtures.records[1], + schemaOrg: null, + }); + }); + + it("builds unique static, record, DOI, and organisation prerender routes", async () => { + const log = vi.spyOn(console, "log").mockImplementation(() => {}); + const routes = await onBeforePrerenderStart(); + + expect(routes).toContain("/"); + expect(routes).toContain("/1"); + expect(routes).toContain("/10.1234/example"); + expect(routes).toContain("/example"); + expect(routes).toContain("/2"); + expect(routes).toContain("/organisations/2"); + expect(new Set(routes).size).toBe(routes.length); + expect(log).toHaveBeenCalledWith(expect.stringContaining("Building Batch #1")); + + log.mockRestore(); + }); + + it("logs when a batch contains no record routes", async () => { + const records = [...fixtures.records]; + const organisations = [...fixtures.organisations]; + fixtures.records.splice(0); + fixtures.organisations.splice(0); + const log = vi.spyOn(console, "log").mockImplementation(() => {}); + + const routes = await onBeforePrerenderStart(); + + expect(routes).toContain("/"); + expect(log).toHaveBeenCalledWith("No records found for batch #1."); + + fixtures.records.push(...records); + fixtures.organisations.push(...organisations); + log.mockRestore(); + }); + + it("returns organisation collections and selects an organisation by ID", async () => { + await expect(organisationsData()).resolves.toEqual({ + organisations: fixtures.organisations, + }); + await expect( + organisationData({ routeParams: { id: "2" } }), + ).resolves.toEqual({ organisation: fixtures.organisations[1] }); + await expect( + organisationData({ routeParams: {} }), + ).resolves.toEqual({ organisation: null }); + await expect( + organisationData({ routeParams: { id: "99" } }), + ).resolves.toEqual({ organisation: null }); + }); +}); diff --git a/tests/unit/pages/indexData.spec.js b/tests/unit/pages/indexData.spec.js new file mode 100644 index 0000000000..e0e0786cf8 --- /dev/null +++ b/tests/unit/pages/indexData.spec.js @@ -0,0 +1,47 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const mocks = vi.hoisted(() => ({ + getHomepageJsonld: vi.fn(), + setConfig: vi.fn(), +})); + +vi.mock("@/lib/Client/RESTClient.js", () => ({ + default: vi.fn(function () { + return { getHomepageJsonld: mocks.getHomepageJsonld }; + }), +})); +vi.mock("vike-vue/useConfig", () => ({ + useConfig: () => mocks.setConfig, +})); + +import { data } from "@/pages/index/+data.js"; + +describe("homepage data", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("adds non-empty schema.org data to the page head", async () => { + mocks.getHomepageJsonld.mockResolvedValue({ + "@type": "WebSite", + description: "", + }); + + const result = await data(); + const head = mocks.setConfig.mock.calls[0][0].Head; + + expect(result.JSONLD).toEqual({ + "@type": "WebSite", + description: "", + }); + expect(head.type).toBe("script"); + expect(head.props.innerHTML).toContain("\\u003cunsafe>"); + }); + + it("returns null and leaves the head unchanged without schema.org data", async () => { + mocks.getHomepageJsonld.mockResolvedValue(null); + + await expect(data()).resolves.toEqual({ JSONLD: null }); + expect(mocks.setConfig).not.toHaveBeenCalled(); + }); +}); diff --git a/tests/unit/pages/metadata.spec.js b/tests/unit/pages/metadata.spec.js new file mode 100644 index 0000000000..2396dbe63f --- /dev/null +++ b/tests/unit/pages/metadata.spec.js @@ -0,0 +1,162 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const pageData = vi.hoisted(() => ({ current: {} })); + +vi.mock("vike-vue/useData", () => ({ + useData: () => pageData.current, +})); +vi.mock("vike-vue/config", () => ({ default: { name: "vike-vue" } })); +vi.mock("@/pages/+Layout.vue", () => ({ default: { name: "Layout" } })); + +import config from "@/pages/+config.js"; +import Head from "@/pages/all/+Head.js"; +import description from "@/pages/all/+description.js"; +import route from "@/pages/all/+route.js"; +import title from "@/pages/all/+title.js"; +import organisationDescription from "@/pages/organisations/@id/+description.js"; +import organisationTitle from "@/pages/organisations/@id/+title.js"; + +describe("page metadata", () => { + beforeEach(() => { + pageData.current = {}; + }); + + it("exports the root Vike configuration and catch-all route", () => { + expect(config.extends).toEqual([{ name: "vike-vue" }]); + expect(config.Layout).toEqual({ name: "Layout" }); + expect(config.ssr).toBe(true); + expect(config.prerender).toMatchObject({ partial: true, parallel: false }); + expect(route).toBe("/*"); + }); + + it("does not create record head elements without a record", () => { + expect(Head()).toBeNull(); + }); + + it("creates canonical, Open Graph, and escaped schema.org head elements", () => { + pageData.current = { + record: { + doi: "10.1234/example", + name: "Example record", + description: "Description ", + }, + schemaOrg: { "@context": "https://schema.org", ignoredName: "old" }, + canonicalUrl: "https://fairsharing.org/10.1234/example", + seoTitle: "Example record | FAIRsharing", + seoDescription: "Example description", + }; + + const elements = Head(); + const script = elements.find((element) => element.type === "script"); + + expect(elements).toHaveLength(7); + expect(elements.find((element) => element.type === "title").children).toBe( + "Example record | FAIRsharing", + ); + expect(script.props.innerHTML).toContain("\\u003cunsafe>"); + expect(script.props.innerHTML).toContain( + '"url":"https://fairsharing.org/10.1234/example"', + ); + }); + + it("filters optional head elements and schema when values are absent", () => { + pageData.current = { record: { name: "Minimal" } }; + + expect(Head()).toEqual([]); + }); + + it("uses schema.org fallbacks when DOI and description are absent", () => { + pageData.current = { + record: { name: "Minimal" }, + schemaOrg: { "@context": "https://schema.org" }, + canonicalUrl: "https://fairsharing.org/1", + }; + + const script = Head().find((element) => element.type === "script"); + const schema = JSON.parse(script.props.innerHTML); + + expect(schema.identifier).toEqual([]); + expect(schema.description).toBe(""); + }); + + it("returns record, static, search, and fallback titles", () => { + expect( + title({ urlPathname: "/anything", data: { record: { name: "Record" } } }), + ).toBe("Record | FAIRsharing"); + expect(title({ urlPathname: "/privacy" })).toBe( + "Privacy Policy | FAIRsharing", + ); + expect( + title({ + urlPathname: "/search", + urlParsed: { search: "?fairsharingRegistry=DATABASE" }, + }), + ).toBe("Databases | FAIRsharing"); + expect( + title({ + urlPathname: "/search", + urlParsed: { search: "?fairsharingRegistry=unknown" }, + }), + ).toBe("Search | FAIRsharing"); + expect(title({ urlPathname: "/unknown" })).toBe("FAIRsharing"); + }); + + it("returns record, static, search, and fallback descriptions", () => { + expect( + description({ + urlPathname: "/anything", + data: { record: { name: "Record", description: "Record description" } }, + }), + ).toBe("Record description"); + expect( + description({ + urlPathname: "/anything", + data: { record: { name: "Record" } }, + }), + ).toContain("Record"); + expect(description({ urlPathname: "/organisations" })).toBe( + "List of Organisations", + ); + expect( + description({ + urlPathname: "/search", + urlParsed: { search: "?fairsharingRegistry=POLICY" }, + }), + ).toContain("data preservation"); + expect(description({ urlPathname: "/search" })).toContain( + "advanced filtering", + ); + expect( + description({ + urlPathname: "/search", + urlParsed: { search: "?fairsharingRegistry=unknown" }, + }), + ).toContain("advanced filtering"); + expect(description({ urlPathname: "/unknown" })).toContain( + "A curated, informative", + ); + }); + + it("creates organisation titles and descriptions with fallbacks", () => { + const context = { + data: { + organisation: { + name: "Example Organisation", + homepage: "https://example.org", + }, + }, + }; + + expect(organisationTitle(context)).toBe( + "Example Organisation | FAIRsharing", + ); + expect(organisationDescription(context)).toBe("https://example.org"); + expect( + organisationDescription({ + data: { organisation: { name: "No homepage", length: 1 } }, + }), + ).toContain("1 organisations available"); + expect(organisationTitle({})).toBe("Organisations | FAIRsharing"); + expect(organisationDescription({})).toContain("A curated, informative"); + }); +}); diff --git a/tests/unit/pages/onCreateApp.spec.js b/tests/unit/pages/onCreateApp.spec.js new file mode 100644 index 0000000000..bceb07e3f4 --- /dev/null +++ b/tests/unit/pages/onCreateApp.spec.js @@ -0,0 +1,106 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const mocks = vi.hoisted(() => ({ + store: { name: "store" }, + router: { + push: vi.fn(), + isReady: vi.fn().mockResolvedValue(undefined), + }, + bootstrapApp: vi.fn().mockResolvedValue(undefined), + vuetify: { name: "vuetify" }, + metaManager: { name: "meta" }, + sanitize: vi.fn((value) => `clean:${value}`), + accessibilityInit: vi.fn(), + loadFull: vi.fn().mockResolvedValue(undefined), +})); + +vi.mock("@/store", () => ({ createMyStore: () => mocks.store })); +vi.mock("@/router", () => ({ createMyRouter: () => mocks.router })); +vi.mock("@/plugins/vuetify", () => ({ default: () => mocks.vuetify })); +vi.mock("@/utils/setupUtils", () => ({ + bootstrapApp: mocks.bootstrapApp, + globalFilters: { capitalize: vi.fn() }, +})); +vi.mock("vue-meta", () => ({ createMetaManager: () => mocks.metaManager })); +vi.mock("vue-3-sanitize", () => ({ default: { name: "sanitize-plugin" } })); +vi.mock("vue-3-linkify", () => ({ default: { name: "linkify" } })); +vi.mock("dompurify", () => ({ default: { sanitize: mocks.sanitize } })); +vi.mock("@/components/Static/APIDoc/CodeBlock.vue", () => ({ + default: { name: "CodeBlock" }, +})); +vi.mock("highcharts-vue", () => ({ default: { name: "highcharts-vue" } })); +vi.mock("highcharts", () => ({ default: { name: "highcharts" } })); +vi.mock("highcharts/modules/accessibility", () => ({ + default: mocks.accessibilityInit, +})); +vi.mock("simple-analytics-vue", () => ({ default: { name: "analytics" } })); +vi.mock("vue-gtag", () => ({ default: { name: "gtag" } })); +vi.mock("vue-scrollto", () => ({ default: { name: "scroll-to" } })); +vi.mock("@tsparticles/vue3", () => ({ default: { name: "particles" } })); +vi.mock("tsparticles", () => ({ loadFull: mocks.loadFull })); + +import onCreateApp from "@/pages/+onCreateApp.js"; + +function createApp() { + const directives = {}; + const app = { + use: vi.fn(() => app), + component: vi.fn(), + directive: vi.fn((name, handler) => { + directives[name] = handler; + }), + config: { globalProperties: {} }, + }; + return { app, directives }; +} + +describe("onCreateApp", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("initializes the isolated store and router for server rendering", async () => { + vi.stubEnv("SSR", true); + const { app, directives } = createApp(); + + await onCreateApp({ app, urlPathname: "/privacy" }); + + expect(app.use).toHaveBeenCalledWith(mocks.store); + expect(app.use).toHaveBeenCalledWith(mocks.router); + expect(mocks.bootstrapApp).toHaveBeenCalledWith(mocks.store, mocks.router); + expect(mocks.router.push).toHaveBeenCalledWith("/privacy"); + expect(mocks.router.isReady).toHaveBeenCalled(); + expect(app.component).toHaveBeenCalledWith( + "CodeBlock", + expect.objectContaining({ name: "CodeBlock" }), + ); + + const element = { innerHTML: "" }; + directives["safe-html"](element, { value: "