From c67e9951cf61b543b2c083baded60ccfba271108 Mon Sep 17 00:00:00 2001 From: Julia Bardi Date: Wed, 9 Feb 2022 13:09:52 +0100 Subject: [PATCH 1/3] edit package policy test --- x-pack/plugins/fleet/README.md | 15 +- .../edit_package_policy_page/index.test.tsx | 256 ++++++++++++++++++ .../edit_package_policy_page/index.tsx | 2 + .../applications/integrations/hooks/index.ts | 4 +- 4 files changed, 268 insertions(+), 9 deletions(-) create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx diff --git a/x-pack/plugins/fleet/README.md b/x-pack/plugins/fleet/README.md index f67314ba49fa4..8fc7967234e8f 100644 --- a/x-pack/plugins/fleet/README.md +++ b/x-pack/plugins/fleet/README.md @@ -147,10 +147,11 @@ Write stories by creating `.stories.tsx` files colocated with the components you The projects below are dependent on Fleet, most using Fleet API as well. In case of breaking changes in Fleet functionality/API, the project owners have to be notified to make sure they can plan for the necessary changes on their end to avoid unexpected break in functionality. - * [Elastic Agent](https://github.com/elastic/beats/blob/master/x-pack/elastic-agent): uses Fleet API to enroll agents. [See here](https://github.com/elastic/beats/blob/master/x-pack/elastic-agent/pkg/agent/cmd/container.go) - * [Fleet Server](https://github.com/elastic/fleet-server): uses Fleet API to enroll fleet server [See here](https://github.com/elastic/fleet-server/blob/master/cmd/fleet/router.go) - * [elastic-package](https://github.com/elastic/elastic-package): command line tool, uses Fleet with docker compose and Fleet API [See here](https://github.com/elastic/elastic-package/tree/master/internal/kibana) - * [Azure VM extension](https://github.com/elastic/azure-vm-extension): automation tool for Azure VMs, uses Fleet API to enroll agents [See here](https://github.com/elastic/azure-vm-extension/blob/main/src/handler/windows/scripts/enable.ps1) - * [e2e-testing](https://github.com/elastic/e2e-testing): internal project that runs Fleet and tests Fleet API [See here](https://github.com/elastic/e2e-testing/tree/main/internal/kibana) - * [observability-test-environments](https://github.com/elastic/observability-test-environments): internal project, uses Fleet API [See here](https://github.com/elastic/observability-test-environments/blob/master/ansible/tasks-fleet-config.yml) - * [ECK](https://github.com/elastic/cloud-on-k8s): Elastic Cloud on Kubernetes, orchestrates Elastic Stack applications, including Kibana with Fleet (no direct dependency, has examples that include Fleet config) [See here](https://github.com/elastic/cloud-on-k8s/blob/main/docs/orchestrating-elastic-stack-applications/agent-fleet.asciidoc) \ No newline at end of file + * [Elastic Agent](https://github.com/elastic/beats/blob/master/x-pack/elastic-agent): uses Fleet API to enroll agents. [Check here](https://github.com/elastic/beats/blob/master/x-pack/elastic-agent/pkg/agent/cmd/container.go) + * [Fleet Server](https://github.com/elastic/fleet-server): uses Fleet API to enroll fleet server [Check here](https://github.com/elastic/fleet-server/blob/master/cmd/fleet/router.go) + * [elastic-package](https://github.com/elastic/elastic-package): command line tool, uses Fleet with docker compose and Fleet API [Check here](https://github.com/elastic/elastic-package/tree/master/internal/kibana) + * [Azure VM extension](https://github.com/elastic/azure-vm-extension): automation tool for Azure VMs, uses Fleet API to enroll agents [Check here](https://github.com/elastic/azure-vm-extension/blob/main/src/handler/windows/scripts/enable.ps1) + * [e2e-testing](https://github.com/elastic/e2e-testing): internal project that runs Fleet and tests Fleet API [Check here](https://github.com/elastic/e2e-testing/tree/main/internal/kibana) + * [observability-test-environments](https://github.com/elastic/observability-test-environments): internal project, uses Fleet API [Check here](https://github.com/elastic/observability-test-environments/blob/master/ansible/tasks-fleet-config.yml) + * [ECK](https://github.com/elastic/cloud-on-k8s): Elastic Cloud on Kubernetes, orchestrates Elastic Stack applications, including Kibana with Fleet (no direct dependency, has examples that include Fleet config) [Check here](https://github.com/elastic/cloud-on-k8s/blob/main/docs/orchestrating-elastic-stack-applications/agent-fleet.asciidoc) + * [APM Server](https://github.com/elastic/apm-server) APM Server, receives data from Elastic APM agents. Using docker compose for testing. [Check here](https://github.com/elastic/apm-server/pull/7227/files) \ No newline at end of file diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx new file mode 100644 index 0000000000000..a90f422d47b5a --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx @@ -0,0 +1,256 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { fireEvent, act, waitFor } from '@testing-library/react'; + +import type { TestRenderer } from '../../../../../mock'; +import { createFleetTestRendererMock } from '../../../../../mock'; + +import { + useUIExtension, + sendGetOneAgentPolicy, + sendGetOnePackagePolicy, + sendUpgradePackagePolicyDryRun, +} from '../../../hooks'; +import { useGetOnePackagePolicy } from '../../../../integrations/hooks'; + +import { EditPackagePolicyPage } from '.'; + +jest.mock('../../../hooks', () => { + return { + ...jest.requireActual('../../../hooks'), + sendGetAgentStatus: jest.fn().mockResolvedValue({ data: { results: { total: 0 } } }), + sendUpdatePackagePolicy: jest.fn(), + sendGetOnePackagePolicy: jest.fn(), + sendGetOneAgentPolicy: jest.fn(), + sendUpgradePackagePolicyDryRun: jest.fn(), + sendGetPackageInfoByKey: jest.fn().mockImplementation((name, version) => + Promise.resolve({ + data: { + item: { + name, + title: 'Nginx', + version, + release: 'ga', + description: 'Collect logs and metrics from Nginx HTTP servers with Elastic Agent.', + policy_templates: [ + { + name: 'nginx', + title: 'Nginx logs and metrics', + description: 'Collect logs and metrics from Nginx instances', + inputs: [ + { + type: 'logfile', + title: 'Collect logs from Nginx instances', + description: 'Collecting Nginx access and error logs', + }, + ], + multiple: true, + }, + ], + data_streams: [ + { + type: 'logs', + dataset: 'nginx.access', + title: 'Nginx access logs', + release: 'experimental', + ingest_pipeline: 'default', + streams: [ + { + input: 'logfile', + vars: [ + { + name: 'paths', + type: 'text', + title: 'Paths', + multi: true, + required: true, + show_user: true, + default: ['/var/log/nginx/access.log*'], + }, + ], + template_path: 'stream.yml.hbs', + title: 'Nginx access logs', + description: 'Collect Nginx access logs', + enabled: true, + }, + ], + package: 'nginx', + path: 'access', + }, + ], + latestVersion: version, + removable: true, + keepPoliciesUpToDate: false, + status: 'not_installed', + }, + }, + isLoading: false, + }) + ), + useUIExtension: jest.fn(), + }; +}); + +jest.mock('../../../../integrations/hooks', () => { + return { + ...jest.requireActual('../../../../integrations/hooks'), + useGetOnePackagePolicy: jest.fn(), + }; +}); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useRouteMatch: jest.fn().mockReturnValue({ + params: { + packagePolicyId: 'nginx-1', + }, + }), +})); + +const mockPackagePolicy = { + id: 'nginx-1', + name: 'nginx-1', + namespace: 'default', + description: 'Nginx description', + package: { name: 'nginx', title: 'Nginx', version: '1.3.0' }, + enabled: true, + policy_id: 'agent-policy-1', + output_id: '', + inputs: [ + { + type: 'logfile', + policy_template: 'nginx', + enabled: true, + streams: [ + { + enabled: true, + data_stream: { type: 'logs', dataset: 'nginx.access' }, + vars: { + paths: { value: ['/var/log/nginx/access.log*'], type: 'text' }, + }, + }, + ], + }, + ], +}; + +const mockPackagePolicyNewVersion = { + ...mockPackagePolicy, + package: { name: 'nginx', title: 'Nginx', version: '1.4.0' }, +}; + +const TestComponent = async () => { + return { + default: () => { + return
; + }, + }; +}; + +describe('edit package policy page', () => { + let testRenderer: TestRenderer; + let renderResult: ReturnType; + const render = () => (renderResult = testRenderer.render()); + + beforeEach(() => { + testRenderer = createFleetTestRendererMock(); + + (useGetOnePackagePolicy as jest.MockedFunction).mockReturnValue({ + data: { + item: mockPackagePolicy, + }, + }); + (sendGetOnePackagePolicy as jest.MockedFunction).mockResolvedValue({ + data: { + item: mockPackagePolicy, + }, + }); + (sendGetOneAgentPolicy as jest.MockedFunction).mockResolvedValue({ + data: { item: { id: 'agent-policy-1', name: 'Agent policy 1', namespace: 'default' } }, + }); + }); + + it('should disable submit button on invalid form with empty package var', async () => { + (sendUpgradePackagePolicyDryRun as jest.MockedFunction).mockResolvedValue({ + data: [ + { + diff: [mockPackagePolicy, mockPackagePolicy], + }, + ], + }); + render(); + + await waitFor(() => { + expect(renderResult.getByText('Collect logs from Nginx instances')).toBeInTheDocument(); + expect(renderResult.getByDisplayValue('nginx-1')).toBeInTheDocument(); + expect(renderResult.getByDisplayValue('Nginx description')).toBeInTheDocument(); + }); + + await act(async () => { + fireEvent.click(renderResult.getByLabelText('Show logfile inputs')); + }); + + await act(async () => { + fireEvent.change(renderResult.getByDisplayValue('/var/log/nginx/access.log*'), { + target: { value: '' }, + }); + }); + + expect( + renderResult.getByText('Your integration policy has errors. Please fix them before saving.') + ).toBeInTheDocument(); + expect(renderResult.getByText(/Save integration/).closest('button')!).toBeDisabled(); + }); + + it('should show ready for upgrade if package useLatestPackageVersion and no conflicts', async () => { + (useUIExtension as jest.MockedFunction).mockReturnValue({ + useLatestPackageVersion: true, + Component: TestComponent, + }); + (sendUpgradePackagePolicyDryRun as jest.MockedFunction).mockResolvedValue({ + data: [ + { + diff: [mockPackagePolicy, mockPackagePolicyNewVersion], + }, + ], + }); + + render(); + + await waitFor(() => { + expect(renderResult.getByText(/Upgrade integration/).closest('button')!).not.toBeDisabled(); + expect( + renderResult.getByText( + 'This integration is ready to be upgraded from version 1.3.0 to 1.4.0. Review the changes below and save to upgrade.' + ) + ).toBeInTheDocument(); + }); + }); + + it('should show review field conflicts if package useLatestPackageVersion and has conflicts', async () => { + (useUIExtension as jest.MockedFunction).mockReturnValue({ + useLatestPackageVersion: true, + Component: TestComponent, + }); + (sendUpgradePackagePolicyDryRun as jest.MockedFunction).mockResolvedValue({ + data: [ + { + hasErrors: true, + diff: [mockPackagePolicy, mockPackagePolicyNewVersion], + }, + ], + }); + + render(); + + await waitFor(() => { + expect(renderResult.getByText('Review field conflicts')).toBeInTheDocument(); + }); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index 8151215c3cced..370399bb81013 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -347,6 +347,8 @@ export const EditPackagePolicyForm = memo<{ : false; if (!hasValidationErrors) { setFormState('VALID'); + } else { + setFormState('INVALID'); } }, [packagePolicy, updatePackagePolicyValidation] diff --git a/x-pack/plugins/fleet/public/applications/integrations/hooks/index.ts b/x-pack/plugins/fleet/public/applications/integrations/hooks/index.ts index 9e4cdde064e70..9c907436af6e3 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/hooks/index.ts +++ b/x-pack/plugins/fleet/public/applications/integrations/hooks/index.ts @@ -6,8 +6,8 @@ */ export * from '../../../hooks'; -export { useBreadcrumbs } from './use_breadcrumbs'; -export { useLinks } from './use_links'; +export * from './use_breadcrumbs'; +export * from './use_links'; export * from './use_local_search'; export * from './use_package_install'; export * from './use_agent_policy_context'; From 2ec6255a22de92cba8603b3ebf11e3f0a68f5ad0 Mon Sep 17 00:00:00 2001 From: Julia Bardi Date: Wed, 9 Feb 2022 13:42:54 +0100 Subject: [PATCH 2/3] moved out styled component, added null checks --- .../components/package_policy_input_config.tsx | 3 ++- .../components/package_policy_input_panel.tsx | 4 ++-- .../components/package_policy_input_stream.tsx | 10 +++++----- .../agent_policy/edit_package_policy_page/index.tsx | 12 ++++++------ 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/package_policy_input_config.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/package_policy_input_config.tsx index 50305249ab7f4..73a74d09abb33 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/package_policy_input_config.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/package_policy_input_config.tsx @@ -105,7 +105,8 @@ export const PackagePolicyInputConfig: React.FunctionComponent<{ {requiredVars.map((varDef) => { const { name: varName, type: varType } = varDef; - const { value, frozen } = packagePolicyInput.vars![varName]; + if (!packagePolicyInput.vars) return; + const { value, frozen } = packagePolicyInput.vars[varName]; return ( {hasInputStreams ? : } @@ -238,7 +238,7 @@ export const PackagePolicyInputPanel: React.FunctionComponent<{ updatePackagePolicyInput(updatedInput); }} inputStreamValidationResults={ - inputValidationResults.streams![packagePolicyInputStream!.data_stream!.dataset] + inputValidationResults?.streams![packagePolicyInputStream!.data_stream!.dataset] } forceShowErrors={forceShowErrors} /> diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/package_policy_input_stream.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/package_policy_input_stream.tsx index edc7d6f02bc0a..3e376d4344938 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/package_policy_input_stream.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/package_policy_input_stream.tsx @@ -70,9 +70,9 @@ export const PackagePolicyInputStreamConfig: React.FunctionComponent<{ const advancedVarsWithErrorsCount: number = useMemo( () => advancedVars.filter( - ({ name: varName }) => inputStreamValidationResults.vars?.[varName]?.length + ({ name: varName }) => inputStreamValidationResults?.vars?.[varName]?.length ).length, - [advancedVars, inputStreamValidationResults.vars] + [advancedVars, inputStreamValidationResults?.vars] ); return ( @@ -106,7 +106,7 @@ export const PackagePolicyInputStreamConfig: React.FunctionComponent<{ {requiredVars.map((varDef) => { - if (!packagePolicyInputStream.vars) return null; + if (!packagePolicyInputStream?.vars) return null; const { name: varName, type: varType } = varDef; const varConfigEntry = packagePolicyInputStream.vars?.[varName]; const value = varConfigEntry?.value; @@ -129,7 +129,7 @@ export const PackagePolicyInputStreamConfig: React.FunctionComponent<{ }, }); }} - errors={inputStreamValidationResults.vars![varName]} + errors={inputStreamValidationResults?.vars![varName]} forceShowErrors={forceShowErrors} /> @@ -187,7 +187,7 @@ export const PackagePolicyInputStreamConfig: React.FunctionComponent<{ }, }); }} - errors={inputStreamValidationResults.vars![varName]} + errors={inputStreamValidationResults?.vars![varName]} forceShowErrors={forceShowErrors} /> diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index 370399bb81013..c731703e43bc6 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -734,6 +734,12 @@ const UpgradeBreadcrumb: React.FunctionComponent<{ return null; }; +const FlyoutBody = styled(EuiFlyoutBody)` + .euiFlyoutBody__overflowContent { + padding: 0; + } +`; + const UpgradeStatusCallout: React.FunctionComponent<{ dryRunData: UpgradePackagePolicyDryRunResponse; }> = ({ dryRunData }) => { @@ -747,12 +753,6 @@ const UpgradeStatusCallout: React.FunctionComponent<{ const [currentPackagePolicy, proposedUpgradePackagePolicy] = dryRunData[0].diff || []; - const FlyoutBody = styled(EuiFlyoutBody)` - .euiFlyoutBody__overflowContent { - padding: 0; - } - `; - return ( <> {isPreviousVersionFlyoutOpen && currentPackagePolicy && ( From 05f78f1e10d5f3d34b9e71eb4ea43e4934f3204c Mon Sep 17 00:00:00 2001 From: Julia Bardi Date: Thu, 10 Feb 2022 08:51:54 +0100 Subject: [PATCH 3/3] added tests for submit --- .../edit_package_policy_page/index.test.tsx | 145 ++++++++++++++++-- 1 file changed, 134 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx index a90f422d47b5a..3a5050b1b6d06 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx @@ -16,11 +16,15 @@ import { sendGetOneAgentPolicy, sendGetOnePackagePolicy, sendUpgradePackagePolicyDryRun, + sendUpdatePackagePolicy, + useStartServices, } from '../../../hooks'; import { useGetOnePackagePolicy } from '../../../../integrations/hooks'; import { EditPackagePolicyPage } from '.'; +type MockFn = jest.MockedFunction; + jest.mock('../../../hooks', () => { return { ...jest.requireActual('../../../hooks'), @@ -94,6 +98,33 @@ jest.mock('../../../hooks', () => { }) ), useUIExtension: jest.fn(), + useStartServices: jest.fn().mockReturnValue({ + application: { navigateToApp: jest.fn(), navigateToUrl: jest.fn() }, + notifications: { + toasts: { + addError: jest.fn(), + addSuccess: jest.fn(), + }, + }, + docLinks: { + links: { + fleet: {}, + }, + }, + http: { + basePath: { + get: () => 'http://localhost:5620', + prepend: (url: string) => 'http://localhost:5620' + url, + }, + }, + chrome: { + docTitle: { + change: jest.fn(), + }, + setBreadcrumbs: jest.fn(), + }, + }), + useLink: jest.fn().mockReturnValue({ getHref: jest.fn().mockReturnValue('/navigate/path') }), }; }); @@ -136,6 +167,7 @@ const mockPackagePolicy = { }, }, ], + vars: undefined, }, ], }; @@ -161,29 +193,32 @@ describe('edit package policy page', () => { beforeEach(() => { testRenderer = createFleetTestRendererMock(); - (useGetOnePackagePolicy as jest.MockedFunction).mockReturnValue({ + (useGetOnePackagePolicy as MockFn).mockReturnValue({ data: { item: mockPackagePolicy, }, }); - (sendGetOnePackagePolicy as jest.MockedFunction).mockResolvedValue({ + (sendGetOnePackagePolicy as MockFn).mockResolvedValue({ data: { item: mockPackagePolicy, }, }); - (sendGetOneAgentPolicy as jest.MockedFunction).mockResolvedValue({ + (sendGetOneAgentPolicy as MockFn).mockResolvedValue({ data: { item: { id: 'agent-policy-1', name: 'Agent policy 1', namespace: 'default' } }, }); - }); - - it('should disable submit button on invalid form with empty package var', async () => { - (sendUpgradePackagePolicyDryRun as jest.MockedFunction).mockResolvedValue({ + (sendUpgradePackagePolicyDryRun as MockFn).mockResolvedValue({ data: [ { diff: [mockPackagePolicy, mockPackagePolicy], }, ], }); + (sendUpdatePackagePolicy as MockFn).mockResolvedValue({}); + (useStartServices().application.navigateToUrl as MockFn).mockReset(); + (useStartServices().notifications.toasts.addError as MockFn).mockReset(); + }); + + it('should disable submit button on invalid form with empty package var', async () => { render(); await waitFor(() => { @@ -206,14 +241,102 @@ describe('edit package policy page', () => { renderResult.getByText('Your integration policy has errors. Please fix them before saving.') ).toBeInTheDocument(); expect(renderResult.getByText(/Save integration/).closest('button')!).toBeDisabled(); + + renderResult.getAllByRole('link', { name: 'Cancel' }).forEach((btn) => { + expect(btn).toHaveAttribute('href', '/navigate/path'); + }); + }); + + it('should navigate on submit', async () => { + render(); + + await waitFor(() => { + expect(renderResult.getByText('Collect logs from Nginx instances')).toBeInTheDocument(); + }); + act(() => { + fireEvent.click(renderResult.getByRole('switch')); + }); + + await act(async () => { + fireEvent.click(renderResult.getByText('Save integration').closest('button')!); + }); + + const { id, ...restProps } = mockPackagePolicy; + expect(sendUpdatePackagePolicy).toHaveBeenCalledWith('nginx-1', { + ...restProps, + inputs: [ + { + ...mockPackagePolicy.inputs[0], + enabled: false, + streams: [ + { + ...mockPackagePolicy.inputs[0].streams[0], + enabled: false, + }, + ], + }, + ], + }); + expect(useStartServices().application.navigateToUrl).toHaveBeenCalledWith('/navigate/path'); + }); + + it('should show out of date error on 409 statusCode on submit', async () => { + (sendUpdatePackagePolicy as MockFn).mockResolvedValue({ error: { statusCode: 409 } }); + + render(); + + await waitFor(() => { + expect(renderResult.getByText('Collect logs from Nginx instances')).toBeInTheDocument(); + }); + act(() => { + fireEvent.click(renderResult.getByRole('switch')); + }); + + await act(async () => { + fireEvent.click(renderResult.getByText('Save integration').closest('button')!); + }); + + expect(useStartServices().notifications.toasts.addError).toHaveBeenCalledWith( + { statusCode: 409 }, + { + title: "Error updating 'nginx-1'", + toastMessage: 'Data is out of date. Refresh the page to get the latest policy.', + } + ); + + expect(useStartServices().application.navigateToUrl).not.toHaveBeenCalled(); + }); + + it('should show generic error on other statusCode on submit', async () => { + (sendUpdatePackagePolicy as MockFn).mockResolvedValue({ error: { statusCode: 500 } }); + + render(); + + await waitFor(() => { + expect(renderResult.getByText('Collect logs from Nginx instances')).toBeInTheDocument(); + }); + act(() => { + fireEvent.click(renderResult.getByRole('switch')); + }); + + await act(async () => { + fireEvent.click(renderResult.getByText('Save integration').closest('button')!); + }); + + expect(useStartServices().notifications.toasts.addError).toHaveBeenCalledWith( + { statusCode: 500 }, + { title: "Error updating 'nginx-1'" } + ); + + expect(useStartServices().application.navigateToUrl).not.toHaveBeenCalled(); }); it('should show ready for upgrade if package useLatestPackageVersion and no conflicts', async () => { - (useUIExtension as jest.MockedFunction).mockReturnValue({ + (useUIExtension as MockFn).mockReturnValue({ useLatestPackageVersion: true, Component: TestComponent, }); - (sendUpgradePackagePolicyDryRun as jest.MockedFunction).mockResolvedValue({ + (sendUpgradePackagePolicyDryRun as MockFn).mockResolvedValue({ data: [ { diff: [mockPackagePolicy, mockPackagePolicyNewVersion], @@ -234,11 +357,11 @@ describe('edit package policy page', () => { }); it('should show review field conflicts if package useLatestPackageVersion and has conflicts', async () => { - (useUIExtension as jest.MockedFunction).mockReturnValue({ + (useUIExtension as MockFn).mockReturnValue({ useLatestPackageVersion: true, Component: TestComponent, }); - (sendUpgradePackagePolicyDryRun as jest.MockedFunction).mockResolvedValue({ + (sendUpgradePackagePolicyDryRun as MockFn).mockResolvedValue({ data: [ { hasErrors: true,