Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MINOR: supported all_index in search index configuration form #16571

Merged
merged 12 commits into from
Jul 9, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"dataProduct",
"testCaseResolutionStatus"
],
"uiFieldType": "treeSelect",
"recreateIndex": true,
"batchSize": "100",
"searchIndexMappingLanguage": "EN"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"storageService",
"dataProduct"
],
"uiFieldType": "treeSelect",
"recreateIndex": true,
"batchSize": "100",
"searchIndexMappingLanguage": "EN"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/*
* Copyright 2024 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import test, { expect, Page } from '@playwright/test';
import { GlobalSettingOptions } from '../../constant/settings';
import { getApiContext, redirectToHomePage } from '../../utils/common';
import { settingClick } from '../../utils/sidebar';

// use the admin user to login
test.use({ storageState: 'playwright/.auth/admin.json' });

const verifyApplicationTriggerToastData = async (page: Page) => {
Ashish8689 marked this conversation as resolved.
Show resolved Hide resolved
await expect(page.getByRole('alert').first()).toHaveText(
/Application triggered successfully/
);

await page.getByLabel('close').first().click();
};

const verifyLastExecutionStatus = async (page: Page) => {
const { apiContext } = await getApiContext(page);

await expect
.poll(
async () => {
const response = await apiContext
.get(
'/api/v1/apps/name/SearchIndexingApplication/status?offset=0&limit=1'
)
.then((res) => res.json());

return response.data[0]?.status;
},
{
// Custom expect message for reporting, optional.
message: 'To get the last run execution status as success',
intervals: [30_000],
timeout: 300_000,
}
)
.toBe('success');

await page.reload();

await page.waitForSelector('[data-testid="app-run-history-table"]');

await expect(page.getByTestId('pipeline-status')).toContainText('Success');
};

const verifyLastExecutionRun = async (page: Page) => {
const response = await page.waitForResponse(
'/api/v1/apps/name/SearchIndexingApplication/status?offset=0&limit=1'
);

expect(response.status()).toBe(200);

const responseData = await response.json();
if (responseData.data.length > 0) {
expect(responseData.data).toHaveLength(1);

if (responseData.data[0].status === 'running') {
// wait for success status
await verifyLastExecutionStatus(page);
} else {
expect(responseData.data[0].status).toBe('success');
}
}
};

test('Search Index Application', async ({ page }) => {
await test.step('Visit Application page', async () => {
await redirectToHomePage(page);
await settingClick(page, GlobalSettingOptions.APPLICATIONS);
});

await test.step('Verify last execution run', async () => {
await page
.locator(
'[data-testid="search-indexing-application-card"] [data-testid="config-btn"]'
)
.click();
await verifyLastExecutionRun(page);
});

await test.step('Edit application', async () => {
await page.click('[data-testid="edit-button"]');
await page.click('[data-testid="cron-type"]');
await page.click('.rc-virtual-list [title="None"]');

const deployResponse = page.waitForResponse('/api/v1/apps/*');
await page.click('.ant-modal-body [data-testid="deploy-button"]');
await deployResponse;

await expect(page.getByRole('alert').first()).toHaveText(
/Schedule saved successfully/
);

await page.getByLabel('close').first().click();

expect(await page.innerText('[data-testid="schedule-type"]')).toContain(
'None'
);

await page.click('[data-testid="configuration"]');
await page.fill('#root\\/batchSize', '0');

await page.getByTitle('chart').getByLabel('close').click();

await page.click(
'[data-testid="select-widget"] > .ant-select-selector > .ant-select-selection-item'
);
await page.click('[data-testid="select-option-JP"]');

const responseAfterSubmit = page.waitForResponse('/api/v1/apps/*');
await page.click('[data-testid="submit-btn"]');
await responseAfterSubmit;

await expect(page.getByRole('alert').first()).toHaveText(
/Configuration saved successfully/
);

await page.getByLabel('close').first().click();
});

await test.step('Uninstall application', async () => {
await page.click('[data-testid="manage-button"]');
await page.click('[data-testid="uninstall-button-title"]');

const deleteRequest = page.waitForResponse(
'/api/v1/apps/name/SearchIndexingApplication?hardDelete=true'
);
await page.click('[data-testid="save-button"]');
await deleteRequest;

await expect(page.getByRole('alert').first()).toHaveText(
/Application uninstalled/
);

await page.getByLabel('close').first().click();

const card1 = page.locator(
'[data-testid="search-indexing-application-card"]'
);

expect(await card1.isVisible()).toBe(false);
});

await test.step('Install application', async () => {
await page.click('[data-testid="add-application"]');

// Verify response status code
const getMarketPlaceResponse = await page.waitForResponse(
'/api/v1/apps/marketplace?limit=*'
);

expect(getMarketPlaceResponse.status()).toBe(200);

await page.click(
'[data-testid="search-indexing-application-card"] [data-testid="config-btn"]'
);
await page.click('[data-testid="install-application"]');
await page.click('[data-testid="save-button"]');
await page.click('[data-testid="submit-btn"]');
await page.click('[data-testid="cron-type"]');
await page.click('.rc-virtual-list [title="None"]');

expect(await page.innerText('[data-testid="cron-type"]')).toContain('None');

const installApplicationResponse = page.waitForResponse('api/v1/apps');
await page.click('[data-testid="deploy-button"]');
await installApplicationResponse;

await expect(page.getByRole('alert').first()).toHaveText(
/Application installed successfully/
);

await page.getByLabel('close').first().click();

const card = page.locator(
'[data-testid="search-indexing-application-card"]'
);

expect(await card.isVisible()).toBe(true);
});

if (process.env.isOss) {
await test.step('Run application', async () => {
test.slow(true); // Test time shouldn't exceed while re-fetching the history API.

await page.click(
'[data-testid="search-indexing-application-card"] [data-testid="config-btn"]'
);

const triggerPipelineResponse = page.waitForResponse(
'/api/v1/apps/trigger/SearchIndexingApplication'
);
await page.click('[data-testid="run-now-button"]');

await triggerPipelineResponse;

await verifyApplicationTriggerToastData(page);

await page.reload();

await verifyLastExecutionRun(page);
});
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
*/
import { APIRequestContext, expect, Page } from '@playwright/test';
import {
ENTITY_PATH,
EntityTypeEndpoint,
ENTITY_PATH,
} from '../support/entity/Entity.interface';
import { UserClass } from '../support/user/UserClass';
import { uuid } from './common';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,50 @@ import {
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { MOCK_SELECT_WIDGET } from '../../../../../mocks/SelectWidget.mock';
import {
MOCK_SELECT_WIDGET,
MOCK_TREE_SELECT_WIDGET,
} from '../../../../../mocks/SelectWidget.mock';
import SelectWidget from './SelectWidget';

jest.mock('./TreeSelectWidget', () =>
jest.fn().mockImplementation(() => <p>TreeSelectWidget</p>)
);

const mockOnFocus = jest.fn();
const mockOnBlur = jest.fn();
const mockOnChange = jest.fn();

const mockProps: WidgetProps = {
const mockBaseProps = {
onFocus: mockOnFocus,
onBlur: mockOnBlur,
onChange: mockOnChange,
registry: {} as Registry,
};

const mockSelectProps: WidgetProps = {
...mockBaseProps,
...MOCK_SELECT_WIDGET,
};

const mockTreeSelectProps: WidgetProps = {
...mockBaseProps,
...MOCK_TREE_SELECT_WIDGET,
};

describe('Test SelectWidget Component', () => {
it('Should render select component', async () => {
render(<SelectWidget {...mockProps} />);
render(<SelectWidget {...mockSelectProps} />);

const selectInput = screen.getByTestId('select-widget');
const treeSelectWidget = screen.queryByText('TreeSelectWidget');

expect(selectInput).toBeInTheDocument();
expect(treeSelectWidget).not.toBeInTheDocument();
});

it('Should be disabled', async () => {
render(<SelectWidget {...mockProps} disabled />);
render(<SelectWidget {...mockSelectProps} disabled />);

const selectInput = await findByRole(
screen.getByTestId('select-widget'),
Expand All @@ -58,7 +76,7 @@ describe('Test SelectWidget Component', () => {
});

it('Should call onFocus', async () => {
render(<SelectWidget {...mockProps} />);
render(<SelectWidget {...mockSelectProps} />);

const selectInput = screen.getByTestId('select-widget');

Expand All @@ -68,7 +86,7 @@ describe('Test SelectWidget Component', () => {
});

it('Should call onBlur', async () => {
render(<SelectWidget {...mockProps} />);
render(<SelectWidget {...mockSelectProps} />);

const selectInput = screen.getByTestId('select-widget');

Expand All @@ -78,7 +96,7 @@ describe('Test SelectWidget Component', () => {
});

it('Should call onChange', async () => {
render(<SelectWidget {...mockProps} />);
render(<SelectWidget {...mockSelectProps} />);

const selectInput = await findByRole(
screen.getByTestId('select-widget'),
Expand All @@ -97,4 +115,14 @@ describe('Test SelectWidget Component', () => {

expect(mockOnChange).toHaveBeenCalledTimes(1);
});

it('Should render TreeSelectWidget component if uiFieldType is treeSelect', async () => {
render(<SelectWidget {...mockTreeSelectProps} />);

const selectWidget = screen.queryByTestId('select-widget');
const treeSelectWidget = screen.getByText('TreeSelectWidget');

expect(treeSelectWidget).toBeInTheDocument();
expect(selectWidget).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,18 @@ import { WidgetProps } from '@rjsf/utils';
import { Select } from 'antd';
import { capitalize } from 'lodash';
import React, { FC } from 'react';
import TreeSelectWidget from './TreeSelectWidget';

const SelectWidget: FC<WidgetProps> = (props) => {
if (props.schema.uiFieldType === 'treeSelect') {
return <TreeSelectWidget {...props} />;
}

const { onFocus, onBlur, onChange, ...rest } = props;

const SelectWidget: FC<WidgetProps> = ({
onFocus,
onBlur,
onChange,
...rest
}) => {
return (
<Select
allowClear
autoFocus={rest.autofocus}
className="d-block w-full"
data-testid="select-widget"
Expand Down
Loading
Loading