mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-15 02:38:42 +00:00
parent
992a4547af
commit
5756b4c9d3
@ -14,40 +14,75 @@
|
|||||||
import {
|
import {
|
||||||
act,
|
act,
|
||||||
cleanup,
|
cleanup,
|
||||||
findByText,
|
|
||||||
fireEvent,
|
fireEvent,
|
||||||
render,
|
render,
|
||||||
screen,
|
screen,
|
||||||
|
waitFor,
|
||||||
} from '@testing-library/react';
|
} from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Column } from '../../../../../generated/entity/data/dashboardDataModel';
|
||||||
import { MOCK_TABLE } from '../../../../../mocks/TableData.mock';
|
import { MOCK_TABLE } from '../../../../../mocks/TableData.mock';
|
||||||
import { getTableProfilerConfig } from '../../../../../rest/tableAPI';
|
import { getTableProfilerConfig } from '../../../../../rest/tableAPI';
|
||||||
import { ProfilerSettingsModalProps } from '../TableProfiler.interface';
|
import { ProfilerSettingsModalProps } from '../TableProfiler.interface';
|
||||||
import ProfilerSettingsModal from './ProfilerSettingsModal';
|
import ProfilerSettingsModal from './ProfilerSettingsModal';
|
||||||
|
|
||||||
|
const mockShowSuccessToast = jest.fn();
|
||||||
|
const mockShowErrorToast = jest.fn();
|
||||||
|
const mockOnVisibilityChange = jest.fn();
|
||||||
|
|
||||||
jest.mock('../../../../../rest/tableAPI', () => ({
|
jest.mock('../../../../../rest/tableAPI', () => ({
|
||||||
getTableProfilerConfig: jest
|
getTableProfilerConfig: jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementation(() => Promise.resolve(MOCK_TABLE)),
|
.mockImplementation(() => Promise.resolve(MOCK_TABLE)),
|
||||||
putTableProfileConfig: jest.fn(),
|
putTableProfileConfig: jest.fn().mockResolvedValue({}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const mockProps: ProfilerSettingsModalProps = {
|
const mockProps: ProfilerSettingsModalProps = {
|
||||||
tableId: MOCK_TABLE.id,
|
tableId: MOCK_TABLE.id,
|
||||||
columns: MOCK_TABLE.columns || [],
|
columns: [
|
||||||
|
{ name: 'column1', dataType: 'string' },
|
||||||
|
{ name: 'column2', dataType: 'timestamp' },
|
||||||
|
] as unknown as Column[],
|
||||||
visible: true,
|
visible: true,
|
||||||
onVisibilityChange: jest.fn(),
|
onVisibilityChange: mockOnVisibilityChange,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockTableProfilerConfig = {
|
||||||
|
profileSample: 60.0,
|
||||||
|
profileSampleType: 'PERCENTAGE',
|
||||||
|
sampleDataCount: 500,
|
||||||
|
profileQuery: 'select * from table',
|
||||||
|
excludeColumns: ['column1'],
|
||||||
|
includeColumns: [{ columnName: 'column2', metrics: ['column_count'] }],
|
||||||
|
partitioning: {
|
||||||
|
enablePartitioning: true,
|
||||||
|
partitionColumnName: 'column2',
|
||||||
|
partitionIntervalType: 'COLUMN-VALUE',
|
||||||
|
partitionValues: ['test'],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.mock('../../../../../constants/profiler.constant', () => ({
|
jest.mock('../../../../../constants/profiler.constant', () => ({
|
||||||
DEFAULT_INCLUDE_PROFILE: [],
|
DEFAULT_INCLUDE_PROFILE: [],
|
||||||
INTERVAL_TYPE_OPTIONS: [],
|
INTERVAL_TYPE_OPTIONS: [
|
||||||
INTERVAL_UNIT_OPTIONS: [],
|
{ label: 'Column Value', value: 'COLUMN-VALUE' },
|
||||||
PROFILER_METRIC: [],
|
{ label: 'Time Unit', value: 'TIME-UNIT' },
|
||||||
|
],
|
||||||
|
INTERVAL_UNIT_OPTIONS: [
|
||||||
|
{ label: 'Day', value: 'DAY' },
|
||||||
|
{ label: 'Hour', value: 'HOUR' },
|
||||||
|
],
|
||||||
|
PROFILER_METRIC: ['column_count', 'distinct_count'],
|
||||||
PROFILER_MODAL_LABEL_STYLE: {},
|
PROFILER_MODAL_LABEL_STYLE: {},
|
||||||
PROFILE_SAMPLE_OPTIONS: [],
|
PROFILE_SAMPLE_OPTIONS: [
|
||||||
SUPPORTED_COLUMN_DATA_TYPE_FOR_INTERVAL: {},
|
{ label: 'Percentage', value: 'PERCENTAGE' },
|
||||||
TIME_BASED_PARTITION: [],
|
{ label: 'Row Count', value: 'ROW_COUNT' },
|
||||||
|
],
|
||||||
|
SUPPORTED_COLUMN_DATA_TYPE_FOR_INTERVAL: {
|
||||||
|
'COLUMN-VALUE': ['string'],
|
||||||
|
'TIME-UNIT': ['timestamp'],
|
||||||
|
},
|
||||||
|
TIME_BASED_PARTITION: ['TIME-UNIT'],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('../../../../../utils/CommonUtils', () => ({
|
jest.mock('../../../../../utils/CommonUtils', () => ({
|
||||||
@ -55,8 +90,12 @@ jest.mock('../../../../../utils/CommonUtils', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('../../../../../utils/ToastUtils', () => ({
|
jest.mock('../../../../../utils/ToastUtils', () => ({
|
||||||
showErrorToast: jest.fn(),
|
showErrorToast: jest
|
||||||
showSuccessToast: jest.fn(),
|
.fn()
|
||||||
|
.mockImplementation((error) => mockShowErrorToast(error)),
|
||||||
|
showSuccessToast: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation((msg) => mockShowSuccessToast(msg)),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('../../../SchemaEditor/SchemaEditor', () => {
|
jest.mock('../../../SchemaEditor/SchemaEditor', () => {
|
||||||
@ -70,133 +109,84 @@ jest.mock('../../../../common/SliderWithInput/SliderWithInput', () => {
|
|||||||
describe('Test ProfilerSettingsModal component', () => {
|
describe('Test ProfilerSettingsModal component', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cleanup();
|
cleanup();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render without crashing', async () => {
|
it('should render without crashing', async () => {
|
||||||
render(<ProfilerSettingsModal {...mockProps} />);
|
|
||||||
|
|
||||||
const modal = await screen.findByTestId('profiler-settings-modal');
|
|
||||||
const sampleContainer = await screen.findByTestId(
|
|
||||||
'profile-sample-container'
|
|
||||||
);
|
|
||||||
const sqlEditor = await screen.findByTestId('sql-editor-container');
|
|
||||||
const includeSelect = await screen.findByTestId('include-column-container');
|
|
||||||
const excludeSelect = await screen.findByTestId('exclude-column-container');
|
|
||||||
const partitionSwitch = await screen.findByTestId(
|
|
||||||
'enable-partition-switch'
|
|
||||||
);
|
|
||||||
const intervalType = await screen.findByTestId('interval-type');
|
|
||||||
const columnName = await screen.findByTestId('column-name');
|
|
||||||
const sampleDataCount = await screen.findByTestId(
|
|
||||||
'sample-data-count-input'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(modal).toBeInTheDocument();
|
|
||||||
expect(sampleContainer).toBeInTheDocument();
|
|
||||||
expect(sqlEditor).toBeInTheDocument();
|
|
||||||
expect(includeSelect).toBeInTheDocument();
|
|
||||||
expect(excludeSelect).toBeInTheDocument();
|
|
||||||
expect(partitionSwitch).toBeInTheDocument();
|
|
||||||
expect(intervalType).toBeInTheDocument();
|
|
||||||
expect(columnName).toBeInTheDocument();
|
|
||||||
expect(sampleDataCount).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Interval Type and Column Name field should be disabled, when partition switch is off', async () => {
|
|
||||||
render(<ProfilerSettingsModal {...mockProps} />);
|
|
||||||
const partitionSwitch = await screen.findByTestId(
|
|
||||||
'enable-partition-switch'
|
|
||||||
);
|
|
||||||
const intervalType = await screen.findByTestId('interval-type');
|
|
||||||
const columnName = await screen.findByTestId('column-name');
|
|
||||||
|
|
||||||
expect(partitionSwitch).toHaveAttribute('aria-checked', 'false');
|
|
||||||
expect(intervalType).toHaveClass('ant-select-disabled');
|
|
||||||
expect(columnName).toHaveClass('ant-select-disabled');
|
|
||||||
});
|
|
||||||
|
|
||||||
it.skip('Interval Type and Column Name field should be enabled, when partition switch is on', async () => {
|
|
||||||
render(<ProfilerSettingsModal {...mockProps} />);
|
|
||||||
const partitionSwitch = await screen.findByTestId(
|
|
||||||
'enable-partition-switch'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(partitionSwitch).toHaveAttribute('aria-checked', 'false');
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
fireEvent.click(partitionSwitch);
|
render(<ProfilerSettingsModal {...mockProps} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(await screen.findByTestId('interval-type')).not.toHaveClass(
|
await waitFor(() => {
|
||||||
'ant-select-disabled'
|
expect(screen.getByTestId('profiler-settings-modal')).toBeInTheDocument();
|
||||||
);
|
expect(
|
||||||
expect(await screen.findByTestId('column-name')).not.toHaveClass(
|
screen.getByTestId('profile-sample-container')
|
||||||
'ant-select-disabled'
|
).toBeInTheDocument();
|
||||||
);
|
expect(screen.getByTestId('sql-editor-container')).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByTestId('include-column-container')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByTestId('exclude-column-container')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(screen.getByTestId('enable-partition-switch')).toBeInTheDocument();
|
||||||
|
expect(screen.getByTestId('interval-type')).toBeInTheDocument();
|
||||||
|
expect(screen.getByTestId('column-name')).toBeInTheDocument();
|
||||||
|
expect(screen.getByTestId('sample-data-count-input')).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('initial values should be visible in the form', async () => {
|
it('should handle modal visibility', async () => {
|
||||||
const tableProfilerConfig = {
|
await act(async () => {
|
||||||
profileSample: 60.0,
|
render(<ProfilerSettingsModal {...mockProps} />);
|
||||||
profileSampleType: 'PERCENTAGE',
|
});
|
||||||
sampleDataCount: 500,
|
|
||||||
profileQuery: 'select * from table',
|
|
||||||
excludeColumns: ['address_id'],
|
|
||||||
includeColumns: [
|
|
||||||
{
|
|
||||||
columnName: 'first_name',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
partitioning: {
|
|
||||||
enablePartitioning: true,
|
|
||||||
partitionColumnName: 'last_name',
|
|
||||||
partitionIntervalType: 'COLUMN-VALUE',
|
|
||||||
partitionValues: ['test'],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
(getTableProfilerConfig as jest.Mock).mockImplementationOnce(() =>
|
|
||||||
Promise.resolve({ ...MOCK_TABLE, tableProfilerConfig })
|
|
||||||
);
|
|
||||||
render(<ProfilerSettingsModal {...mockProps} />);
|
|
||||||
|
|
||||||
const excludeSelect = await screen.findByTestId('exclude-column-select');
|
await waitFor(() => {
|
||||||
const includeSelect = await screen.findByTestId('include-column-select');
|
expect(screen.getByTestId('profiler-settings-modal')).toBeInTheDocument();
|
||||||
const partitionSwitch = await screen.findByTestId(
|
});
|
||||||
'enable-partition-switch'
|
|
||||||
);
|
|
||||||
const intervalType = await screen.findByTestId('interval-type');
|
|
||||||
const columnName = await screen.findByTestId('column-name');
|
|
||||||
|
|
||||||
expect(await screen.findByTestId('sample-data-count-input')).toHaveValue(
|
const cancelButton = screen.getByRole('button', { name: /cancel/i });
|
||||||
tableProfilerConfig.sampleDataCount.toString()
|
await act(async () => {
|
||||||
);
|
fireEvent.click(cancelButton);
|
||||||
expect(await screen.findByTestId('slider-input')).toHaveValue(
|
});
|
||||||
`${tableProfilerConfig.profileSample}%`
|
|
||||||
);
|
expect(mockOnVisibilityChange).toHaveBeenCalledWith(false);
|
||||||
expect(await screen.findByTestId('partition-value')).toHaveValue(
|
});
|
||||||
tableProfilerConfig.partitioning.partitionValues[0]
|
|
||||||
);
|
it('should load initial profiler config', async () => {
|
||||||
expect(
|
(getTableProfilerConfig as jest.Mock).mockResolvedValueOnce({
|
||||||
await findByText(excludeSelect, tableProfilerConfig.excludeColumns[0])
|
...MOCK_TABLE,
|
||||||
).toBeInTheDocument();
|
tableProfilerConfig: mockTableProfilerConfig,
|
||||||
expect(
|
});
|
||||||
await findByText(
|
|
||||||
includeSelect,
|
await act(async () => {
|
||||||
tableProfilerConfig.includeColumns[0].columnName
|
render(<ProfilerSettingsModal {...mockProps} />);
|
||||||
)
|
});
|
||||||
).toBeInTheDocument();
|
|
||||||
expect(
|
await waitFor(() => {
|
||||||
await findByText(
|
const sampleDataCount = screen.getByTestId('sample-data-count-input');
|
||||||
intervalType,
|
|
||||||
tableProfilerConfig.partitioning.partitionIntervalType
|
expect(sampleDataCount).toHaveAttribute('value', '500');
|
||||||
)
|
});
|
||||||
).toBeInTheDocument();
|
});
|
||||||
expect(
|
|
||||||
await findByText(
|
it('should handle sample data count change', async () => {
|
||||||
columnName,
|
await act(async () => {
|
||||||
tableProfilerConfig.partitioning.partitionColumnName
|
render(<ProfilerSettingsModal {...mockProps} />);
|
||||||
)
|
});
|
||||||
).toBeInTheDocument();
|
|
||||||
expect(partitionSwitch).toHaveAttribute('aria-checked', 'true');
|
const sampleDataCount = screen.getByTestId('sample-data-count-input');
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.change(sampleDataCount, { target: { value: '100' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(sampleDataCount).toHaveAttribute('value', '100');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -113,11 +113,20 @@ const ProfilerSettingsModal: React.FC<ProfilerSettingsModalProps> = ({
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectOptions = useMemo(() => {
|
const { columnOptions, columnWithAllOption } = useMemo(() => {
|
||||||
return columns.map(({ name }) => ({
|
const columnOptions = columns.map(({ name }) => ({
|
||||||
label: name,
|
label: name,
|
||||||
value: name,
|
value: name,
|
||||||
}));
|
}));
|
||||||
|
const columnWithAllOption = [
|
||||||
|
{
|
||||||
|
label: t('label.all'),
|
||||||
|
value: 'all',
|
||||||
|
},
|
||||||
|
...columnOptions,
|
||||||
|
];
|
||||||
|
|
||||||
|
return { columnOptions, columnWithAllOption };
|
||||||
}, [columns]);
|
}, [columns]);
|
||||||
const metricsOptions = useMemo(() => {
|
const metricsOptions = useMemo(() => {
|
||||||
const metricsOptions = [
|
const metricsOptions = [
|
||||||
@ -547,9 +556,9 @@ const ProfilerSettingsModal: React.FC<ProfilerSettingsModalProps> = ({
|
|||||||
allowClear
|
allowClear
|
||||||
className="w-full"
|
className="w-full"
|
||||||
data-testid="exclude-column-select"
|
data-testid="exclude-column-select"
|
||||||
dropdownStyle={{ maxHeight: 200 }}
|
dropdownStyle={{ maxHeight: 200, overflowY: 'auto' }}
|
||||||
mode="multiple"
|
mode="multiple"
|
||||||
options={selectOptions}
|
options={columnOptions}
|
||||||
placeholder={t('label.select-column-plural-to-exclude')}
|
placeholder={t('label.select-column-plural-to-exclude')}
|
||||||
size="middle"
|
size="middle"
|
||||||
value={state?.excludeCol}
|
value={state?.excludeCol}
|
||||||
@ -604,7 +613,7 @@ const ProfilerSettingsModal: React.FC<ProfilerSettingsModalProps> = ({
|
|||||||
showSearch
|
showSearch
|
||||||
className="w-full"
|
className="w-full"
|
||||||
data-testid="include-column-select"
|
data-testid="include-column-select"
|
||||||
options={selectOptions}
|
options={columnWithAllOption}
|
||||||
placeholder={t(
|
placeholder={t(
|
||||||
'label.select-column-plural-to-include'
|
'label.select-column-plural-to-include'
|
||||||
)}
|
)}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user