From 20307d2b7ed8c81808fdd23b07262c39fa7549c8 Mon Sep 17 00:00:00 2001 From: alexeykozyurov Date: Wed, 28 Feb 2024 19:08:15 +0800 Subject: [PATCH] Tests --- .../Brokers/Broker/Configs/Configs.tsx | 5 +- .../InputCell/__test__/InputCell.spec.tsx | 72 +++++++++++++++++++ .../__test__/InputCellEditMode.spec.tsx | 42 +++++++++++ .../__test__/InputCellViewMode.spec.tsx | 69 ++++++++++++++++++ .../TableComponents/InputCell/index.tsx | 2 +- .../Configs/lib/__test__/utils.spec.tsx | 47 ++++++++++++ 6 files changed, 234 insertions(+), 3 deletions(-) create mode 100644 frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/__test__/InputCell.spec.tsx create mode 100644 frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/__test__/InputCellEditMode.spec.tsx create mode 100644 frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/__test__/InputCellViewMode.spec.tsx create mode 100644 frontend/src/components/Brokers/Broker/Configs/lib/__test__/utils.spec.tsx diff --git a/frontend/src/components/Brokers/Broker/Configs/Configs.tsx b/frontend/src/components/Brokers/Broker/Configs/Configs.tsx index c098c53c6..54b9bd6a9 100644 --- a/frontend/src/components/Brokers/Broker/Configs/Configs.tsx +++ b/frontend/src/components/Brokers/Broker/Configs/Configs.tsx @@ -19,7 +19,7 @@ const Configs: FC = () => { const [searchQuery, setSearchQuery] = useState(''); const { clusterName, brokerId } = useAppParams(); const { data: configs = [] } = useBrokerConfig(clusterName, Number(brokerId)); - const { mutateAsync } = useUpdateBrokerConfigByName( + const updateBrokerConfigByName = useUpdateBrokerConfigByName( clusterName, Number(brokerId) ); @@ -32,7 +32,8 @@ const Configs: FC = () => { const onUpdateInputCell = async ( name: BrokerConfig['name'], value: BrokerConfig['value'] - ) => mutateAsync({ name, brokerConfigItem: { value } }); + ) => + updateBrokerConfigByName.mutateAsync({ name, brokerConfigItem: { value } }); const columns = useMemo( () => getBrokerConfigsTableColumns(onUpdateInputCell), diff --git a/frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/__test__/InputCell.spec.tsx b/frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/__test__/InputCell.spec.tsx new file mode 100644 index 000000000..421b00f21 --- /dev/null +++ b/frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/__test__/InputCell.spec.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import InputCell, { + type InputCellProps, +} from 'components/Brokers/Broker/Configs/TableComponents/InputCell/index'; +import { render } from 'lib/testHelpers'; +import { ConfigSource } from 'generated-sources'; +import { useConfirm } from 'lib/hooks/useConfirm'; +import { BrokerConfigsTableRow } from 'components/Brokers/Broker/Configs/lib/types'; +import { Row } from '@tanstack/react-table'; + +jest.mock('lib/hooks/useConfirm', () => ({ + useConfirm: jest.fn(), +})); + +describe('InputCell', () => { + const mockOnUpdate = jest.fn(); + const initialValue = 'initialValue'; + const name = 'testName'; + const original = { + name, + source: ConfigSource.DYNAMIC_BROKER_CONFIG, + value: initialValue, + isSensitive: false, + isReadOnly: false, + }; + + beforeEach(() => { + const setupWrapper = (props?: Partial) => ( + } + onUpdate={mockOnUpdate} + /> + ); + (useConfirm as jest.Mock).mockImplementation( + () => (message: string, callback: () => void) => callback() + ); + render(setupWrapper()); + }); + + it('renders InputCellViewMode by default', () => { + expect(screen.getByText(initialValue)).toBeInTheDocument(); + }); + + it('switches to InputCellEditMode upon triggering an edit action', async () => { + const user = userEvent.setup(); + await user.click(screen.getByLabelText('editAction')); + expect( + screen.getByRole('textbox', { name: /inputValue/i }) + ).toBeInTheDocument(); + }); + + it('calls onUpdate callback with the new value when saved', async () => { + const user = userEvent.setup(); + await user.click(screen.getByLabelText('editAction')); // Enter edit mode + await user.type( + screen.getByRole('textbox', { name: /inputValue/i }), + '123' + ); + await user.click(screen.getByRole('button', { name: /confirmAction/i })); + expect(mockOnUpdate).toHaveBeenCalledWith(name, 'initialValue123'); + }); + + it('returns to InputCellViewMode upon canceling an edit', async () => { + const user = userEvent.setup(); + await user.click(screen.getByLabelText('editAction')); // Enter edit mode + await user.click(screen.getByRole('button', { name: /cancelAction/i })); + expect(screen.getByText(initialValue)).toBeInTheDocument(); // Back to view mode + }); +}); diff --git a/frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/__test__/InputCellEditMode.spec.tsx b/frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/__test__/InputCellEditMode.spec.tsx new file mode 100644 index 000000000..91270469e --- /dev/null +++ b/frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/__test__/InputCellEditMode.spec.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { screen } from '@testing-library/react'; +import InputCellEditMode from 'components/Brokers/Broker/Configs/TableComponents/InputCell/InputCellEditMode'; +import { render } from 'lib/testHelpers'; +import userEvent from '@testing-library/user-event'; + +describe('InputCellEditMode', () => { + const mockOnSave = jest.fn(); + const mockOnCancel = jest.fn(); + + beforeEach(() => { + render( + + ); + }); + + it('renders with initial value', () => { + expect(screen.getByRole('textbox', { name: /inputValue/i })).toHaveValue( + 'test' + ); + }); + + it('calls onSave with new value', async () => { + const user = userEvent.setup(); + await user.type( + screen.getByRole('textbox', { name: /inputValue/i }), + '123' + ); + await user.click(screen.getByRole('button', { name: /confirmAction/i })); + expect(mockOnSave).toHaveBeenCalledWith('test123'); + }); + + it('calls onCancel', async () => { + const user = userEvent.setup(); + await user.click(screen.getByRole('button', { name: /cancelAction/i })); + expect(mockOnCancel).toHaveBeenCalled(); + }); +}); diff --git a/frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/__test__/InputCellViewMode.spec.tsx b/frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/__test__/InputCellViewMode.spec.tsx new file mode 100644 index 000000000..9499fa857 --- /dev/null +++ b/frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/__test__/InputCellViewMode.spec.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { render } from 'lib/testHelpers'; +import InputCellViewMode from 'components/Brokers/Broker/Configs/TableComponents/InputCell/InputCellViewMode'; + +describe('InputCellViewMode', () => { + const mockOnEdit = jest.fn(); + const value = 'testValue'; + + it('displays the correct value for non-sensitive data', () => { + render( + + ); + expect(screen.getByTitle(value)).toBeInTheDocument(); + }); + + it('masks sensitive data with asterisks', () => { + render( + + ); + expect(screen.getByTitle('Sensitive Value')).toBeInTheDocument(); + expect(screen.getByText('**********')).toBeInTheDocument(); + }); + + it('renders edit button and triggers onEdit callback when clicked', async () => { + const user = userEvent.setup(); + render( + + ); + await user.click(screen.getByLabelText('editAction')); + expect(mockOnEdit).toHaveBeenCalled(); + }); + + it('disables edit button for read-only properties', () => { + render( + + ); + expect(screen.getByLabelText('editAction')).toBeDisabled(); + }); +}); diff --git a/frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/index.tsx b/frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/index.tsx index b00e26f7a..a55d7852c 100644 --- a/frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/index.tsx +++ b/frontend/src/components/Brokers/Broker/Configs/TableComponents/InputCell/index.tsx @@ -11,7 +11,7 @@ import { getConfigUnit } from 'components/Brokers/Broker/Configs/lib/utils'; import InputCellViewMode from './InputCellViewMode'; import InputCellEditMode from './InputCellEditMode'; -interface InputCellProps +export interface InputCellProps extends CellContext { onUpdate: UpdateBrokerConfigCallback; } diff --git a/frontend/src/components/Brokers/Broker/Configs/lib/__test__/utils.spec.tsx b/frontend/src/components/Brokers/Broker/Configs/lib/__test__/utils.spec.tsx new file mode 100644 index 000000000..fa9e04be1 --- /dev/null +++ b/frontend/src/components/Brokers/Broker/Configs/lib/__test__/utils.spec.tsx @@ -0,0 +1,47 @@ +import { + getConfigTableData, + getConfigUnit, +} from 'components/Brokers/Broker/Configs/lib/utils'; +import { ConfigSource } from 'generated-sources'; + +describe('getConfigTableData', () => { + it('filters configs by search query and sorts by source priority', () => { + const configs = [ + { + name: 'log.retention.ms', + value: '7200000', + source: ConfigSource.DEFAULT_CONFIG, + isSensitive: true, + isReadOnly: false, + }, + { + name: 'log.segment.bytes', + value: '1073741824', + source: ConfigSource.DYNAMIC_BROKER_CONFIG, + isSensitive: false, + isReadOnly: true, + }, + { + name: 'compression.type', + value: 'producer', + source: ConfigSource.DEFAULT_CONFIG, + isSensitive: true, + isReadOnly: false, + }, + ]; + const searchQuery = 'log'; + const result = getConfigTableData(configs, searchQuery); + + expect(result).toHaveLength(2); + expect(result[0].name).toBe('log.segment.bytes'); + expect(result[1].name).toBe('log.retention.ms'); + }); +}); + +describe('getConfigUnit', () => { + it('identifies the unit of a configuration name', () => { + expect(getConfigUnit('log.retention.ms')).toBe('ms'); + expect(getConfigUnit('log.segment.bytes')).toBe('bytes'); + expect(getConfigUnit('compression.type')).toBeUndefined(); + }); +});