@cccsaurora/howler-ui 3.1.0-dev.1656 → 3.1.0-dev.1675
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/api/action/execute.test.d.ts +1 -0
- package/api/action/execute.test.js +38 -0
- package/api/action/index.test.d.ts +1 -0
- package/api/action/index.test.js +59 -0
- package/api/action/operations.test.d.ts +1 -0
- package/api/action/operations.test.js +23 -0
- package/api/analytic/comments/index.test.d.ts +1 -0
- package/api/analytic/comments/index.test.js +43 -0
- package/api/analytic/comments/react.test.d.ts +1 -0
- package/api/analytic/comments/react.test.js +27 -0
- package/api/analytic/favourite.test.d.ts +1 -0
- package/api/analytic/favourite.test.js +20 -0
- package/api/analytic/index.test.d.ts +1 -0
- package/api/analytic/index.test.js +54 -0
- package/api/analytic/notebooks/index.test.d.ts +1 -0
- package/api/analytic/notebooks/index.test.js +31 -0
- package/api/analytic/owner.test.d.ts +1 -0
- package/api/analytic/owner.test.js +25 -0
- package/api/auth/apikey.test.d.ts +1 -0
- package/api/auth/apikey.test.js +34 -0
- package/api/auth/index.test.d.ts +1 -0
- package/api/auth/index.test.js +21 -0
- package/api/auth/login.test.d.ts +1 -0
- package/api/auth/login.test.js +53 -0
- package/api/configs/index.test.d.ts +1 -0
- package/api/configs/index.test.js +22 -0
- package/api/dossier/index.test.d.ts +1 -0
- package/api/dossier/index.test.js +57 -0
- package/api/help.test.d.ts +1 -0
- package/api/help.test.js +25 -0
- package/api/hit/assign.test.d.ts +1 -0
- package/api/hit/assign.test.js +22 -0
- package/api/hit/comments/index.test.d.ts +1 -0
- package/api/hit/comments/index.test.js +47 -0
- package/api/hit/comments/react.test.d.ts +1 -0
- package/api/hit/comments/react.test.js +27 -0
- package/api/hit/index.test.d.ts +1 -0
- package/api/hit/index.test.js +49 -0
- package/api/hit/labels.test.d.ts +1 -0
- package/api/hit/labels.test.js +29 -0
- package/api/hit/overwrite.test.d.ts +1 -0
- package/api/hit/overwrite.test.js +23 -0
- package/api/hit/transition.test.d.ts +1 -0
- package/api/hit/transition.test.js +24 -0
- package/api/index.test.d.ts +1 -0
- package/api/index.test.js +137 -0
- package/api/notebook/environments.test.d.ts +1 -0
- package/api/notebook/environments.test.js +22 -0
- package/api/notebook/index.test.d.ts +1 -0
- package/api/notebook/index.test.js +28 -0
- package/api/overview/index.test.d.ts +1 -0
- package/api/overview/index.test.js +42 -0
- package/api/search/fields/index.test.d.ts +1 -0
- package/api/search/fields/index.test.js +31 -0
- package/api/search/grouped/index.test.d.ts +1 -0
- package/api/search/grouped/index.test.js +18 -0
- package/api/search/grouped/user.test.d.ts +1 -0
- package/api/search/grouped/user.test.js +33 -0
- package/api/search/index.test.d.ts +1 -0
- package/api/search/index.test.js +41 -0
- package/api/search/user.test.d.ts +1 -0
- package/api/search/user.test.js +41 -0
- package/api/socket/index.test.d.ts +1 -0
- package/api/socket/index.test.js +15 -0
- package/api/template/index.test.d.ts +1 -0
- package/api/template/index.test.js +43 -0
- package/api/user/avatar/index.test.d.ts +1 -0
- package/api/user/avatar/index.test.js +22 -0
- package/api/user/groups.test.d.ts +1 -0
- package/api/user/groups.test.js +22 -0
- package/api/user/index.test.d.ts +1 -0
- package/api/user/index.test.js +37 -0
- package/api/user/whoami.test.d.ts +1 -0
- package/api/user/whoami.test.js +26 -0
- package/api/utils/createPermissionsApi.test.d.ts +1 -0
- package/api/utils/createPermissionsApi.test.js +30 -0
- package/api/v2/case/index.test.d.ts +1 -0
- package/api/v2/case/index.test.js +57 -0
- package/api/v2/case/items.test.d.ts +1 -0
- package/api/v2/case/items.test.js +37 -0
- package/api/v2/case/rules.test.d.ts +1 -0
- package/api/v2/case/rules.test.js +33 -0
- package/api/v2/fuzzy.test.d.ts +1 -0
- package/api/v2/fuzzy.test.js +30 -0
- package/api/v2/index.test.d.ts +1 -0
- package/api/v2/index.test.js +13 -0
- package/api/v2/search/index.test.d.ts +1 -0
- package/api/v2/search/index.test.js +42 -0
- package/api/view/index.test.d.ts +1 -0
- package/api/view/index.test.js +54 -0
- package/branding/AppBrand.test.d.ts +1 -0
- package/branding/AppBrand.test.js +29 -0
- package/components/app/drawers/ApiKeyDrawer.test.d.ts +1 -0
- package/components/app/drawers/ApiKeyDrawer.test.js +119 -0
- package/components/app/drawers/AssignUserDrawer.test.d.ts +1 -0
- package/components/app/drawers/AssignUserDrawer.test.js +75 -0
- package/components/app/hooks/useTitle.test.d.ts +1 -0
- package/components/app/hooks/useTitle.test.js +103 -0
- package/components/app/providers/AnalyticProvider.test.d.ts +1 -0
- package/components/app/providers/AnalyticProvider.test.js +58 -0
- package/components/app/providers/AppBarProvider.test.d.ts +1 -0
- package/components/app/providers/AppBarProvider.test.js +23 -0
- package/components/app/providers/AppDrawerProvider.test.d.ts +1 -0
- package/components/app/providers/AppDrawerProvider.test.js +42 -0
- package/components/app/providers/AvatarProvider.test.d.ts +1 -0
- package/components/app/providers/AvatarProvider.test.js +50 -0
- package/components/app/providers/CustomPluginProvider.test.d.ts +1 -0
- package/components/app/providers/CustomPluginProvider.test.js +29 -0
- package/components/app/providers/FavouritesProvider.test.d.ts +1 -0
- package/components/app/providers/FavouritesProvider.test.js +115 -0
- package/components/app/providers/FieldProvider.test.d.ts +1 -0
- package/components/app/providers/FieldProvider.test.js +28 -0
- package/components/app/providers/LocalStorageProvider.test.d.ts +1 -0
- package/components/app/providers/LocalStorageProvider.test.js +42 -0
- package/components/app/providers/ModalProvider.test.d.ts +1 -0
- package/components/app/providers/ModalProvider.test.js +35 -0
- package/components/app/providers/OverviewProvider.test.d.ts +1 -0
- package/components/app/providers/OverviewProvider.test.js +62 -0
- package/components/app/providers/RecordProvider.test.d.ts +1 -0
- package/components/app/providers/RecordProvider.test.js +66 -0
- package/components/app/providers/contextUtils.test.d.ts +1 -0
- package/components/app/providers/contextUtils.test.js +8 -0
- package/components/elements/Comment.test.d.ts +1 -0
- package/components/elements/Comment.test.js +109 -0
- package/components/elements/EditRow.test.d.ts +1 -0
- package/components/elements/EditRow.test.js +88 -0
- package/components/elements/MarkdownEditor.test.d.ts +1 -0
- package/components/elements/MarkdownEditor.test.js +75 -0
- package/components/elements/ObjectDetails.test.d.ts +1 -0
- package/components/elements/ObjectDetails.test.js +70 -0
- package/components/elements/PluginChip.d.ts +3 -2
- package/components/elements/PluginChip.js +2 -2
- package/components/elements/PluginChip.test.d.ts +1 -0
- package/components/elements/PluginChip.test.js +30 -0
- package/components/elements/ThemedEditor.test.d.ts +1 -0
- package/components/elements/ThemedEditor.test.js +66 -0
- package/components/elements/addons/layout/FlexPort.test.d.ts +1 -0
- package/components/elements/addons/layout/FlexPort.test.js +34 -0
- package/components/elements/addons/lists/TuiListBase.test.d.ts +1 -0
- package/components/elements/addons/lists/TuiListBase.test.js +44 -0
- package/components/elements/addons/lists/TuiListProvider.test.d.ts +1 -0
- package/components/elements/addons/lists/TuiListProvider.test.js +50 -0
- package/components/elements/addons/search/phrase/Phrase.test.d.ts +1 -0
- package/components/elements/addons/search/phrase/Phrase.test.js +77 -0
- package/components/elements/addons/search/phrase/PhraseLexer.test.d.ts +1 -0
- package/components/elements/addons/search/phrase/PhraseLexer.test.js +92 -0
- package/components/elements/addons/search/phrase/index.test.d.ts +1 -0
- package/components/elements/addons/search/phrase/index.test.js +20 -0
- package/components/elements/case/CaseCard.test.d.ts +1 -0
- package/components/elements/case/CaseCard.test.js +107 -0
- package/components/elements/display/ClassificationChip.test.d.ts +1 -0
- package/components/elements/display/ClassificationChip.test.js +60 -0
- package/components/elements/display/HandlebarsMarkdown.test.d.ts +1 -0
- package/components/elements/display/HandlebarsMarkdown.test.js +41 -0
- package/components/elements/display/HowlerAvatar.test.d.ts +1 -0
- package/components/elements/display/HowlerAvatar.test.js +54 -0
- package/components/elements/display/ItemManager.test.d.ts +1 -0
- package/components/elements/display/ItemManager.test.js +68 -0
- package/components/elements/display/UserPageWrapper.test.d.ts +1 -0
- package/components/elements/display/UserPageWrapper.test.js +22 -0
- package/components/elements/display/handlebars/helpers.test.d.ts +1 -0
- package/components/elements/display/handlebars/helpers.test.js +104 -0
- package/components/elements/display/icons/SocketBadge.test.d.ts +1 -0
- package/components/elements/display/icons/SocketBadge.test.js +49 -0
- package/components/elements/display/markdownPlugins/tabs.test.d.ts +1 -0
- package/components/elements/display/markdownPlugins/tabs.test.js +50 -0
- package/components/elements/hit/HitActions.js +1 -1
- package/components/elements/hit/HitActions.test.d.ts +1 -0
- package/components/elements/hit/HitActions.test.js +166 -0
- package/components/elements/hit/HitLabels.test.js +34 -3
- package/components/elements/hit/HitNotebooks.test.d.ts +1 -0
- package/components/elements/hit/HitNotebooks.test.js +138 -0
- package/components/elements/hit/HitSummary.test.d.ts +1 -0
- package/components/elements/hit/HitSummary.test.js +188 -0
- package/components/elements/hit/actions/ButtonActions.test.d.ts +1 -0
- package/components/elements/hit/actions/ButtonActions.test.js +51 -0
- package/components/elements/hit/actions/DropdownActions.test.d.ts +1 -0
- package/components/elements/hit/actions/DropdownActions.test.js +60 -0
- package/components/elements/hit/grid/AddColumnModal.test.d.ts +1 -0
- package/components/elements/hit/grid/AddColumnModal.test.js +88 -0
- package/components/elements/hit/grid/RecordTable.test.d.ts +1 -0
- package/components/elements/hit/grid/RecordTable.test.js +99 -0
- package/components/elements/record/RecordComments.test.d.ts +1 -0
- package/components/elements/record/RecordComments.test.js +151 -0
- package/components/elements/record/RecordRelated.test.d.ts +1 -0
- package/components/elements/record/RecordRelated.test.js +77 -0
- package/components/elements/record/RecordWorklog.test.d.ts +1 -0
- package/components/elements/record/RecordWorklog.test.js +77 -0
- package/components/hooks/useHitActions.test.d.ts +1 -0
- package/components/hooks/useHitActions.test.js +189 -0
- package/components/hooks/useMyApi.test.d.ts +1 -0
- package/components/hooks/useMyApi.test.js +31 -0
- package/components/hooks/useMyChart.test.d.ts +1 -0
- package/components/hooks/useMyChart.test.js +62 -0
- package/components/hooks/useMySearch.test.d.ts +1 -0
- package/components/hooks/useMySearch.test.js +96 -0
- package/components/hooks/useMySnackbar.test.d.ts +1 -0
- package/components/hooks/useMySnackbar.test.js +36 -0
- package/components/hooks/useMyUserFunctions.test.d.ts +1 -0
- package/components/hooks/useMyUserFunctions.test.js +142 -0
- package/components/hooks/useRecordSelection.test.d.ts +1 -0
- package/components/hooks/useRecordSelection.test.js +102 -0
- package/components/logins/Login.test.d.ts +1 -0
- package/components/logins/Login.test.js +67 -0
- package/components/logins/hooks/useLogin.test.d.ts +1 -0
- package/components/logins/hooks/useLogin.test.js +142 -0
- package/components/routes/action/shared/OperationEntry.test.d.ts +1 -0
- package/components/routes/action/shared/OperationEntry.test.js +80 -0
- package/components/routes/action/shared/OperationStep.test.d.ts +1 -0
- package/components/routes/action/shared/OperationStep.test.js +84 -0
- package/components/routes/action/useMyActionFunctions.test.d.ts +1 -0
- package/components/routes/action/useMyActionFunctions.test.js +217 -0
- package/components/routes/action/view/ActionDetails.test.d.ts +1 -0
- package/components/routes/action/view/ActionDetails.test.js +170 -0
- package/components/routes/action/view/ActionSearch.test.d.ts +1 -0
- package/components/routes/action/view/ActionSearch.test.js +185 -0
- package/components/routes/action/view/Integrations.test.d.ts +1 -0
- package/components/routes/action/view/Integrations.test.js +62 -0
- package/components/routes/admin/users/UserEditor.test.d.ts +1 -0
- package/components/routes/admin/users/UserEditor.test.js +74 -0
- package/components/routes/admin/users/UserSearch.test.d.ts +1 -0
- package/components/routes/admin/users/UserSearch.test.js +146 -0
- package/components/routes/advanced/QueryBuilder.test.d.ts +1 -0
- package/components/routes/advanced/QueryBuilder.test.js +185 -0
- package/components/routes/advanced/QueryEditor.test.d.ts +1 -0
- package/components/routes/advanced/QueryEditor.test.js +130 -0
- package/components/routes/advanced/completionProviders.test.d.ts +1 -0
- package/components/routes/advanced/completionProviders.test.js +144 -0
- package/components/routes/analytics/AnalyticComments.test.d.ts +1 -0
- package/components/routes/analytics/AnalyticComments.test.js +156 -0
- package/components/routes/analytics/AnalyticDetails.test.d.ts +1 -0
- package/components/routes/analytics/AnalyticDetails.test.js +161 -0
- package/components/routes/analytics/AnalyticNotebooks.test.d.ts +1 -0
- package/components/routes/analytics/AnalyticNotebooks.test.js +112 -0
- package/components/routes/analytics/AnalyticOverview.test.d.ts +1 -0
- package/components/routes/analytics/AnalyticOverview.test.js +97 -0
- package/components/routes/analytics/AnalyticOverviews.test.d.ts +1 -0
- package/components/routes/analytics/AnalyticOverviews.test.js +70 -0
- package/components/routes/analytics/AnalyticSearch.test.d.ts +1 -0
- package/components/routes/analytics/AnalyticSearch.test.js +167 -0
- package/components/routes/analytics/AnalyticTemplates.test.d.ts +1 -0
- package/components/routes/analytics/AnalyticTemplates.test.js +63 -0
- package/components/routes/analytics/TriageSettings.test.d.ts +1 -0
- package/components/routes/analytics/TriageSettings.test.js +89 -0
- package/components/routes/analytics/widgets/Assessment.test.d.ts +1 -0
- package/components/routes/analytics/widgets/Assessment.test.js +45 -0
- package/components/routes/analytics/widgets/Created.test.d.ts +1 -0
- package/components/routes/analytics/widgets/Created.test.js +41 -0
- package/components/routes/analytics/widgets/DetectionStatus.test.d.ts +1 -0
- package/components/routes/analytics/widgets/DetectionStatus.test.js +21 -0
- package/components/routes/analytics/widgets/Stacked.test.d.ts +1 -0
- package/components/routes/analytics/widgets/Stacked.test.js +51 -0
- package/components/routes/cases/Cases.test.d.ts +1 -0
- package/components/routes/cases/Cases.test.js +132 -0
- package/components/routes/dossiers/Dossiers.test.d.ts +1 -0
- package/components/routes/dossiers/Dossiers.test.js +150 -0
- package/components/routes/help/ActionDocumentation.test.d.ts +1 -0
- package/components/routes/help/ActionDocumentation.test.js +58 -0
- package/components/routes/help/ActionIntroductionDocumentation.test.d.ts +1 -0
- package/components/routes/help/ActionIntroductionDocumentation.test.js +68 -0
- package/components/routes/help/ApiDocumentation.test.d.ts +1 -0
- package/components/routes/help/ApiDocumentation.test.js +79 -0
- package/components/routes/help/AuthDocumentation.test.d.ts +1 -0
- package/components/routes/help/AuthDocumentation.test.js +34 -0
- package/components/routes/help/ClientDocumentation.test.d.ts +1 -0
- package/components/routes/help/ClientDocumentation.test.js +34 -0
- package/components/routes/help/Help.test.d.ts +1 -0
- package/components/routes/help/Help.test.js +57 -0
- package/components/routes/help/HitBannerDocumentation.test.d.ts +1 -0
- package/components/routes/help/HitBannerDocumentation.test.js +25 -0
- package/components/routes/help/HitDocumentation.test.d.ts +1 -0
- package/components/routes/help/HitDocumentation.test.js +53 -0
- package/components/routes/help/HitLabelsDocumentation.test.d.ts +1 -0
- package/components/routes/help/HitLabelsDocumentation.test.js +17 -0
- package/components/routes/help/HitLinksDocumentation.test.d.ts +1 -0
- package/components/routes/help/HitLinksDocumentation.test.js +27 -0
- package/components/routes/help/HitSchemaDocumentation.test.d.ts +1 -0
- package/components/routes/help/HitSchemaDocumentation.test.js +67 -0
- package/components/routes/help/NotebookDocumentation.test.d.ts +1 -0
- package/components/routes/help/NotebookDocumentation.test.js +34 -0
- package/components/routes/help/OverviewDocumentation.test.d.ts +1 -0
- package/components/routes/help/OverviewDocumentation.test.js +26 -0
- package/components/routes/help/RetentionDocumentation.test.d.ts +1 -0
- package/components/routes/help/RetentionDocumentation.test.js +61 -0
- package/components/routes/help/SearchDocumentation.test.d.ts +1 -0
- package/components/routes/help/SearchDocumentation.test.js +65 -0
- package/components/routes/help/TemplateDocumentation.test.d.ts +1 -0
- package/components/routes/help/TemplateDocumentation.test.js +58 -0
- package/components/routes/help/ViewDocumentation.test.d.ts +1 -0
- package/components/routes/help/ViewDocumentation.test.js +34 -0
- package/components/routes/help/components/HelpTabs.test.d.ts +1 -0
- package/components/routes/help/components/HelpTabs.test.js +26 -0
- package/components/routes/hits/search/InformationPane.test.d.ts +1 -0
- package/components/routes/hits/search/InformationPane.test.js +251 -0
- package/components/routes/hits/search/RecordBrowser.test.js +179 -51
- package/components/routes/hits/search/RecordQuery.test.d.ts +1 -0
- package/components/routes/hits/search/RecordQuery.test.js +117 -0
- package/components/routes/hits/search/SearchPane.test.d.ts +1 -0
- package/components/routes/hits/search/SearchPane.test.js +178 -0
- package/components/routes/hits/search/grid/RecordGrid.test.d.ts +1 -0
- package/components/routes/hits/search/grid/RecordGrid.test.js +107 -0
- package/components/routes/hits/search/shared/CustomSort.test.d.ts +1 -0
- package/components/routes/hits/search/shared/CustomSort.test.js +77 -0
- package/components/routes/hits/search/shared/HitFilter.test.d.ts +1 -0
- package/components/routes/hits/search/shared/HitFilter.test.js +83 -0
- package/components/routes/hits/search/shared/HitSort.test.d.ts +1 -0
- package/components/routes/hits/search/shared/HitSort.test.js +61 -0
- package/components/routes/hits/search/shared/LayoutSettings.test.d.ts +1 -0
- package/components/routes/hits/search/shared/LayoutSettings.test.js +84 -0
- package/components/routes/hits/search/shared/SearchSpan.test.d.ts +1 -0
- package/components/routes/hits/search/shared/SearchSpan.test.js +84 -0
- package/components/routes/home/AnalyticCard.test.d.ts +1 -0
- package/components/routes/home/AnalyticCard.test.js +87 -0
- package/components/routes/home/index.test.d.ts +1 -0
- package/components/routes/home/index.test.js +190 -0
- package/components/routes/overviews/OverviewViewer.test.d.ts +1 -0
- package/components/routes/overviews/OverviewViewer.test.js +151 -0
- package/components/routes/overviews/Overviews.test.d.ts +1 -0
- package/components/routes/overviews/Overviews.test.js +154 -0
- package/components/routes/settings/AdminSection.test.d.ts +1 -0
- package/components/routes/settings/AdminSection.test.js +26 -0
- package/components/routes/settings/LocalSection.test.d.ts +1 -0
- package/components/routes/settings/LocalSection.test.js +75 -0
- package/components/routes/settings/ProfileSection.test.d.ts +1 -0
- package/components/routes/settings/ProfileSection.test.js +95 -0
- package/components/routes/settings/SecuritySection.test.d.ts +1 -0
- package/components/routes/settings/SecuritySection.test.js +90 -0
- package/components/routes/settings/Settings.test.d.ts +1 -0
- package/components/routes/settings/Settings.test.js +60 -0
- package/components/routes/templates/TemplateEditor.test.d.ts +1 -0
- package/components/routes/templates/TemplateEditor.test.js +94 -0
- package/components/routes/templates/TemplateViewer.test.d.ts +1 -0
- package/components/routes/templates/TemplateViewer.test.js +145 -0
- package/components/routes/templates/Templates.test.d.ts +1 -0
- package/components/routes/templates/Templates.test.js +165 -0
- package/components/routes/views/ViewComposer.test.d.ts +1 -0
- package/components/routes/views/ViewComposer.test.js +320 -0
- package/components/routes/views/Views.test.d.ts +1 -0
- package/components/routes/views/Views.test.js +247 -0
- package/package.json +2 -2
- package/plugins/HowlerPlugin.test.d.ts +1 -0
- package/plugins/HowlerPlugin.test.js +103 -0
- package/plugins/clue/components/ClueChip.js +2 -2
- package/plugins/clue/helpers.test.d.ts +1 -0
- package/plugins/clue/helpers.test.js +100 -0
- package/plugins/store.test.d.ts +1 -0
- package/plugins/store.test.js +53 -0
- package/utils/classificationParser.test.d.ts +1 -0
- package/utils/classificationParser.test.js +199 -0
- package/utils/constants.test.d.ts +1 -0
- package/utils/constants.test.js +62 -0
- package/utils/typeUtils.test.d.ts +1 -0
- package/utils/typeUtils.test.js +22 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/// <reference types="vitest" />
|
|
3
|
+
import { act, render, screen } from '@testing-library/react';
|
|
4
|
+
import { useContext } from 'react';
|
|
5
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
6
|
+
const mockDispatchApi = vi.hoisted(() => vi.fn());
|
|
7
|
+
vi.mock('api', () => ({
|
|
8
|
+
default: { search: { fields: { hit: { get: () => ({}) } } } }
|
|
9
|
+
}));
|
|
10
|
+
vi.mock('components/hooks/useMyApi', () => ({
|
|
11
|
+
default: () => ({ dispatchApi: mockDispatchApi })
|
|
12
|
+
}));
|
|
13
|
+
import FieldProvider, { FieldContext } from './FieldProvider';
|
|
14
|
+
const Consumer = () => {
|
|
15
|
+
const ctx = useContext(FieldContext);
|
|
16
|
+
return (_jsxs("div", { children: [_jsx("button", { onClick: () => void ctx.getHitFields(), children: "load" }), _jsx("span", { children: ctx.hitFields.length })] }));
|
|
17
|
+
};
|
|
18
|
+
describe('FieldProvider', () => {
|
|
19
|
+
it('loads hit fields once and reuses the cached value', async () => {
|
|
20
|
+
mockDispatchApi.mockResolvedValue([{ name: 'field-a' }]);
|
|
21
|
+
render(_jsx(FieldProvider, { children: _jsx(Consumer, {}) }));
|
|
22
|
+
await act(async () => screen.getByText('load').click());
|
|
23
|
+
expect(mockDispatchApi).toHaveBeenCalledTimes(1);
|
|
24
|
+
expect(screen.getByText('1')).toBeInTheDocument();
|
|
25
|
+
await act(async () => screen.getByText('load').click());
|
|
26
|
+
expect(mockDispatchApi).toHaveBeenCalledTimes(1);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/// <reference types="vitest" />
|
|
3
|
+
import { act, renderHook, waitFor } from '@testing-library/react';
|
|
4
|
+
import { useContext } from 'react';
|
|
5
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
6
|
+
import { StorageKey } from '@cccsaurora/howler-ui/utils/constants';
|
|
7
|
+
const mockGetStored = vi.hoisted(() => vi.fn());
|
|
8
|
+
const mockSetStored = vi.hoisted(() => vi.fn());
|
|
9
|
+
const mockRemoveStored = vi.hoisted(() => vi.fn());
|
|
10
|
+
vi.mock('components/hooks/useLocalStorage', () => ({
|
|
11
|
+
default: () => ({
|
|
12
|
+
get: mockGetStored,
|
|
13
|
+
set: mockSetStored,
|
|
14
|
+
remove: mockRemoveStored
|
|
15
|
+
})
|
|
16
|
+
}));
|
|
17
|
+
import LocalStorageProvider, { LocalStorageContext } from './LocalStorageProvider';
|
|
18
|
+
describe('LocalStorageProvider', () => {
|
|
19
|
+
it('hydrates values, updates stored state, and removes keys', async () => {
|
|
20
|
+
mockGetStored.mockImplementation((key) => {
|
|
21
|
+
if (key === StorageKey.PAGE_COUNT)
|
|
22
|
+
return 25;
|
|
23
|
+
if (key === StorageKey.NEXT_LOCATION)
|
|
24
|
+
return '/hits';
|
|
25
|
+
return undefined;
|
|
26
|
+
});
|
|
27
|
+
const wrapper = ({ children }) => _jsx(LocalStorageProvider, { children: children });
|
|
28
|
+
const { result } = renderHook(() => useContext(LocalStorageContext), { wrapper });
|
|
29
|
+
await waitFor(() => expect(result.current.values[StorageKey.PAGE_COUNT]).toBe(25));
|
|
30
|
+
expect(result.current.values[StorageKey.NEXT_LOCATION]).toBe('/hits');
|
|
31
|
+
act(() => {
|
|
32
|
+
result.current.set(StorageKey.PAGE_COUNT, 50);
|
|
33
|
+
});
|
|
34
|
+
expect(mockSetStored).toHaveBeenCalledWith(StorageKey.PAGE_COUNT, 50);
|
|
35
|
+
expect(result.current.values[StorageKey.PAGE_COUNT]).toBe(50);
|
|
36
|
+
act(() => {
|
|
37
|
+
result.current.remove(StorageKey.PAGE_COUNT);
|
|
38
|
+
});
|
|
39
|
+
expect(mockRemoveStored).toHaveBeenCalledWith(StorageKey.PAGE_COUNT);
|
|
40
|
+
expect(result.current.values[StorageKey.PAGE_COUNT]).toBeUndefined();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/// <reference types="vitest" />
|
|
3
|
+
import { act, fireEvent, render, screen } from '@testing-library/react';
|
|
4
|
+
import { useContext } from 'react';
|
|
5
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
6
|
+
vi.mock('components/elements/display/modals/ConfirmDeleteModal', () => ({
|
|
7
|
+
default: ({ onConfirm, preferDelete, preferCancel }) => (_jsx("button", { onClick: onConfirm, children: `confirm:${String(preferDelete)}:${String(preferCancel)}` }))
|
|
8
|
+
}));
|
|
9
|
+
import ModalProvider, { ModalContext } from './ModalProvider';
|
|
10
|
+
const Consumer = () => {
|
|
11
|
+
const modal = useContext(ModalContext);
|
|
12
|
+
return (_jsxs("div", { children: [_jsx("button", { onClick: () => modal.showModal(_jsx("div", { children: "modal-body" }), { disableClose: true, maxWidth: 'xl' }), children: "show" }), _jsx("button", { onClick: () => modal.withConfirmDeleteModal(vi.fn(), true, false), children: "confirm-wrapper" }), _jsx("button", { onClick: () => modal.close(), children: "close" }), _jsx("div", { children: String(modal.options?.disableClose) }), _jsx("div", { children: modal.content })] }));
|
|
13
|
+
};
|
|
14
|
+
describe('ModalProvider', () => {
|
|
15
|
+
it('shows modal content, resets options, and closes', async () => {
|
|
16
|
+
render(_jsx(ModalProvider, { children: _jsx(Consumer, {}) }));
|
|
17
|
+
fireEvent.click(screen.getByText('show'));
|
|
18
|
+
expect(screen.getByText('modal-body')).toBeInTheDocument();
|
|
19
|
+
expect(screen.getAllByText('true')[0]).toBeInTheDocument();
|
|
20
|
+
fireEvent.click(screen.getByText('close'));
|
|
21
|
+
await act(async () => { });
|
|
22
|
+
expect(screen.queryByText('modal-body')).not.toBeInTheDocument();
|
|
23
|
+
});
|
|
24
|
+
it('builds confirm-delete modal wrappers', () => {
|
|
25
|
+
const onConfirm = vi.fn();
|
|
26
|
+
const TestConsumer = () => {
|
|
27
|
+
const modal = useContext(ModalContext);
|
|
28
|
+
return (_jsxs("div", { children: [_jsx("button", { onClick: () => modal.withConfirmDeleteModal(onConfirm, true, false), children: "show-confirm" }), _jsx("div", { children: modal.content })] }));
|
|
29
|
+
};
|
|
30
|
+
render(_jsx(ModalProvider, { children: _jsx(TestConsumer, {}) }));
|
|
31
|
+
fireEvent.click(screen.getByText('show-confirm'));
|
|
32
|
+
fireEvent.click(screen.getByText('confirm:true:false'));
|
|
33
|
+
expect(onConfirm).toHaveBeenCalled();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/// <reference types="vitest" />
|
|
3
|
+
import { act, renderHook, waitFor } from '@testing-library/react';
|
|
4
|
+
import { useContext } from 'react';
|
|
5
|
+
import { setupContextSelectorMock } from '@cccsaurora/howler-ui/tests/mocks';
|
|
6
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
+
setupContextSelectorMock();
|
|
8
|
+
const mockOverviewGet = vi.hoisted(() => vi.fn());
|
|
9
|
+
vi.mock('api', () => ({
|
|
10
|
+
default: {
|
|
11
|
+
overview: {
|
|
12
|
+
get: mockOverviewGet
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}));
|
|
16
|
+
import OverviewProvider, { OverviewContext } from './OverviewProvider';
|
|
17
|
+
describe('OverviewProvider', () => {
|
|
18
|
+
const wrapper = ({ children }) => _jsx(OverviewProvider, { children: children });
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
mockOverviewGet.mockReset();
|
|
21
|
+
});
|
|
22
|
+
it('loads and caches overviews until forced to refresh', async () => {
|
|
23
|
+
const dataset = [
|
|
24
|
+
{ overview_id: '1', analytic: 'a1' },
|
|
25
|
+
{ overview_id: '2', analytic: 'a2', detection: 'Phishing' }
|
|
26
|
+
];
|
|
27
|
+
mockOverviewGet.mockResolvedValue(dataset);
|
|
28
|
+
const { result } = renderHook(() => useContext(OverviewContext), { wrapper });
|
|
29
|
+
await act(async () => {
|
|
30
|
+
await expect(result.current.getOverviews()).resolves.toEqual(dataset);
|
|
31
|
+
});
|
|
32
|
+
await waitFor(() => expect(result.current.loaded).toBe(true));
|
|
33
|
+
expect(mockOverviewGet).toHaveBeenCalledTimes(1);
|
|
34
|
+
await act(async () => {
|
|
35
|
+
await expect(result.current.getOverviews()).resolves.toEqual(dataset);
|
|
36
|
+
});
|
|
37
|
+
expect(mockOverviewGet).toHaveBeenCalledTimes(1);
|
|
38
|
+
await act(async () => {
|
|
39
|
+
await expect(result.current.getOverviews(true)).resolves.toEqual(dataset);
|
|
40
|
+
});
|
|
41
|
+
expect(mockOverviewGet).toHaveBeenCalledTimes(2);
|
|
42
|
+
});
|
|
43
|
+
it('matches the most specific overview for a hit and can refresh state', async () => {
|
|
44
|
+
mockOverviewGet.mockResolvedValue([
|
|
45
|
+
{ overview_id: 'generic', analytic: 'analytic-1' },
|
|
46
|
+
{ overview_id: 'specific', analytic: 'analytic-1', detection: 'Malware' }
|
|
47
|
+
]);
|
|
48
|
+
const { result } = renderHook(() => useContext(OverviewContext), { wrapper });
|
|
49
|
+
await act(async () => {
|
|
50
|
+
await result.current.getOverviews();
|
|
51
|
+
});
|
|
52
|
+
expect(result.current.getMatchingOverview({ howler: { analytic: 'analytic-1', detection: 'malware' } })).toMatchObject({ overview_id: 'specific' });
|
|
53
|
+
expect(result.current.getMatchingOverview({ howler: { analytic: 'analytic-1' } })).toMatchObject({
|
|
54
|
+
overview_id: 'generic'
|
|
55
|
+
});
|
|
56
|
+
mockOverviewGet.mockResolvedValueOnce([{ overview_id: 'refreshed', analytic: 'analytic-2' }]);
|
|
57
|
+
act(() => {
|
|
58
|
+
result.current.refresh();
|
|
59
|
+
});
|
|
60
|
+
await waitFor(() => expect(mockOverviewGet).toHaveBeenCalledTimes(2));
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/// <reference types="vitest" />
|
|
3
|
+
import { act, render, screen, waitFor } from '@testing-library/react';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
const socketContextToken = vi.hoisted(() => ({ name: 'socket-context' }));
|
|
6
|
+
const mockDispatchApi = vi.hoisted(() => vi.fn());
|
|
7
|
+
const mockAddListener = vi.hoisted(() => vi.fn());
|
|
8
|
+
const mockRemoveListener = vi.hoisted(() => vi.fn());
|
|
9
|
+
vi.mock('api', () => ({
|
|
10
|
+
default: {
|
|
11
|
+
v2: {
|
|
12
|
+
search: {
|
|
13
|
+
post: (_indexes, body) => body
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}));
|
|
18
|
+
vi.mock('components/hooks/useMyApi', () => ({
|
|
19
|
+
default: () => ({ dispatchApi: mockDispatchApi })
|
|
20
|
+
}));
|
|
21
|
+
vi.mock('./SocketProvider', () => ({
|
|
22
|
+
SocketContext: socketContextToken
|
|
23
|
+
}));
|
|
24
|
+
vi.mock('react', async (importOriginal) => {
|
|
25
|
+
const actual = await importOriginal();
|
|
26
|
+
return {
|
|
27
|
+
...actual,
|
|
28
|
+
useContext: (context) => {
|
|
29
|
+
if (context === socketContextToken) {
|
|
30
|
+
return { addListener: mockAddListener, removeListener: mockRemoveListener };
|
|
31
|
+
}
|
|
32
|
+
return actual.useContext(context);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
import RecordProvider, { useRecordContextSelector } from './RecordProvider';
|
|
37
|
+
const Consumer = () => {
|
|
38
|
+
const records = useRecordContextSelector(ctx => ctx.records);
|
|
39
|
+
const selected = useRecordContextSelector(ctx => ctx.selectedRecords);
|
|
40
|
+
const loadRecords = useRecordContextSelector(ctx => ctx.loadRecords);
|
|
41
|
+
const updateRecord = useRecordContextSelector(ctx => ctx.updateRecord);
|
|
42
|
+
const getRecord = useRecordContextSelector(ctx => ctx.getRecord);
|
|
43
|
+
const addRecordToSelection = useRecordContextSelector(ctx => ctx.addRecordToSelection);
|
|
44
|
+
const removeRecordFromSelection = useRecordContextSelector(ctx => ctx.removeRecordFromSelection);
|
|
45
|
+
const clearSelectedRecords = useRecordContextSelector(ctx => ctx.clearSelectedRecords);
|
|
46
|
+
return (_jsxs("div", { children: [_jsx("button", { onClick: () => loadRecords([{ howler: { id: 'h1' } }, { howler: { id: 'h2' } }]), children: "load" }), _jsx("button", { onClick: () => updateRecord({ howler: { id: 'h2' }, updated: true }), children: "update" }), _jsx("button", { onClick: () => addRecordToSelection('h1'), children: "select-one" }), _jsx("button", { onClick: () => addRecordToSelection('missing'), children: "select-missing" }), _jsx("button", { onClick: () => removeRecordFromSelection('h1'), children: "remove" }), _jsx("button", { onClick: () => clearSelectedRecords('h2'), children: "clear-except" }), _jsx("button", { onClick: () => void getRecord('missing').then(r => (document.body.dataset.record = r.howler.id)), children: "fetch" }), _jsx("span", { children: Object.keys(records).join(',') }), _jsx("span", { children: selected.map((item) => item.howler.id).join(',') })] }));
|
|
47
|
+
};
|
|
48
|
+
describe('RecordProvider', () => {
|
|
49
|
+
it('loads, updates, selects, and fetches records while wiring socket listeners', async () => {
|
|
50
|
+
mockDispatchApi.mockResolvedValue({ items: [{ howler: { id: 'missing' } }] });
|
|
51
|
+
render(_jsx(RecordProvider, { children: _jsx(Consumer, {}) }));
|
|
52
|
+
expect(mockAddListener).toHaveBeenCalledWith('hits', expect.any(Function));
|
|
53
|
+
await act(async () => screen.getByText('load').click());
|
|
54
|
+
expect(screen.getByText('h1,h2')).toBeInTheDocument();
|
|
55
|
+
await act(async () => screen.getByText('update').click());
|
|
56
|
+
await act(async () => screen.getByText('select-one').click());
|
|
57
|
+
expect(screen.getByText('h1')).toBeInTheDocument();
|
|
58
|
+
await act(async () => screen.getByText('select-missing').click());
|
|
59
|
+
await waitFor(() => expect(mockDispatchApi).toHaveBeenCalled());
|
|
60
|
+
await act(async () => screen.getByText('fetch').click());
|
|
61
|
+
expect(document.body.dataset.record).toBe('missing');
|
|
62
|
+
await act(async () => screen.getByText('clear-except').click());
|
|
63
|
+
expect(screen.getByText('h2')).toBeInTheDocument();
|
|
64
|
+
await act(async () => screen.getByText('remove').click());
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="vitest" />
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { missingContext } from './contextUtils';
|
|
4
|
+
describe('missingContext', () => {
|
|
5
|
+
it('throws a provider-specific error', () => {
|
|
6
|
+
expect(() => missingContext('DemoContext')).toThrow('DemoContext must be used within its provider.');
|
|
7
|
+
});
|
|
8
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/// <reference types="vitest" />
|
|
3
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
4
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
let currentUser = { username: 'author', is_admin: false };
|
|
6
|
+
vi.mock('@mui/icons-material', () => ({
|
|
7
|
+
Celebration: () => _jsx("div", { children: "confetti" }),
|
|
8
|
+
Check: () => _jsx("div", { children: "check" }),
|
|
9
|
+
Clear: () => _jsx("div", { children: "clear" }),
|
|
10
|
+
Delete: () => _jsx("div", { children: "delete" }),
|
|
11
|
+
Edit: () => _jsx("div", { children: "edit" }),
|
|
12
|
+
Favorite: () => _jsx("div", { children: "heart" }),
|
|
13
|
+
FireTruck: () => _jsx("div", { children: "fire" }),
|
|
14
|
+
FormatQuote: () => _jsx("div", { children: "quote" }),
|
|
15
|
+
Mood: () => _jsx("div", { children: "laugh" }),
|
|
16
|
+
MoreHoriz: () => _jsx("div", { children: "menu" }),
|
|
17
|
+
RocketLaunch: () => _jsx("div", { children: "rocket" }),
|
|
18
|
+
ThumbDown: () => _jsx("div", { children: "minus" }),
|
|
19
|
+
ThumbUp: () => _jsx("div", { children: "plus" })
|
|
20
|
+
}));
|
|
21
|
+
vi.mock('@mui/material', () => ({
|
|
22
|
+
CardActions: ({ children }) => _jsx("div", { children: children }),
|
|
23
|
+
CardContent: ({ children }) => _jsx("div", { children: children }),
|
|
24
|
+
Chip: ({ label, onClick }) => _jsx("button", { onClick: onClick, children: String(label ?? '') }),
|
|
25
|
+
CircularProgress: () => _jsx("div", { children: "loading" }),
|
|
26
|
+
Collapse: ({ children, in: open }) => (open ? _jsx("div", { children: children }) : null),
|
|
27
|
+
Fade: ({ children }) => _jsx(_Fragment, { children: children }),
|
|
28
|
+
IconButton: ({ children, onClick, disabled, id }) => (_jsx("button", { id: id, onClick: onClick, disabled: disabled, children: children })),
|
|
29
|
+
ListItemIcon: ({ children }) => _jsx("div", { children: children }),
|
|
30
|
+
ListItemText: ({ children }) => _jsx("div", { children: children }),
|
|
31
|
+
Menu: ({ children, open }) => (open ? _jsx("div", { children: children }) : null),
|
|
32
|
+
MenuItem: ({ children, onClick, disabled }) => (_jsx("button", { onClick: onClick, disabled: disabled, children: children })),
|
|
33
|
+
Stack: ({ children, onMouseEnter, onMouseLeave }) => (_jsx("div", { onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, children: children })),
|
|
34
|
+
TextField: ({ defaultValue, onChange, onKeyDown }) => (_jsx("textarea", { "aria-label": "comment-editor", defaultValue: defaultValue, onChange: onChange, onKeyDown: onKeyDown })),
|
|
35
|
+
Tooltip: ({ children }) => _jsx(_Fragment, { children: children }),
|
|
36
|
+
Typography: ({ children }) => _jsx("div", { children: children })
|
|
37
|
+
}));
|
|
38
|
+
vi.mock('@tui/core', () => ({
|
|
39
|
+
useAppUser: () => ({ user: currentUser })
|
|
40
|
+
}));
|
|
41
|
+
vi.mock('components/elements/addons/layout/FlexOne', () => ({
|
|
42
|
+
default: () => _jsx("div", { children: "flex-one" })
|
|
43
|
+
}));
|
|
44
|
+
vi.mock('components/hooks/useMyUtils', () => ({
|
|
45
|
+
default: () => ({ shiftColor: () => '#999' })
|
|
46
|
+
}));
|
|
47
|
+
vi.mock('react-i18next', () => ({
|
|
48
|
+
useTranslation: () => ({ t: (key) => key })
|
|
49
|
+
}));
|
|
50
|
+
vi.mock('utils/utils', () => ({
|
|
51
|
+
compareTimestamp: () => 2,
|
|
52
|
+
twitterShort: () => 'short-time'
|
|
53
|
+
}));
|
|
54
|
+
vi.mock('./display/HowlerAvatar', () => ({
|
|
55
|
+
default: ({ userId }) => _jsx("div", { children: `avatar-${userId}` })
|
|
56
|
+
}));
|
|
57
|
+
vi.mock('./display/HowlerCard', () => ({
|
|
58
|
+
default: ({ children, onClick, onMouseEnter, onMouseLeave }) => (_jsx("div", { onClick: onClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, children: children }))
|
|
59
|
+
}));
|
|
60
|
+
vi.mock('./display/Markdown', () => ({
|
|
61
|
+
default: ({ md }) => _jsx("div", { children: md })
|
|
62
|
+
}));
|
|
63
|
+
import Comment from './Comment';
|
|
64
|
+
describe('Comment', () => {
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
currentUser = { username: 'author', is_admin: false };
|
|
67
|
+
});
|
|
68
|
+
it('quotes and deletes a comment from the action menu', async () => {
|
|
69
|
+
const handleDelete = vi.fn().mockResolvedValue(undefined);
|
|
70
|
+
const handleQuote = vi.fn();
|
|
71
|
+
render(_jsx(Comment, { comment: {
|
|
72
|
+
id: 'c1',
|
|
73
|
+
user: 'author',
|
|
74
|
+
value: 'hello',
|
|
75
|
+
timestamp: '2026-01-01T00:00:00Z',
|
|
76
|
+
modified: '2026-01-02T00:00:00Z'
|
|
77
|
+
}, handleDelete: handleDelete, handleQuote: handleQuote, users: { author: { name: 'Author Name' } }, extra: _jsx("div", { children: "extra" }) }));
|
|
78
|
+
expect(screen.getByText('Author Name')).toBeInTheDocument();
|
|
79
|
+
expect(screen.getByText('comments.edited')).toBeInTheDocument();
|
|
80
|
+
expect(screen.getByText('hello')).toBeInTheDocument();
|
|
81
|
+
fireEvent.mouseEnter(screen.getByText('hello').closest('div'));
|
|
82
|
+
fireEvent.click(screen.getByText('menu'));
|
|
83
|
+
fireEvent.click(screen.getByText('comments.quote'));
|
|
84
|
+
expect(handleQuote).toHaveBeenCalled();
|
|
85
|
+
fireEvent.click(screen.getByText('menu'));
|
|
86
|
+
fireEvent.click(screen.getByText('comments.delete'));
|
|
87
|
+
await waitFor(() => expect(handleDelete).toHaveBeenCalled());
|
|
88
|
+
});
|
|
89
|
+
it('edits and reacts to a comment', async () => {
|
|
90
|
+
const handleEdit = vi.fn().mockResolvedValue(undefined);
|
|
91
|
+
const handleReact = vi.fn().mockResolvedValue(undefined);
|
|
92
|
+
render(_jsx(Comment, { comment: {
|
|
93
|
+
id: 'c2',
|
|
94
|
+
user: 'author',
|
|
95
|
+
value: 'old text',
|
|
96
|
+
timestamp: '2026-01-01T00:00:00Z',
|
|
97
|
+
modified: '2026-01-01T00:00:00Z',
|
|
98
|
+
reactions: { other: 'heart' }
|
|
99
|
+
}, handleEdit: handleEdit, handleReact: handleReact, users: { author: { name: 'Author Name' } } }));
|
|
100
|
+
fireEvent.mouseEnter(screen.getByText('old text').closest('div'));
|
|
101
|
+
fireEvent.click(screen.getByText('menu'));
|
|
102
|
+
fireEvent.click(screen.getByText('comments.edit'));
|
|
103
|
+
fireEvent.change(screen.getByLabelText('comment-editor'), { target: { value: 'new text' } });
|
|
104
|
+
fireEvent.keyDown(screen.getByLabelText('comment-editor'), { key: 'Enter', ctrlKey: true });
|
|
105
|
+
await waitFor(() => expect(handleEdit).toHaveBeenCalledWith('new text'));
|
|
106
|
+
fireEvent.click(screen.getByText('1'));
|
|
107
|
+
await waitFor(() => expect(handleReact).toHaveBeenCalledWith('heart'));
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/// <reference types="vitest" />
|
|
3
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
const mockShowErrorMessage = vi.hoisted(() => vi.fn());
|
|
6
|
+
vi.mock('@mui/icons-material', async (importOriginal) => {
|
|
7
|
+
const actual = await importOriginal();
|
|
8
|
+
return {
|
|
9
|
+
...actual,
|
|
10
|
+
Check: () => _jsx("div", { children: "check-icon" }),
|
|
11
|
+
Close: () => _jsx("div", { children: "close-icon" }),
|
|
12
|
+
Delete: () => _jsx("div", { children: "delete-icon" }),
|
|
13
|
+
Edit: () => _jsx("div", { children: "edit-icon" })
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
vi.mock('@mui/material', () => ({
|
|
17
|
+
Box: ({ children }) => _jsx("div", { children: children }),
|
|
18
|
+
Checkbox: ({ checked, onChange }) => (_jsx("input", { "aria-label": "checkbox", type: "checkbox", checked: checked, onChange: onChange })),
|
|
19
|
+
CircularProgress: () => _jsx("div", { children: "loading" }),
|
|
20
|
+
IconButton: ({ children, onClick, disabled }) => (_jsx("button", { disabled: disabled, onClick: onClick, children: children })),
|
|
21
|
+
Slider: ({ value, onChange }) => (_jsx("input", { "aria-label": "slider", type: "range", value: value, onChange: e => onChange(null, Number(e.target.value)) })),
|
|
22
|
+
Stack: ({ children }) => _jsx("div", { children: children }),
|
|
23
|
+
TableCell: ({ children }) => _jsx("div", { children: children }),
|
|
24
|
+
TableRow: ({ children }) => _jsx("div", { children: children }),
|
|
25
|
+
TextField: ({ value, onChange, onKeyDown, label, type, error }) => (_jsxs("label", { children: [label ?? type ?? 'text', _jsx("input", { "aria-label": label ?? type ?? 'text', value: String(value ?? ''), onChange: onChange, onKeyDown: onKeyDown, "data-error": String(error) })] })),
|
|
26
|
+
Typography: ({ children }) => _jsx("div", { children: children })
|
|
27
|
+
}));
|
|
28
|
+
vi.mock('components/hooks/useMySnackbar', () => ({
|
|
29
|
+
default: () => ({ showErrorMessage: mockShowErrorMessage })
|
|
30
|
+
}));
|
|
31
|
+
vi.mock('react-i18next', () => ({
|
|
32
|
+
useTranslation: () => ({ t: (key) => key })
|
|
33
|
+
}));
|
|
34
|
+
import EditRow from './EditRow';
|
|
35
|
+
describe('EditRow', () => {
|
|
36
|
+
it('edits text values and closes on escape when unchanged', async () => {
|
|
37
|
+
const onEdit = vi.fn(async () => undefined);
|
|
38
|
+
render(_jsx(EditRow, { titleKey: "title", descriptionKey: "description", value: "current", onEdit: onEdit }));
|
|
39
|
+
fireEvent.click(screen.getByText('edit-icon'));
|
|
40
|
+
fireEvent.change(screen.getByLabelText('text'), { target: { value: 'updated' } });
|
|
41
|
+
fireEvent.click(screen.getByText('check-icon'));
|
|
42
|
+
await waitFor(() => expect(onEdit).toHaveBeenCalledWith('updated'));
|
|
43
|
+
fireEvent.click(screen.getByText('edit-icon'));
|
|
44
|
+
fireEvent.keyDown(screen.getByLabelText('text'), { key: 'Escape' });
|
|
45
|
+
expect(screen.queryByLabelText('text')).not.toBeInTheDocument();
|
|
46
|
+
expect(screen.getByText('description')).toBeInTheDocument();
|
|
47
|
+
});
|
|
48
|
+
it('validates passwords and supports optional delete', async () => {
|
|
49
|
+
const onEdit = vi.fn(async () => undefined);
|
|
50
|
+
render(_jsx(EditRow, { titleKey: "password.title", value: "secret", type: "password", onEdit: onEdit, optional: true }));
|
|
51
|
+
fireEvent.click(screen.getByText('edit-icon'));
|
|
52
|
+
fireEvent.change(screen.getByLabelText('password'), { target: { value: 'next-secret' } });
|
|
53
|
+
fireEvent.change(screen.getByLabelText('password.confirm'), { target: { value: 'wrong' } });
|
|
54
|
+
fireEvent.click(screen.getByText('check-icon'));
|
|
55
|
+
expect(mockShowErrorMessage).toHaveBeenCalledWith('password.match');
|
|
56
|
+
fireEvent.change(screen.getByLabelText('password.confirm'), { target: { value: 'next-secret' } });
|
|
57
|
+
fireEvent.click(screen.getByText('check-icon'));
|
|
58
|
+
await waitFor(() => expect(onEdit).toHaveBeenCalledWith('next-secret'));
|
|
59
|
+
fireEvent.click(screen.getByText('edit-icon'));
|
|
60
|
+
fireEvent.click(screen.getByText('delete-icon'));
|
|
61
|
+
await waitFor(() => expect(onEdit).toHaveBeenCalledWith(undefined));
|
|
62
|
+
});
|
|
63
|
+
it('applies checkbox and range edits with validation', async () => {
|
|
64
|
+
const checkboxEdit = vi.fn(async () => undefined);
|
|
65
|
+
const rangeEdit = vi.fn(async () => undefined);
|
|
66
|
+
const { rerender } = render(_jsx(EditRow, { titleKey: "checkbox.title", value: false, type: "checkbox", onEdit: checkboxEdit }));
|
|
67
|
+
fireEvent.click(screen.getByLabelText('checkbox'));
|
|
68
|
+
await waitFor(() => expect(checkboxEdit).toHaveBeenCalledWith('true'));
|
|
69
|
+
rerender(_jsx(EditRow, { titleKey: "range.title", value: 10, type: "range", min: 5, max: 20, onEdit: rangeEdit, valueLabelFormat: value => `${value}%` }));
|
|
70
|
+
expect(screen.getByText('10%')).toBeInTheDocument();
|
|
71
|
+
fireEvent.click(screen.getByText('edit-icon'));
|
|
72
|
+
fireEvent.change(screen.getByLabelText('slider'), { target: { value: '15' } });
|
|
73
|
+
fireEvent.click(screen.getByText('check-icon'));
|
|
74
|
+
await waitFor(() => expect(rangeEdit).toHaveBeenCalledWith('15'));
|
|
75
|
+
});
|
|
76
|
+
it('tracks validation errors and failOnValidate behavior for text and numbers', () => {
|
|
77
|
+
const onEdit = vi.fn(async () => undefined);
|
|
78
|
+
const { unmount } = render(_jsx(EditRow, { titleKey: "text.title", value: "alpha", onEdit: onEdit, validate: (value) => value !== 'bad' }));
|
|
79
|
+
fireEvent.click(screen.getByText('edit-icon'));
|
|
80
|
+
fireEvent.change(screen.getByLabelText('text'), { target: { value: 'bad' } });
|
|
81
|
+
expect(screen.getByLabelText('text')).toHaveAttribute('data-error', 'true');
|
|
82
|
+
unmount();
|
|
83
|
+
render(_jsx(EditRow, { titleKey: "number.title", value: 5, type: "number", min: 2, max: 10, onEdit: onEdit, failOnValidate: true }));
|
|
84
|
+
fireEvent.click(screen.getByText('edit-icon'));
|
|
85
|
+
fireEvent.change(screen.getByLabelText('number'), { target: { value: '1' } });
|
|
86
|
+
expect(screen.getByLabelText('number')).toHaveValue('5');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/// <reference types="vitest" />
|
|
3
|
+
import { render } from '@testing-library/react';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
const apiConfigContextToken = vi.hoisted(() => ({ name: 'api-config-context' }));
|
|
6
|
+
const capturedProps = vi.hoisted(() => ({ current: null }));
|
|
7
|
+
let monacoValue = null;
|
|
8
|
+
vi.mock('@monaco-editor/react', () => ({
|
|
9
|
+
useMonaco: () => monacoValue
|
|
10
|
+
}));
|
|
11
|
+
vi.mock('@mui/material', () => ({
|
|
12
|
+
useTheme: () => ({ palette: { mode: 'light' } })
|
|
13
|
+
}));
|
|
14
|
+
vi.mock('components/app/providers/ApiConfigProvider', () => ({
|
|
15
|
+
ApiConfigContext: apiConfigContextToken
|
|
16
|
+
}));
|
|
17
|
+
vi.mock('components/elements/ThemedEditor', () => ({
|
|
18
|
+
default: (props) => {
|
|
19
|
+
capturedProps.current = props;
|
|
20
|
+
return _jsx("div", { children: "themed-editor" });
|
|
21
|
+
}
|
|
22
|
+
}));
|
|
23
|
+
vi.mock('../routes/overviews/markdownExtendedTokenProvider', () => ({
|
|
24
|
+
conf: { autoClosingPairs: [] },
|
|
25
|
+
language: { tokenizer: {} }
|
|
26
|
+
}));
|
|
27
|
+
vi.mock('react', async (importOriginal) => {
|
|
28
|
+
const actual = await importOriginal();
|
|
29
|
+
return {
|
|
30
|
+
...actual,
|
|
31
|
+
useContext: (context) => {
|
|
32
|
+
if (context === apiConfigContextToken)
|
|
33
|
+
return { config: { lookups: {} } };
|
|
34
|
+
return actual.useContext(context);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
import MarkdownEditor from './MarkdownEditor';
|
|
39
|
+
describe('MarkdownEditor', () => {
|
|
40
|
+
it('configures markdown-extended editors and normalizes onChange values', () => {
|
|
41
|
+
const setEOL = vi.fn();
|
|
42
|
+
const model = { setEOL, getLanguageId: () => 'plaintext' };
|
|
43
|
+
const dispose = vi.fn();
|
|
44
|
+
monacoValue = {
|
|
45
|
+
editor: {
|
|
46
|
+
EndOfLineSequence: { LF: 1 },
|
|
47
|
+
getModels: () => [model],
|
|
48
|
+
onDidCreateModel: (cb) => {
|
|
49
|
+
cb(model);
|
|
50
|
+
return { dispose };
|
|
51
|
+
},
|
|
52
|
+
setModelLanguage: vi.fn()
|
|
53
|
+
},
|
|
54
|
+
languages: {
|
|
55
|
+
register: vi.fn(),
|
|
56
|
+
setLanguageConfiguration: vi.fn(() => ({ dispose })),
|
|
57
|
+
setMonarchTokensProvider: vi.fn(() => ({ dispose })),
|
|
58
|
+
getLanguages: () => [{ id: 'markdown-extended' }]
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const setContent = vi.fn();
|
|
62
|
+
render(_jsx(MarkdownEditor, { content: "hello", setContent: setContent, editorOptions: { wordWrap: 'on' } }));
|
|
63
|
+
capturedProps.current.beforeMount(monacoValue);
|
|
64
|
+
expect(monacoValue.languages.register).toHaveBeenCalledWith({ id: 'markdown-extended' });
|
|
65
|
+
expect(setEOL).toHaveBeenCalledWith(1);
|
|
66
|
+
expect(monacoValue.editor.setModelLanguage).toHaveBeenCalledWith(model, 'markdown-extended');
|
|
67
|
+
expect(capturedProps.current.options).toMatchObject({
|
|
68
|
+
fontSize: 16,
|
|
69
|
+
wordWrap: 'on',
|
|
70
|
+
bracketPairColorization: { enabled: false }
|
|
71
|
+
});
|
|
72
|
+
capturedProps.current.onChange(undefined);
|
|
73
|
+
expect(setContent).toHaveBeenCalledWith('');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/// <reference types="vitest" />
|
|
3
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
vi.mock('@mui/icons-material', () => ({
|
|
6
|
+
ArrowDropDown: () => _jsx("div", { children: "expand-icon" }),
|
|
7
|
+
InfoOutlined: () => _jsx("div", { children: "info-icon" })
|
|
8
|
+
}));
|
|
9
|
+
vi.mock('@mui/material', () => ({
|
|
10
|
+
Accordion: ({ children }) => _jsx("div", { children: children }),
|
|
11
|
+
AccordionDetails: ({ children }) => _jsx("div", { children: children }),
|
|
12
|
+
AccordionSummary: ({ children }) => _jsx("div", { children: children }),
|
|
13
|
+
Box: ({ children }) => _jsx("div", { children: children }),
|
|
14
|
+
Divider: () => _jsx("div", { children: "divider" }),
|
|
15
|
+
Grid: ({ children }) => _jsx("div", { children: children }),
|
|
16
|
+
Stack: ({ children }) => _jsx("div", { children: children }),
|
|
17
|
+
TextField: ({ value, onChange, label }) => (_jsxs("label", { children: [label, _jsx("input", { "aria-label": label, value: value, onChange: onChange })] })),
|
|
18
|
+
Tooltip: ({ children }) => _jsx(_Fragment, { children: children }),
|
|
19
|
+
Typography: ({ children }) => _jsx("div", { children: children }),
|
|
20
|
+
useTheme: () => ({
|
|
21
|
+
palette: { divider: '#ddd' },
|
|
22
|
+
spacing: (n) => `${n * 8}px`
|
|
23
|
+
})
|
|
24
|
+
}));
|
|
25
|
+
vi.mock('components/elements/PluginTypography', () => ({
|
|
26
|
+
default: ({ children }) => _jsx("span", { children: children })
|
|
27
|
+
}));
|
|
28
|
+
vi.mock('react-i18next', () => ({
|
|
29
|
+
useTranslation: () => ({ t: (key) => key })
|
|
30
|
+
}));
|
|
31
|
+
vi.mock('utils/Throttler', () => ({
|
|
32
|
+
default: class {
|
|
33
|
+
debounce(fn) {
|
|
34
|
+
fn();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}));
|
|
38
|
+
import ObjectDetails from './ObjectDetails';
|
|
39
|
+
describe('ObjectDetails', () => {
|
|
40
|
+
it('renders grouped sections, nested values, and filters by search query', async () => {
|
|
41
|
+
render(_jsx(ObjectDetails, { obj: {
|
|
42
|
+
event: {
|
|
43
|
+
id: 'evt-1',
|
|
44
|
+
nested: { key: 'value' },
|
|
45
|
+
dup: ['alpha', 'alpha', 'beta']
|
|
46
|
+
},
|
|
47
|
+
source: {
|
|
48
|
+
ip: '1.1.1.1',
|
|
49
|
+
port: 443,
|
|
50
|
+
enabled: false
|
|
51
|
+
},
|
|
52
|
+
howler: { id: 'skip-me' },
|
|
53
|
+
labels: { tag: 'skip' },
|
|
54
|
+
__hidden: { value: 'skip' }
|
|
55
|
+
} }));
|
|
56
|
+
expect(screen.getByText('Event')).toBeInTheDocument();
|
|
57
|
+
expect(screen.getByText('Source')).toBeInTheDocument();
|
|
58
|
+
expect(screen.queryByText('Howler')).not.toBeInTheDocument();
|
|
59
|
+
expect(screen.getByText('evt-1')).toBeInTheDocument();
|
|
60
|
+
expect(screen.getByText('value')).toBeInTheDocument();
|
|
61
|
+
expect(screen.getByText('alpha')).toBeInTheDocument();
|
|
62
|
+
expect(screen.getByText('beta')).toBeInTheDocument();
|
|
63
|
+
expect(screen.getByText('info-icon')).toBeInTheDocument();
|
|
64
|
+
fireEvent.change(screen.getByLabelText('overview.search'), { target: { value: 'ip' } });
|
|
65
|
+
await waitFor(() => {
|
|
66
|
+
expect(screen.getByText('1.1.1.1')).toBeInTheDocument();
|
|
67
|
+
expect(screen.queryByText('evt-1')).not.toBeInTheDocument();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type ChipProps } from '@mui/material';
|
|
2
2
|
import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
|
|
3
|
-
import type
|
|
4
|
-
export type PluginChipProps = ChipProps & {
|
|
3
|
+
import { type FC, type ReactNode } from 'react';
|
|
4
|
+
export type PluginChipProps = Omit<ChipProps, 'children'> & {
|
|
5
|
+
children?: ReactNode;
|
|
5
6
|
value: string;
|
|
6
7
|
context: string;
|
|
7
8
|
field?: string;
|