@oneuptime/common 12.0.9 → 12.0.11
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/Models/DatabaseModels/NetworkDevice.ts +44 -0
- package/Models/DatabaseModels/NetworkDeviceLink.ts +116 -0
- package/Models/DatabaseModels/RunnerJob.ts +17 -2
- package/Server/API/LlmProviderAPI.ts +8 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.ts +52 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +240 -0
- package/Server/Services/NetworkDeviceLinkService.ts +338 -2
- package/Server/Services/NetworkDeviceService.ts +265 -12
- package/Server/Services/RunnerJobService.ts +24 -1
- package/Server/Types/Billing/MeteredPlan/AllMeteredPlans.ts +19 -5
- package/Server/Types/Database/JSONColumnQuery.ts +42 -4
- package/Server/Utils/LLM/LLMService.ts +108 -19
- package/Server/Utils/Monitor/MonitorAlert.ts +22 -115
- package/Server/Utils/Monitor/MonitorIncident.ts +7 -337
- package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +27 -2
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +32 -0
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +469 -0
- package/Server/Utils/SSRFProtection.ts +5 -4
- package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +186 -38
- package/Tests/App/AdminDashboard/AdminUsersBulkAddToProject.test.tsx +955 -0
- package/Tests/App/AdminDashboard/BulkAddUsersToProject.test.ts +778 -0
- package/Tests/App/AdminDashboard/BulkAddUsersToProjectModal.test.tsx +1051 -0
- package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +420 -112
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +81 -6
- package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +543 -0
- package/Tests/App/Dashboard/PayAsYouGoFreePlan.test.ts +125 -0
- package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +612 -0
- package/Tests/App/Dashboard/SloWidgetChartRendering.test.tsx +536 -0
- package/Tests/App/Dashboard/UserElementEmail.test.tsx +447 -0
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +284 -0
- package/Tests/Models/AnalyticsModels/CommonModel.test.ts +312 -0
- package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +250 -0
- package/Tests/Server/Infrastructure/Postgres/EpisodeMemberNotifyIndexesMigration.test.ts +46 -18
- package/Tests/Server/Services/NetworkDeviceLabelRuleRun.test.ts +618 -0
- package/Tests/Server/Services/NetworkDeviceLinkParentValidation.test.ts +1043 -0
- package/Tests/Server/Services/NetworkSiteAssignmentRuleRun.test.ts +706 -0
- package/Tests/Server/Services/RunnerJobEnqueue.test.ts +412 -0
- package/Tests/Server/Types/Billing/PayAsYouGoMeteredPricing.test.ts +125 -0
- package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +508 -0
- package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +2 -2
- package/Tests/Server/Utils/AI/LLMServiceRetryPolicy.test.ts +450 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +556 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +547 -0
- package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +30 -0
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +699 -0
- package/Tests/Server/Utils/SeriesResourceLabels.test.ts +55 -0
- package/Tests/Server/Utils/Telemetry/InventoryEntityRegistry.test.ts +668 -0
- package/Tests/Types/API/URLMalformedTolerance.test.ts +301 -0
- package/Tests/Types/API/URLTelScheme.test.ts +261 -0
- package/Tests/Types/API/URLUnsupportedScheme.test.ts +148 -0
- package/Tests/Types/Billing/PayAsYouGoPricing.test.ts +64 -0
- package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +107 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +62 -0
- package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +184 -0
- package/Tests/Types/Runbook/RunbookStepType.test.ts +124 -0
- package/Tests/Types/Workflow/BaseModelComponents.test.ts +17 -0
- package/Tests/UI/Components/Button.test.tsx +279 -0
- package/Tests/UI/Components/Charts/ChartXAxisDataKey.test.tsx +256 -0
- package/Tests/UI/Components/Charts/DataPointUtil.test.ts +323 -0
- package/Tests/UI/Components/DictionaryValuePlaceholderAndSuggestions.test.tsx +595 -0
- package/Tests/UI/Components/Icon.test.tsx +57 -0
- package/Tests/UI/Components/List.test.tsx +20 -3
- package/Tests/UI/Components/LogsSavedViewsDropdown.test.tsx +304 -0
- package/Tests/UI/Components/LogsViewerClearSavedView.test.tsx +179 -0
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +349 -1
- package/Tests/UI/Components/Pagination.test.tsx +721 -146
- package/Tests/UI/Components/PaginationIntegration.test.tsx +386 -0
- package/Tests/UI/Components/PaginationUtil.test.ts +417 -0
- package/Tests/UI/Components/TelemetrySavedViewsDropdown.test.tsx +343 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnControl.test.ts +289 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnOperators.test.ts +271 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRow.test.ts +119 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.test.ts +968 -0
- package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +766 -0
- package/Tests/UI/Utils/RunNetworkRule.test.ts +320 -0
- package/Tests/Utils/APIRetryPolicy.test.ts +823 -0
- package/Tests/Utils/Monitor/NetworkDeviceRoleUtil.test.ts +502 -0
- package/Tests/Utils/Monitor/NetworkTopologyDeclaredHierarchy.test.ts +759 -0
- package/Tests/Utils/NetworkAutomation/RuleRunSummary.test.ts +286 -0
- package/Tests/Utils/Schema/BaseSchema.test.ts +651 -0
- package/Types/API/Protocol.ts +9 -0
- package/Types/API/URL.ts +286 -20
- package/Types/Billing/PayAsYouGoPricing.ts +47 -0
- package/Types/CustomField/CustomFieldType.ts +28 -0
- package/Types/Monitor/MonitorType.ts +11 -0
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
- package/Types/NetworkAutomation/RuleRunResult.ts +121 -0
- package/Types/Runbook/RunbookStepType.ts +23 -0
- package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +7 -0
- package/UI/Components/Button/Button.tsx +14 -22
- package/UI/Components/Charts/Area/AreaChart.tsx +4 -2
- package/UI/Components/Charts/Bar/BarChart.tsx +4 -2
- package/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.ts +13 -0
- package/UI/Components/Charts/Line/LineChart.tsx +4 -2
- package/UI/Components/Charts/Types/XAxis/XAxis.ts +6 -0
- package/UI/Components/Charts/Utils/DataPoint.ts +15 -12
- package/UI/Components/Dictionary/Dictionary.tsx +4 -39
- package/UI/Components/Icon/Icon.tsx +1 -1
- package/UI/Components/LogsViewer/LogsViewer.tsx +5 -1
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +8 -0
- package/UI/Components/LogsViewer/components/LogsPagination.tsx +29 -91
- package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +2 -0
- package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +66 -1
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +55 -0
- package/UI/Components/Pagination/Pagination.tsx +373 -328
- package/UI/Components/Pagination/PaginationUtil.ts +263 -0
- package/UI/Components/Pagination/Screenshots/README.md +15 -0
- package/UI/Components/Pagination/Screenshots/pagination-before-after.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-go-to-page-modal.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-long-list.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-mobile.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-telemetry.png +0 -0
- package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +66 -1
- package/UI/Components/TelemetryViewer/components/TelemetryPagination.tsx +38 -92
- package/UI/Components/TextArea/TextArea.tsx +3 -0
- package/UI/Components/Workflow/ArgumentsForm.tsx +18 -1
- package/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.tsx +177 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.tsx +243 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnControl.ts +255 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.tsx +178 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnOperators.ts +206 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnRow.ts +157 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.ts +517 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnValueInput.tsx +482 -0
- package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +131 -0
- package/UI/Components/Workflow/ColumnEditor/ModelRecordForm.tsx +163 -0
- package/UI/Components/Workflow/ModelColumnEditor.tsx +284 -100
- package/UI/Utils/NetworkAutomation/RunNetworkRule.ts +122 -0
- package/Utils/API.ts +243 -36
- package/Utils/Monitor/NetworkDeviceRoleUtil.ts +45 -0
- package/Utils/Monitor/NetworkTopologyUtil.ts +42 -2
- package/Utils/NetworkAutomation/RuleRunSummary.ts +147 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +45 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js +115 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RunnerJob.js +17 -2
- package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
- package/build/dist/Server/API/LlmProviderAPI.js +9 -1
- package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js +33 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +202 -0
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLinkService.js +253 -1
- package/build/dist/Server/Services/NetworkDeviceLinkService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +223 -12
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/RunnerJobService.js +20 -2
- package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
- package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js +12 -5
- package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js.map +1 -1
- package/build/dist/Server/Types/Database/JSONColumnQuery.js +40 -4
- package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +78 -22
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -98
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +7 -254
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +14 -2
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +27 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +285 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -0
- package/build/dist/Server/Utils/SSRFProtection.js +5 -4
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +128 -35
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
- package/build/dist/Types/API/Protocol.js +9 -0
- package/build/dist/Types/API/Protocol.js.map +1 -1
- package/build/dist/Types/API/URL.js +241 -18
- package/build/dist/Types/API/URL.js.map +1 -1
- package/build/dist/Types/Billing/PayAsYouGoPricing.js +41 -0
- package/build/dist/Types/Billing/PayAsYouGoPricing.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldType.js +26 -0
- package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +10 -0
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js +39 -0
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStepType.js +21 -0
- package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
- package/build/dist/UI/Components/Button/Button.js +10 -16
- package/build/dist/UI/Components/Button/Button.js.map +1 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +2 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +2 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js +12 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js.map +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js +2 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js +17 -10
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
- package/build/dist/UI/Components/Dictionary/Dictionary.js +4 -18
- package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +1 -1
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +3 -3
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +5 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js +14 -44
- package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +20 -2
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +42 -0
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js +174 -199
- package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
- package/build/dist/UI/Components/Pagination/PaginationUtil.js +160 -0
- package/build/dist/UI/Components/Pagination/PaginationUtil.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +20 -2
- package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js +23 -47
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js.map +1 -1
- package/build/dist/UI/Components/TextArea/TextArea.js +1 -1
- package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js +14 -2
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js +86 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js +119 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js +206 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js +57 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js +150 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js +67 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js +309 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js +204 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +66 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js +83 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js +187 -68
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js.map +1 -1
- package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js +75 -0
- package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js.map +1 -0
- package/build/dist/Utils/API.js +175 -34
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +37 -0
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +25 -3
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js +78 -0
- package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import SavedViewsDropdown, {
|
|
2
|
+
SavedViewsDropdownProps,
|
|
3
|
+
} from "../../../UI/Components/LogsViewer/components/SavedViewsDropdown";
|
|
4
|
+
import LogsViewerToolbar from "../../../UI/Components/LogsViewer/components/LogsViewerToolbar";
|
|
5
|
+
import LogsFacetSidebar from "../../../UI/Components/LogsViewer/components/LogsFacetSidebar";
|
|
6
|
+
import { LogsSavedViewOption } from "../../../UI/Components/LogsViewer/types";
|
|
7
|
+
import "@testing-library/jest-dom";
|
|
8
|
+
import {
|
|
9
|
+
cleanup,
|
|
10
|
+
fireEvent,
|
|
11
|
+
render,
|
|
12
|
+
screen,
|
|
13
|
+
RenderResult,
|
|
14
|
+
} from "@testing-library/react";
|
|
15
|
+
import React from "react";
|
|
16
|
+
import { afterEach, describe, expect, jest, test } from "@jest/globals";
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
* The logs explorer grew its saved views before the shared telemetry viewer
|
|
20
|
+
* did, so it carries its own copy of the dropdown — and its own copy of the
|
|
21
|
+
* bug in issue 3189: a view could be applied but never taken back off.
|
|
22
|
+
*
|
|
23
|
+
* Everything the telemetry dropdown gained is pinned here for the logs one
|
|
24
|
+
* too, plus the two extra surfaces logs has that traces does not: the toolbar
|
|
25
|
+
* that mounts the dropdown, and the facet sidebar, which lists the same views
|
|
26
|
+
* again down the left-hand side and re-applied them on click.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const VIEWS: Array<LogsSavedViewOption> = [
|
|
30
|
+
{ id: "errors", name: "Errors only" },
|
|
31
|
+
{ id: "checkout", name: "Checkout service", isDefault: true },
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const CLEAR_LABEL: string = "Clear view";
|
|
35
|
+
const MENU_PROBE: string = "+ Save Current View";
|
|
36
|
+
|
|
37
|
+
interface Handlers {
|
|
38
|
+
onSelect: (viewId: string) => void;
|
|
39
|
+
onClear: () => void;
|
|
40
|
+
onCreate: () => void;
|
|
41
|
+
onEdit: (viewId: string) => void;
|
|
42
|
+
onDelete: (viewId: string) => void;
|
|
43
|
+
onUpdateCurrent: () => void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function makeHandlers(): Handlers {
|
|
47
|
+
return {
|
|
48
|
+
onSelect: jest.fn(),
|
|
49
|
+
onClear: jest.fn(),
|
|
50
|
+
onCreate: jest.fn(),
|
|
51
|
+
onEdit: jest.fn(),
|
|
52
|
+
onDelete: jest.fn(),
|
|
53
|
+
onUpdateCurrent: jest.fn(),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function renderDropdown(
|
|
58
|
+
overrides: Partial<SavedViewsDropdownProps> = {},
|
|
59
|
+
handlers: Handlers = makeHandlers(),
|
|
60
|
+
): { handlers: Handlers; result: RenderResult } {
|
|
61
|
+
const props: SavedViewsDropdownProps = {
|
|
62
|
+
savedViews: VIEWS,
|
|
63
|
+
selectedSavedViewId: null,
|
|
64
|
+
...handlers,
|
|
65
|
+
...overrides,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return { handlers, result: render(<SavedViewsDropdown {...props} />) };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function trigger(): HTMLElement {
|
|
72
|
+
return screen.getAllByRole("button")[0]!;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function openMenu(): void {
|
|
76
|
+
fireEvent.click(trigger());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function isMenuOpen(): boolean {
|
|
80
|
+
return screen.queryByText(MENU_PROBE) !== null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function rowFor(name: string): HTMLElement {
|
|
84
|
+
return screen.getByRole("button", { name: name });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
describe("LogsViewer SavedViewsDropdown — clearing the applied view", () => {
|
|
88
|
+
afterEach(() => {
|
|
89
|
+
cleanup();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("clicking the applied view clears it instead of re-applying it", () => {
|
|
93
|
+
const { handlers } = renderDropdown({ selectedSavedViewId: "errors" });
|
|
94
|
+
|
|
95
|
+
openMenu();
|
|
96
|
+
fireEvent.click(rowFor("Errors only"));
|
|
97
|
+
|
|
98
|
+
expect(handlers.onClear).toHaveBeenCalledTimes(1);
|
|
99
|
+
expect(handlers.onSelect).not.toHaveBeenCalled();
|
|
100
|
+
expect(isMenuOpen()).toBe(false);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("the explicit Clear view row clears and closes the menu", () => {
|
|
104
|
+
const { handlers } = renderDropdown({ selectedSavedViewId: "errors" });
|
|
105
|
+
|
|
106
|
+
openMenu();
|
|
107
|
+
fireEvent.click(rowFor(CLEAR_LABEL));
|
|
108
|
+
|
|
109
|
+
expect(handlers.onClear).toHaveBeenCalledTimes(1);
|
|
110
|
+
expect(handlers.onSelect).not.toHaveBeenCalled();
|
|
111
|
+
expect(isMenuOpen()).toBe(false);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("the Clear view row is offered only while a view is applied", () => {
|
|
115
|
+
renderDropdown({ selectedSavedViewId: null });
|
|
116
|
+
|
|
117
|
+
openMenu();
|
|
118
|
+
|
|
119
|
+
expect(screen.queryByText(CLEAR_LABEL)).toBeNull();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("a selection pointing at a view that no longer exists offers no clear row", () => {
|
|
123
|
+
renderDropdown({ selectedSavedViewId: "deleted-view" });
|
|
124
|
+
|
|
125
|
+
openMenu();
|
|
126
|
+
|
|
127
|
+
expect(screen.queryByText(CLEAR_LABEL)).toBeNull();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("clicking a different view still applies it", () => {
|
|
131
|
+
const { handlers } = renderDropdown({ selectedSavedViewId: "errors" });
|
|
132
|
+
|
|
133
|
+
openMenu();
|
|
134
|
+
fireEvent.click(rowFor("Checkout service (default)"));
|
|
135
|
+
|
|
136
|
+
expect(handlers.onSelect).toHaveBeenCalledWith("checkout");
|
|
137
|
+
expect(handlers.onClear).not.toHaveBeenCalled();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("aria-pressed tracks which view is applied", () => {
|
|
141
|
+
renderDropdown({ selectedSavedViewId: "errors" });
|
|
142
|
+
|
|
143
|
+
openMenu();
|
|
144
|
+
|
|
145
|
+
expect(rowFor("Errors only")).toHaveAttribute("aria-pressed", "true");
|
|
146
|
+
expect(rowFor("Checkout service (default)")).toHaveAttribute(
|
|
147
|
+
"aria-pressed",
|
|
148
|
+
"false",
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("without onClear the applied view is still merely re-applied", () => {
|
|
153
|
+
const { handlers } = renderDropdown({
|
|
154
|
+
selectedSavedViewId: "errors",
|
|
155
|
+
onClear: undefined,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
openMenu();
|
|
159
|
+
|
|
160
|
+
expect(screen.queryByText(CLEAR_LABEL)).toBeNull();
|
|
161
|
+
|
|
162
|
+
fireEvent.click(rowFor("Errors only"));
|
|
163
|
+
|
|
164
|
+
expect(handlers.onSelect).toHaveBeenCalledWith("errors");
|
|
165
|
+
expect(handlers.onClear).not.toHaveBeenCalled();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test("Edit and Delete on the applied row do not clear it", () => {
|
|
169
|
+
const { handlers } = renderDropdown({ selectedSavedViewId: "errors" });
|
|
170
|
+
|
|
171
|
+
openMenu();
|
|
172
|
+
fireEvent.click(screen.getAllByRole("button", { name: "Edit" })[0]!);
|
|
173
|
+
|
|
174
|
+
expect(handlers.onEdit).toHaveBeenCalledWith("errors");
|
|
175
|
+
|
|
176
|
+
openMenu();
|
|
177
|
+
fireEvent.click(screen.getAllByRole("button", { name: "Delete" })[0]!);
|
|
178
|
+
|
|
179
|
+
expect(handlers.onDelete).toHaveBeenCalledWith("errors");
|
|
180
|
+
expect(handlers.onClear).not.toHaveBeenCalled();
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
/*
|
|
185
|
+
* The toolbar is the only thing that mounts the dropdown in the real logs
|
|
186
|
+
* explorer, so a clear handler that never reaches it is the same bug wearing
|
|
187
|
+
* a different hat. This renders the real toolbar rather than asserting on
|
|
188
|
+
* prop names.
|
|
189
|
+
*/
|
|
190
|
+
describe("LogsViewerToolbar hands the clear handler to the dropdown", () => {
|
|
191
|
+
afterEach(() => {
|
|
192
|
+
cleanup();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test("Clear view appears in the toolbar's dropdown and fires the host handler", () => {
|
|
196
|
+
const onClearSavedView: () => void = jest.fn();
|
|
197
|
+
const onSavedViewSelect: (viewId: string) => void = jest.fn();
|
|
198
|
+
|
|
199
|
+
render(
|
|
200
|
+
<LogsViewerToolbar
|
|
201
|
+
resultCount={12}
|
|
202
|
+
savedViews={VIEWS}
|
|
203
|
+
selectedSavedViewId="errors"
|
|
204
|
+
onSavedViewSelect={onSavedViewSelect}
|
|
205
|
+
onClearSavedView={onClearSavedView}
|
|
206
|
+
/>,
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
fireEvent.click(screen.getByRole("button", { name: /Errors only/ }));
|
|
210
|
+
fireEvent.click(screen.getByRole("button", { name: CLEAR_LABEL }));
|
|
211
|
+
|
|
212
|
+
expect(onClearSavedView).toHaveBeenCalledTimes(1);
|
|
213
|
+
expect(onSavedViewSelect).not.toHaveBeenCalled();
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test("a toolbar without a clear handler shows no Clear view row", () => {
|
|
217
|
+
render(
|
|
218
|
+
<LogsViewerToolbar
|
|
219
|
+
resultCount={12}
|
|
220
|
+
savedViews={VIEWS}
|
|
221
|
+
selectedSavedViewId="errors"
|
|
222
|
+
onSavedViewSelect={jest.fn()}
|
|
223
|
+
/>,
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
fireEvent.click(screen.getByRole("button", { name: /Errors only/ }));
|
|
227
|
+
|
|
228
|
+
expect(screen.queryByText(CLEAR_LABEL)).toBeNull();
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
/*
|
|
233
|
+
* The sidebar lists the same saved views a second time. It has no room for a
|
|
234
|
+
* "Clear view" row, so the toggle is the whole affordance there — and without
|
|
235
|
+
* it the sidebar quietly stayed a one-way door even after the dropdown was
|
|
236
|
+
* fixed.
|
|
237
|
+
*/
|
|
238
|
+
describe("LogsFacetSidebar toggles the applied view off", () => {
|
|
239
|
+
afterEach(() => {
|
|
240
|
+
cleanup();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
function renderSidebar(
|
|
244
|
+
onClearSavedView: (() => void) | undefined,
|
|
245
|
+
onSavedViewSelect: (viewId: string) => void,
|
|
246
|
+
): void {
|
|
247
|
+
render(
|
|
248
|
+
<LogsFacetSidebar
|
|
249
|
+
facetData={{}}
|
|
250
|
+
isLoading={false}
|
|
251
|
+
serviceMap={{}}
|
|
252
|
+
onIncludeFilter={jest.fn()}
|
|
253
|
+
onExcludeFilter={jest.fn()}
|
|
254
|
+
savedViews={VIEWS}
|
|
255
|
+
selectedSavedViewId="errors"
|
|
256
|
+
onSavedViewSelect={onSavedViewSelect}
|
|
257
|
+
onClearSavedView={onClearSavedView}
|
|
258
|
+
/>,
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
test("clicking the applied view clears it", () => {
|
|
263
|
+
const onClearSavedView: () => void = jest.fn();
|
|
264
|
+
const onSavedViewSelect: (viewId: string) => void = jest.fn();
|
|
265
|
+
|
|
266
|
+
renderSidebar(onClearSavedView, onSavedViewSelect);
|
|
267
|
+
fireEvent.click(screen.getByRole("button", { name: /Errors only/ }));
|
|
268
|
+
|
|
269
|
+
expect(onClearSavedView).toHaveBeenCalledTimes(1);
|
|
270
|
+
expect(onSavedViewSelect).not.toHaveBeenCalled();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test("clicking another view still applies it", () => {
|
|
274
|
+
const onClearSavedView: () => void = jest.fn();
|
|
275
|
+
const onSavedViewSelect: (viewId: string) => void = jest.fn();
|
|
276
|
+
|
|
277
|
+
renderSidebar(onClearSavedView, onSavedViewSelect);
|
|
278
|
+
fireEvent.click(screen.getByRole("button", { name: /Checkout service/ }));
|
|
279
|
+
|
|
280
|
+
expect(onSavedViewSelect).toHaveBeenCalledWith("checkout");
|
|
281
|
+
expect(onClearSavedView).not.toHaveBeenCalled();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
test("the applied row reports itself as pressed", () => {
|
|
285
|
+
renderSidebar(jest.fn(), jest.fn());
|
|
286
|
+
|
|
287
|
+
expect(screen.getByRole("button", { name: /Errors only/ })).toHaveAttribute(
|
|
288
|
+
"aria-pressed",
|
|
289
|
+
"true",
|
|
290
|
+
);
|
|
291
|
+
expect(
|
|
292
|
+
screen.getByRole("button", { name: /Checkout service/ }),
|
|
293
|
+
).toHaveAttribute("aria-pressed", "false");
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
test("a sidebar without a clear handler re-applies as before", () => {
|
|
297
|
+
const onSavedViewSelect: (viewId: string) => void = jest.fn();
|
|
298
|
+
|
|
299
|
+
renderSidebar(undefined, onSavedViewSelect);
|
|
300
|
+
fireEvent.click(screen.getByRole("button", { name: /Errors only/ }));
|
|
301
|
+
|
|
302
|
+
expect(onSavedViewSelect).toHaveBeenCalledWith("errors");
|
|
303
|
+
});
|
|
304
|
+
});
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { LogsSavedViewOption } from "../../../UI/Components/LogsViewer/types";
|
|
2
|
+
import "@testing-library/jest-dom";
|
|
3
|
+
import {
|
|
4
|
+
cleanup,
|
|
5
|
+
fireEvent,
|
|
6
|
+
render,
|
|
7
|
+
screen,
|
|
8
|
+
waitFor,
|
|
9
|
+
} from "@testing-library/react";
|
|
10
|
+
import React from "react";
|
|
11
|
+
import { afterEach, describe, expect, jest, test } from "@jest/globals";
|
|
12
|
+
import getJestMockFunction, { MockFunction } from "../../MockType";
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* LogsViewer is the container between the logs explorer and the two places a
|
|
16
|
+
* saved view can be picked — the toolbar dropdown and the facet sidebar. Both
|
|
17
|
+
* of those are covered directly in LogsSavedViewsDropdown.test.tsx, and the
|
|
18
|
+
* host's clearSavedView is covered in App/Tests/Dashboard. This file is the
|
|
19
|
+
* middle link: the passthrough that connects them.
|
|
20
|
+
*
|
|
21
|
+
* It is worth its own file because that link is invisible when it breaks.
|
|
22
|
+
* Deleting `onClearSavedView: props.onClearSavedView` from the toolbar props
|
|
23
|
+
* object leaves the dropdown rendering, the host handler defined, every other
|
|
24
|
+
* test green — and the "Clear view" row simply never appears again, which is
|
|
25
|
+
* the original bug back in place.
|
|
26
|
+
*
|
|
27
|
+
* The container loads services and log attributes on mount, so both API
|
|
28
|
+
* surfaces are mocked out; nothing here depends on what they return beyond
|
|
29
|
+
* their resolving.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
* Declared before jest.mock but dereferenced inside the factories: ts-jest
|
|
34
|
+
* hoists the jest.mock calls above these initializers, so naming the mocks
|
|
35
|
+
* directly in a factory would capture undefined.
|
|
36
|
+
*/
|
|
37
|
+
const getListMock: MockFunction = getJestMockFunction();
|
|
38
|
+
const postMock: MockFunction = getJestMockFunction();
|
|
39
|
+
|
|
40
|
+
jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
|
|
41
|
+
return {
|
|
42
|
+
__esModule: true,
|
|
43
|
+
default: {
|
|
44
|
+
getList: (...args: Array<any>) => {
|
|
45
|
+
return getListMock(...args);
|
|
46
|
+
},
|
|
47
|
+
getCommonHeaders: () => {
|
|
48
|
+
return {};
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
jest.mock("../../../UI/Utils/API/API", () => {
|
|
55
|
+
return {
|
|
56
|
+
__esModule: true,
|
|
57
|
+
default: {
|
|
58
|
+
post: (...args: Array<any>) => {
|
|
59
|
+
return postMock(...args);
|
|
60
|
+
},
|
|
61
|
+
getFriendlyErrorMessage: (error: Error) => {
|
|
62
|
+
return error.message;
|
|
63
|
+
},
|
|
64
|
+
getFriendlyMessage: (error: Error) => {
|
|
65
|
+
return error.message;
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
getListMock.mockImplementation(() => {
|
|
72
|
+
return Promise.resolve({ data: [], count: 0, skip: 0, limit: 0 });
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
postMock.mockImplementation(() => {
|
|
76
|
+
return Promise.resolve({ data: {} });
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Imported after the mock so the container picks the mocked ModelAPI up.
|
|
80
|
+
import LogsViewer from "../../../UI/Components/LogsViewer/LogsViewer";
|
|
81
|
+
|
|
82
|
+
const VIEWS: Array<LogsSavedViewOption> = [
|
|
83
|
+
{ id: "errors", name: "Errors only" },
|
|
84
|
+
{ id: "checkout", name: "Checkout service", isDefault: true },
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
const CLEAR_LABEL: string = "Clear view";
|
|
88
|
+
|
|
89
|
+
interface RenderedViewer {
|
|
90
|
+
onClearSavedView: () => void;
|
|
91
|
+
onSavedViewSelect: (viewId: string) => void;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function renderViewer(
|
|
95
|
+
withClearHandler: boolean,
|
|
96
|
+
): Promise<RenderedViewer> {
|
|
97
|
+
const onClearSavedView: () => void = jest.fn();
|
|
98
|
+
const onSavedViewSelect: (viewId: string) => void = jest.fn();
|
|
99
|
+
|
|
100
|
+
render(
|
|
101
|
+
<LogsViewer
|
|
102
|
+
logs={[]}
|
|
103
|
+
isLoading={false}
|
|
104
|
+
filterData={{}}
|
|
105
|
+
onFilterChanged={jest.fn()}
|
|
106
|
+
facetData={{}}
|
|
107
|
+
savedViews={VIEWS}
|
|
108
|
+
selectedSavedViewId="errors"
|
|
109
|
+
onSavedViewSelect={onSavedViewSelect}
|
|
110
|
+
{...(withClearHandler ? { onClearSavedView: onClearSavedView } : {})}
|
|
111
|
+
/>,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
// The container renders a loader until its service lookup resolves.
|
|
115
|
+
await waitFor(() => {
|
|
116
|
+
expect(screen.getAllByRole("button").length).toBeGreaterThan(0);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
onClearSavedView: onClearSavedView,
|
|
121
|
+
onSavedViewSelect: onSavedViewSelect,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function savedViewButtons(): Array<HTMLElement> {
|
|
126
|
+
return screen.getAllByRole("button", { name: /Errors only/ });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
describe("LogsViewer forwards the clear handler to both saved-view surfaces", () => {
|
|
130
|
+
afterEach(() => {
|
|
131
|
+
cleanup();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("the toolbar dropdown offers Clear view and it reaches the host", async () => {
|
|
135
|
+
const { onClearSavedView, onSavedViewSelect } = await renderViewer(true);
|
|
136
|
+
|
|
137
|
+
/*
|
|
138
|
+
* The sidebar lists the view too, so the trigger is picked by its
|
|
139
|
+
* dropdown, not by name alone: the toolbar's trigger is the one that
|
|
140
|
+
* opens a panel containing the clear row.
|
|
141
|
+
*/
|
|
142
|
+
for (const button of savedViewButtons()) {
|
|
143
|
+
fireEvent.click(button);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const clearRow: HTMLElement = screen.getByRole("button", {
|
|
147
|
+
name: CLEAR_LABEL,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
fireEvent.click(clearRow);
|
|
151
|
+
|
|
152
|
+
expect(onClearSavedView).toHaveBeenCalled();
|
|
153
|
+
expect(onSavedViewSelect).not.toHaveBeenCalled();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("the facet sidebar's applied row toggles off through the same handler", async () => {
|
|
157
|
+
const { onClearSavedView, onSavedViewSelect } = await renderViewer(true);
|
|
158
|
+
|
|
159
|
+
/*
|
|
160
|
+
* The sidebar's entry is a plain row rather than a dropdown trigger, so
|
|
161
|
+
* clicking it is the clear. It is the first of the two matches because
|
|
162
|
+
* the sidebar renders before the table column.
|
|
163
|
+
*/
|
|
164
|
+
fireEvent.click(savedViewButtons()[0]!);
|
|
165
|
+
|
|
166
|
+
expect(onClearSavedView).toHaveBeenCalled();
|
|
167
|
+
expect(onSavedViewSelect).not.toHaveBeenCalled();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("a host that passes no clear handler still gets the old behaviour", async () => {
|
|
171
|
+
const { onClearSavedView, onSavedViewSelect } = await renderViewer(false);
|
|
172
|
+
|
|
173
|
+
fireEvent.click(savedViewButtons()[0]!);
|
|
174
|
+
|
|
175
|
+
expect(screen.queryByText(CLEAR_LABEL)).toBeNull();
|
|
176
|
+
expect(onClearSavedView).not.toHaveBeenCalled();
|
|
177
|
+
expect(onSavedViewSelect).toHaveBeenCalledWith("errors");
|
|
178
|
+
});
|
|
179
|
+
});
|