From 09d09a0e9e742e2f916537ca491990ac7c49df24 Mon Sep 17 00:00:00 2001 From: Yu Jin <112784385+yujin-emma@users.noreply.github.com> Date: Thu, 16 May 2024 14:07:34 -0700 Subject: [PATCH] [Multiple Datasource Test]Add test for toast button and validation form (#6755) * add test for toast button and validation form Signed-off-by: yujin-emma * Changeset file for PR #6755 created/updated Signed-off-by: yujin-emma * Update src/plugins/data_source_management/public/components/toast_button/manage_data_source_button.tsx Co-authored-by: Lu Yu Signed-off-by: Yu Jin <112784385+yujin-emma@users.noreply.github.com> Signed-off-by: yujin-emma * Update manage_data_source_button.test.tsx Signed-off-by: yujin-emma * [Multiple Datasource Test] Add test for edit data source form (#6742) * add test for edit data source form Signed-off-by: yujin-emma * Changeset file for PR #6742 created/updated --------- Signed-off-by: yujin-emma Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Signed-off-by: yujin-emma * [MQL] support enhancing language selector (#6613) Enable with `data.enhancements.enabled: true` Allows for enhancing the data plugin UI service and search service. #### Remaining work * Address issue with time range being invalid if previous state successfully queried and set it with a time range format that is invalid for the new query language * For example, DQL with quick time range (4 weeks to now), get results. Switch to PPL, even though PPL has a default time range enhancement. The props date range saved in the app state takes priority and sets the time range to quick range causing an error. I can still modify the time range and get a successful query but it will first fail until the user updates it to a non quick time range. * Add tests * Disable for plugins that do not support the functionality * By default index patterns are created with a unique ID. However, it can be enabled to create an index pattern with a custom ID that matches the name of the index pattern (which in turn maps to indices). * For seamless integration, the temp data frame would need to check if the index pattern that maps to the data frame name. And get it's id. * This means that dashboards with visualizations that were created with an index pattern unique ID still require the existing index pattern to exist in memory. ### Issues Resolved closes #6639 closes #6311 partially resolves: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/5504 * add error data frame Signed-off-by: Paul Sebastian move language to left, some styling and disable per app name Signed-off-by: Kawika Avilla --------- Signed-off-by: Kawika Avilla Signed-off-by: Paul Sebastian Co-authored-by: Paul Sebastian Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Signed-off-by: yujin-emma * Make Field Name Search Filter Case Insensitive (#6759) * Make Field Name Filter Case Insensitive Signed-off-by: Suchit Sahoo * Changeset file for PR #6759 created/updated --------- Signed-off-by: Suchit Sahoo Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Signed-off-by: yujin-emma * address naming for manage data source button test id Signed-off-by: yujin-emma --------- Signed-off-by: yujin-emma Signed-off-by: Yu Jin <112784385+yujin-emma@users.noreply.github.com> Signed-off-by: Kawika Avilla Signed-off-by: Paul Sebastian Signed-off-by: Suchit Sahoo Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Co-authored-by: Lu Yu Co-authored-by: Kawika Avilla Co-authored-by: Paul Sebastian Co-authored-by: Suchit Sahoo <38322563+LDrago27@users.noreply.github.com> Signed-off-by: yujin-emma --- changelogs/fragments/6755.yml | 2 + .../manage_data_source_button.test.tsx | 38 ++++++ .../manage_data_source_button.tsx | 7 +- .../toast_button/reload_button.test.tsx | 26 ++++ .../datasource_form_validation.test.ts | 116 +++++++++++++++++- .../data_source_management/public/mocks.ts | 1 + 6 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 changelogs/fragments/6755.yml create mode 100644 src/plugins/data_source_management/public/components/toast_button/manage_data_source_button.test.tsx create mode 100644 src/plugins/data_source_management/public/components/toast_button/reload_button.test.tsx diff --git a/changelogs/fragments/6755.yml b/changelogs/fragments/6755.yml new file mode 100644 index 000000000000..8e06db889066 --- /dev/null +++ b/changelogs/fragments/6755.yml @@ -0,0 +1,2 @@ +fix: +- Add test for toast button and validation form ([#6755](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6755)) \ No newline at end of file diff --git a/src/plugins/data_source_management/public/components/toast_button/manage_data_source_button.test.tsx b/src/plugins/data_source_management/public/components/toast_button/manage_data_source_button.test.tsx new file mode 100644 index 000000000000..d61cd0dcabc7 --- /dev/null +++ b/src/plugins/data_source_management/public/components/toast_button/manage_data_source_button.test.tsx @@ -0,0 +1,38 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { getManageDataSourceButton } from './manage_data_source_button'; +import { coreMock } from '../../../../../core/public/mocks'; +import { DSM_APP_ID } from '../../plugin'; +import { render } from '@testing-library/react'; + +describe('ManageDataSourceButton', () => { + const applicationMock = coreMock.createStart().application; + + it('renders without crashing', () => { + const wrapper = render(getManageDataSourceButton()); + expect(wrapper).toBeTruthy(); + }); + + it('renders a button with correct label', () => { + const { getByTestId } = render(getManageDataSourceButton(applicationMock)); + const container = getByTestId('manageDataSourceButtonContainer'); + expect(container).toBeInTheDocument(); + expect(container).toHaveTextContent('Manage data sources'); + }); + + it('navigates to management app on button click', () => { + const { getByTestId } = render(getManageDataSourceButton(applicationMock)); + const button = getByTestId('manageDataSourceButton'); + button.click(); + expect(applicationMock.navigateToApp).toHaveBeenCalledTimes(1); + + expect(applicationMock.navigateToApp).toHaveBeenCalledWith('management', { + path: `opensearch-dashboards/${DSM_APP_ID}`, // Assuming DSM_APP_ID is replaced with a value + }); + }); +}); diff --git a/src/plugins/data_source_management/public/components/toast_button/manage_data_source_button.tsx b/src/plugins/data_source_management/public/components/toast_button/manage_data_source_button.tsx index 6222f74fdec4..63fcab2fdf70 100644 --- a/src/plugins/data_source_management/public/components/toast_button/manage_data_source_button.tsx +++ b/src/plugins/data_source_management/public/components/toast_button/manage_data_source_button.tsx @@ -11,9 +11,14 @@ import { DSM_APP_ID } from '../../plugin'; export const getManageDataSourceButton = (application?: ApplicationStart) => { return ( <> - + application?.navigateToApp('management', { diff --git a/src/plugins/data_source_management/public/components/toast_button/reload_button.test.tsx b/src/plugins/data_source_management/public/components/toast_button/reload_button.test.tsx new file mode 100644 index 000000000000..31223ae6943f --- /dev/null +++ b/src/plugins/data_source_management/public/components/toast_button/reload_button.test.tsx @@ -0,0 +1,26 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { render, fireEvent } from '@testing-library/react'; +import { getReloadButton } from './reload_button'; + +describe('getReloadButton', () => { + it('renders button with correct label', () => { + const { getByText } = render(getReloadButton()); + expect(getByText('Refresh the page')).toBeInTheDocument(); + }); + + it('calls window.location.reload() on button click', () => { + const reloadMock = jest.fn(); + Object.defineProperty(window, 'location', { + value: { reload: reloadMock }, + writable: true, + }); + + const { getByText } = render(getReloadButton()); + fireEvent.click(getByText('Refresh the page')); + expect(reloadMock).toHaveBeenCalled(); + }); +}); diff --git a/src/plugins/data_source_management/public/components/validation/datasource_form_validation.test.ts b/src/plugins/data_source_management/public/components/validation/datasource_form_validation.test.ts index 7b92a355e908..925185b98b6d 100644 --- a/src/plugins/data_source_management/public/components/validation/datasource_form_validation.test.ts +++ b/src/plugins/data_source_management/public/components/validation/datasource_form_validation.test.ts @@ -7,11 +7,14 @@ import { AuthType } from '../../types'; import { CreateDataSourceState } from '../create_data_source_wizard/components/create_form/create_data_source_form'; import { EditDataSourceState } from '../edit_data_source/components/edit_form/edit_data_source_form'; import { defaultValidation, performDataSourceFormValidation } from './datasource_form_validation'; -import { mockDataSourceAttributesWithAuth } from '../../mocks'; +import { + mockDataSourceAttributesWithAuth, + mockDataSourceAttributesWithSigV4Auth, +} from '../../mocks'; import { AuthenticationMethod, AuthenticationMethodRegistry } from '../../auth_registry'; describe('DataSourceManagement: Form Validation', () => { - describe('validate create/edit datasource', () => { + describe('validate create/edit datasource for Username and Password auth type', () => { let authenticationMethodRegistry = new AuthenticationMethodRegistry(); let form: CreateDataSourceState | EditDataSourceState = { formErrorsByField: { ...defaultValidation }, @@ -117,4 +120,113 @@ describe('DataSourceManagement: Form Validation', () => { expect(result).toBe(true); }); }); + + describe('validate create/edit datasource for SigV4 auth type', () => { + let authenticationMethodRegistry = new AuthenticationMethodRegistry(); + let form: CreateDataSourceState | EditDataSourceState = { + formErrorsByField: { ...defaultValidation }, + title: '', + description: '', + endpoint: '', + auth: { + type: AuthType.SigV4, + credentials: { + accesskey: 'test123', + secretKey: 'test123', + service: 'es', + region: 'us-east-1', + }, + }, + }; + test('should fail validation when title is empty', () => { + const result = performDataSourceFormValidation(form, [], '', authenticationMethodRegistry); + expect(result).toBe(false); + }); + test('should fail validation on duplicate title', () => { + form.title = 'test'; + const result = performDataSourceFormValidation( + form, + ['oldTitle', 'test'], + 'oldTitle', + authenticationMethodRegistry + ); + expect(result).toBe(false); + }); + test('should fail validation when title is longer than 32 characters', () => { + form.title = 'test'.repeat(10); + const result = performDataSourceFormValidation(form, [], '', authenticationMethodRegistry); + expect(result).toBe(false); + }); + test('should fail validation when endpoint is not valid', () => { + form.endpoint = mockDataSourceAttributesWithSigV4Auth.endpoint; + const result = performDataSourceFormValidation(form, [], '', authenticationMethodRegistry); + expect(result).toBe(false); + }); + test('should fail validation when accesskey is empty', () => { + form.auth.credentials!.accessKey = 'test'; + const result = performDataSourceFormValidation(form, [], '', authenticationMethodRegistry); + expect(result).toBe(false); + }); + test('should fail validation when secrectKey is empty', () => { + form.auth.credentials!.accessKey = 'test'; + form.auth.credentials!.secretKey = ''; + const result = performDataSourceFormValidation(form, [], '', authenticationMethodRegistry); + expect(result).toBe(false); + }); + test('should NOT fail validation on empty accesskey/secretKey when No Auth is selected', () => { + form.auth.type = AuthType.NoAuth; + form.title = 'test'; + form.endpoint = mockDataSourceAttributesWithSigV4Auth.endpoint; + const result = performDataSourceFormValidation(form, [], '', authenticationMethodRegistry); + expect(result).toBe(true); + }); + test('should NOT fail validation on all fields', () => { + form = { ...form, ...mockDataSourceAttributesWithSigV4Auth }; + const result = performDataSourceFormValidation( + form, + [mockDataSourceAttributesWithSigV4Auth.title], + mockDataSourceAttributesWithSigV4Auth.title, + authenticationMethodRegistry + ); + expect(result).toBe(true); + }); + test('should NOT fail validation when registered auth type is selected and related credential field not empty', () => { + authenticationMethodRegistry = new AuthenticationMethodRegistry(); + const authMethodToBeTested = { + name: 'Some Auth Type', + credentialSourceOption: { + value: 'Some Auth Type', + inputDisplay: 'some input', + }, + credentialForm: jest.fn(), + credentialFormField: { + userNameRegistered: 'some filled in userName from registed auth credential form', + passWordRegistered: 'some filled in password from registed auth credential form', + }, + } as AuthenticationMethod; + + authenticationMethodRegistry.registerAuthenticationMethod(authMethodToBeTested); + + const formWithRegisteredAuth: CreateDataSourceState | EditDataSourceState = { + formErrorsByField: { ...defaultValidation }, + title: 'test registered auth type', + description: '', + endpoint: 'https://test.com', + auth: { + type: 'Some Auth Type', + credentials: { + userNameRegistered: 'some filled in userName from registed auth credential form', + passWordRegistered: 'some filled in password from registed auth credential form', + }, + }, + }; + const result = performDataSourceFormValidation( + formWithRegisteredAuth, + [], + '', + authenticationMethodRegistry + ); + expect(result).toBe(true); + }); + }); }); diff --git a/src/plugins/data_source_management/public/mocks.ts b/src/plugins/data_source_management/public/mocks.ts index 0e5ec60bc307..a33a55d6799c 100644 --- a/src/plugins/data_source_management/public/mocks.ts +++ b/src/plugins/data_source_management/public/mocks.ts @@ -278,6 +278,7 @@ export const mockDataSourceAttributesWithSigV4Auth = { accessKey: 'test123', secretKey: 'test123', region: 'us-east-1', + service: 'es', }, }, };