[Ingest Pipelines] Add test coverage for ingest pipelines editor component (#69283)
* first iteration of CIT tests * address pr feedback - use dot notation where we can - use string literals instead of + concatentation
This commit is contained in:
parent
2544daf21b
commit
e0460290b0
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { registerTestBed, TestBed } from '../../../../../../../test_utils';
|
||||
import { PipelineProcessorsEditor, Props } from '../pipeline_processors_editor.container';
|
||||
|
||||
const testBedSetup = registerTestBed<TestSubject>(PipelineProcessorsEditor, {
|
||||
doMountAsync: false,
|
||||
});
|
||||
|
||||
export interface SetupResult extends TestBed<TestSubject> {
|
||||
actions: {
|
||||
toggleOnFailure: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
export const setup = async (props: Props): Promise<SetupResult> => {
|
||||
const testBed = await testBedSetup(props);
|
||||
const toggleOnFailure = () => {
|
||||
const { find } = testBed;
|
||||
find('pipelineEditorOnFailureToggle').simulate('click');
|
||||
};
|
||||
|
||||
return {
|
||||
...testBed,
|
||||
actions: { toggleOnFailure },
|
||||
};
|
||||
};
|
||||
|
||||
type TestSubject =
|
||||
| 'pipelineEditorDoneButton'
|
||||
| 'pipelineEditorOnFailureToggle'
|
||||
| 'pipelineEditorOnFailureTree';
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import React from 'react';
|
||||
import { registerTestBed, TestBed } from '../../../../../../../test_utils';
|
||||
import { PipelineProcessorsEditor, Props } from '../pipeline_processors_editor.container';
|
||||
|
||||
jest.mock('@elastic/eui', () => ({
|
||||
...jest.requireActual('@elastic/eui'),
|
||||
// Mocking EuiComboBox, as it utilizes "react-virtualized" for rendering search suggestions,
|
||||
// which does not produce a valid component wrapper
|
||||
EuiComboBox: (props: any) => (
|
||||
<input
|
||||
data-test-subj={props['data-test-subj'] || 'mockComboBox'}
|
||||
data-currentvalue={props.selectedOptions}
|
||||
onChange={async (syntheticEvent: any) => {
|
||||
props.onChange([syntheticEvent['0']]);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// Mocking EuiCodeEditor, which uses React Ace under the hood
|
||||
EuiCodeEditor: (props: any) => (
|
||||
<input
|
||||
data-test-subj={props['data-test-subj'] || 'mockCodeEditor'}
|
||||
data-currentvalue={props.value}
|
||||
onChange={(e: any) => {
|
||||
props.onChange(e.jsonContent);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('react-virtualized', () => ({
|
||||
...jest.requireActual('react-virtualized'),
|
||||
AutoSizer: ({ children }: { children: any }) => (
|
||||
<div>{children({ height: 500, width: 500 })}</div>
|
||||
),
|
||||
}));
|
||||
|
||||
const testBedSetup = registerTestBed<TestSubject>(PipelineProcessorsEditor, {
|
||||
doMountAsync: false,
|
||||
});
|
||||
|
||||
export interface SetupResult extends TestBed<TestSubject> {
|
||||
actions: ReturnType<typeof createActions>;
|
||||
}
|
||||
|
||||
/**
|
||||
* We make heavy use of "processorSelector" in these actions. They are a way to uniquely identify
|
||||
* a processor and are a stringified version of {@link ProcessorSelector}.
|
||||
*
|
||||
* @remark
|
||||
* See also {@link selectorToDataTestSubject}.
|
||||
*/
|
||||
const createActions = (testBed: TestBed<TestSubject>) => {
|
||||
const { find, component } = testBed;
|
||||
|
||||
return {
|
||||
async addProcessor(processorsSelector: string, type: string, options: Record<string, any>) {
|
||||
find(`${processorsSelector}.addProcessorButton`).simulate('click');
|
||||
await act(async () => {
|
||||
find('processorTypeSelector').simulate('change', [{ value: type, label: type }]);
|
||||
});
|
||||
component.update();
|
||||
await act(async () => {
|
||||
find('processorOptionsEditor').simulate('change', {
|
||||
jsonContent: JSON.stringify(options),
|
||||
});
|
||||
});
|
||||
await act(async () => {
|
||||
find('processorSettingsForm.submitButton').simulate('click');
|
||||
});
|
||||
},
|
||||
|
||||
removeProcessor(processorSelector: string) {
|
||||
find(`${processorSelector}.moreMenu.button`).simulate('click');
|
||||
find(`${processorSelector}.moreMenu.deleteButton`).simulate('click');
|
||||
act(() => {
|
||||
find('removeProcessorConfirmationModal.confirmModalConfirmButton').simulate('click');
|
||||
});
|
||||
},
|
||||
|
||||
moveProcessor(processorSelector: string, dropZoneSelector: string) {
|
||||
act(() => {
|
||||
find(`${processorSelector}.moveItemButton`).simulate('click');
|
||||
});
|
||||
act(() => {
|
||||
find(dropZoneSelector).last().simulate('click');
|
||||
});
|
||||
component.update();
|
||||
},
|
||||
|
||||
async addOnFailureProcessor(
|
||||
processorSelector: string,
|
||||
type: string,
|
||||
options: Record<string, any>
|
||||
) {
|
||||
find(`${processorSelector}.moreMenu.button`).simulate('click');
|
||||
find(`${processorSelector}.moreMenu.addOnFailureButton`).simulate('click');
|
||||
await act(async () => {
|
||||
find('processorTypeSelector').simulate('change', [{ value: type, label: type }]);
|
||||
});
|
||||
component.update();
|
||||
await act(async () => {
|
||||
find('processorOptionsEditor').simulate('change', {
|
||||
jsonContent: JSON.stringify(options),
|
||||
});
|
||||
});
|
||||
await act(async () => {
|
||||
find('processorSettingsForm.submitButton').simulate('click');
|
||||
});
|
||||
},
|
||||
|
||||
duplicateProcessor(processorSelector: string) {
|
||||
find(`${processorSelector}.moreMenu.button`).simulate('click');
|
||||
act(() => {
|
||||
find(`${processorSelector}.moreMenu.duplicateButton`).simulate('click');
|
||||
});
|
||||
},
|
||||
|
||||
startAndCancelMove(processorSelector: string) {
|
||||
act(() => {
|
||||
find(`${processorSelector}.moveItemButton`).simulate('click');
|
||||
});
|
||||
component.update();
|
||||
act(() => {
|
||||
find(`${processorSelector}.cancelMoveItemButton`).simulate('click');
|
||||
});
|
||||
},
|
||||
|
||||
toggleOnFailure() {
|
||||
find('pipelineEditorOnFailureToggle').simulate('click');
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const setup = async (props: Props): Promise<SetupResult> => {
|
||||
const testBed = await testBedSetup(props);
|
||||
return {
|
||||
...testBed,
|
||||
actions: createActions(testBed),
|
||||
};
|
||||
};
|
||||
|
||||
type TestSubject =
|
||||
| 'pipelineEditorDoneButton'
|
||||
| 'pipelineEditorOnFailureToggle'
|
||||
| 'addProcessorsButtonLevel1'
|
||||
| 'processorSettingsForm'
|
||||
| 'processorSettingsForm.submitButton'
|
||||
| 'processorOptionsEditor'
|
||||
| 'processorSettingsFormFlyout'
|
||||
| 'processorTypeSelector'
|
||||
| 'pipelineEditorOnFailureTree'
|
||||
| string;
|
|
@ -3,8 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { setup } from './pipeline_processors_editor.helpers';
|
||||
import { setup, SetupResult } from './pipeline_processors_editor.helpers';
|
||||
import { Pipeline } from '../../../../../common/types';
|
||||
|
||||
const testProcessors: Pick<Pipeline, 'processors'> = {
|
||||
|
@ -25,10 +24,20 @@ const testProcessors: Pick<Pipeline, 'processors'> = {
|
|||
};
|
||||
|
||||
describe('Pipeline Editor', () => {
|
||||
it('provides the same data out it got in if nothing changes', async () => {
|
||||
const onUpdate = jest.fn();
|
||||
let onUpdate: jest.Mock;
|
||||
let testBed: SetupResult;
|
||||
|
||||
await setup({
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
onUpdate = jest.fn();
|
||||
testBed = await setup({
|
||||
value: {
|
||||
...testProcessors,
|
||||
},
|
||||
|
@ -38,7 +47,9 @@ describe('Pipeline Editor', () => {
|
|||
onTestPipelineClick: jest.fn(),
|
||||
esDocsBasePath: 'test',
|
||||
});
|
||||
});
|
||||
|
||||
it('provides the same data out it got in if nothing changes', () => {
|
||||
const {
|
||||
calls: [[arg]],
|
||||
} = onUpdate.mock;
|
||||
|
@ -46,20 +57,134 @@ describe('Pipeline Editor', () => {
|
|||
expect(arg.getData()).toEqual(testProcessors);
|
||||
});
|
||||
|
||||
it('toggles the on-failure processors', async () => {
|
||||
const { actions, exists } = await setup({
|
||||
value: {
|
||||
...testProcessors,
|
||||
},
|
||||
onFlyoutOpen: jest.fn(),
|
||||
onUpdate: jest.fn(),
|
||||
isTestButtonDisabled: false,
|
||||
onTestPipelineClick: jest.fn(),
|
||||
esDocsBasePath: 'test',
|
||||
});
|
||||
|
||||
it('toggles the on-failure processors tree', () => {
|
||||
const { actions, exists } = testBed;
|
||||
expect(exists('pipelineEditorOnFailureTree')).toBe(false);
|
||||
actions.toggleOnFailure();
|
||||
expect(exists('pipelineEditorOnFailureTree')).toBe(true);
|
||||
});
|
||||
|
||||
describe('processors', () => {
|
||||
it('adds a new processor', async () => {
|
||||
const { actions } = testBed;
|
||||
await actions.addProcessor('processors', 'test', { if: '1 == 1' });
|
||||
const [onUpdateResult] = onUpdate.mock.calls[onUpdate.mock.calls.length - 1];
|
||||
const { processors } = onUpdateResult.getData();
|
||||
expect(processors.length).toBe(3);
|
||||
const [a, b, c] = processors;
|
||||
expect(a).toEqual(testProcessors.processors[0]);
|
||||
expect(b).toEqual(testProcessors.processors[1]);
|
||||
expect(c).toEqual({ test: { if: '1 == 1' } });
|
||||
});
|
||||
|
||||
it('removes a processor', () => {
|
||||
const { actions } = testBed;
|
||||
// processor>0 denotes the first processor in the top-level processors array.
|
||||
actions.removeProcessor('processors>0');
|
||||
const [onUpdateResult] = onUpdate.mock.calls[onUpdate.mock.calls.length - 1];
|
||||
const { processors } = onUpdateResult.getData();
|
||||
expect(processors.length).toBe(1);
|
||||
expect(processors[0]).toEqual({
|
||||
gsub: {
|
||||
field: '_index',
|
||||
pattern: '(.monitoring-\\w+-)6(-.+)',
|
||||
replacement: '$17$2',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('reorders processors', () => {
|
||||
const { actions } = testBed;
|
||||
actions.moveProcessor('processors>0', 'dropButtonBelow-processors>1');
|
||||
const [onUpdateResult] = onUpdate.mock.calls[onUpdate.mock.calls.length - 1];
|
||||
const { processors } = onUpdateResult.getData();
|
||||
expect(processors).toEqual(testProcessors.processors.slice(0).reverse());
|
||||
});
|
||||
|
||||
it('adds an on-failure processor to a processor', async () => {
|
||||
const { actions, find, exists } = testBed;
|
||||
const processorSelector = 'processors>1';
|
||||
await actions.addOnFailureProcessor(processorSelector, 'test', { if: '1 == 2' });
|
||||
// Assert that the add on failure button has been removed
|
||||
find(`${processorSelector}.moreMenu.button`).simulate('click');
|
||||
expect(!exists(`${processorSelector}.moreMenu.addOnFailureButton`));
|
||||
// Assert that the add processor button is now visible
|
||||
expect(exists(`${processorSelector}.addProcessor`));
|
||||
const [onUpdateResult] = onUpdate.mock.calls[onUpdate.mock.calls.length - 1];
|
||||
const { processors } = onUpdateResult.getData();
|
||||
expect(processors.length).toBe(2);
|
||||
expect(processors[0]).toEqual(testProcessors.processors[0]); // should be unchanged
|
||||
expect(processors[1].gsub).toEqual({
|
||||
...testProcessors.processors[1].gsub,
|
||||
on_failure: [{ test: { if: '1 == 2' } }],
|
||||
});
|
||||
});
|
||||
|
||||
it('moves a processor to a nested dropzone', async () => {
|
||||
const { actions } = testBed;
|
||||
await actions.addOnFailureProcessor('processors>1', 'test', { if: '1 == 3' });
|
||||
actions.moveProcessor('processors>0', 'dropButtonBelow-processors>1>onFailure>0');
|
||||
const [onUpdateResult] = onUpdate.mock.calls[onUpdate.mock.calls.length - 1];
|
||||
const { processors } = onUpdateResult.getData();
|
||||
expect(processors.length).toBe(1);
|
||||
expect(processors[0].gsub.on_failure).toEqual([
|
||||
{
|
||||
test: { if: '1 == 3' },
|
||||
},
|
||||
testProcessors.processors[0],
|
||||
]);
|
||||
});
|
||||
|
||||
it('duplicates a processor', async () => {
|
||||
const { actions } = testBed;
|
||||
await actions.addOnFailureProcessor('processors>1', 'test', { if: '1 == 4' });
|
||||
actions.duplicateProcessor('processors>1');
|
||||
const [onUpdateResult] = onUpdate.mock.calls[onUpdate.mock.calls.length - 1];
|
||||
const { processors } = onUpdateResult.getData();
|
||||
expect(processors.length).toBe(3);
|
||||
const duplicatedProcessor = {
|
||||
gsub: {
|
||||
...testProcessors.processors[1].gsub,
|
||||
on_failure: [{ test: { if: '1 == 4' } }],
|
||||
},
|
||||
};
|
||||
expect(processors).toEqual([
|
||||
testProcessors.processors[0],
|
||||
duplicatedProcessor,
|
||||
duplicatedProcessor,
|
||||
]);
|
||||
});
|
||||
|
||||
it('can cancel a move', () => {
|
||||
const { actions, exists } = testBed;
|
||||
const processorSelector = 'processors>0';
|
||||
actions.startAndCancelMove(processorSelector);
|
||||
// Assert that we have exited move mode for this processor
|
||||
expect(exists(`moveItemButton-${processorSelector}`));
|
||||
const [onUpdateResult] = onUpdate.mock.calls[onUpdate.mock.calls.length - 1];
|
||||
const { processors } = onUpdateResult.getData();
|
||||
// Assert that nothing has changed
|
||||
expect(processors).toEqual(testProcessors.processors);
|
||||
});
|
||||
|
||||
it('moves to and from the global on-failure tree', async () => {
|
||||
const { actions } = testBed;
|
||||
actions.toggleOnFailure();
|
||||
await actions.addProcessor('onFailure', 'test', { if: '1 == 5' });
|
||||
actions.moveProcessor('processors>0', 'dropButtonBelow-onFailure>0');
|
||||
const [onUpdateResult1] = onUpdate.mock.calls[onUpdate.mock.calls.length - 1];
|
||||
const data1 = onUpdateResult1.getData();
|
||||
expect(data1.processors.length).toBe(1);
|
||||
expect(data1.on_failure.length).toBe(2);
|
||||
expect(data1.processors).toEqual([testProcessors.processors[1]]);
|
||||
expect(data1.on_failure).toEqual([{ test: { if: '1 == 5' } }, testProcessors.processors[0]]);
|
||||
actions.moveProcessor('onFailure>1', 'dropButtonAbove-processors>0');
|
||||
const [onUpdateResult2] = onUpdate.mock.calls[onUpdate.mock.calls.length - 1];
|
||||
const data2 = onUpdateResult2.getData();
|
||||
expect(data2.processors.length).toBe(2);
|
||||
expect(data2.on_failure.length).toBe(1);
|
||||
expect(data2.processors).toEqual(testProcessors.processors);
|
||||
expect(data2.on_failure).toEqual([{ test: { if: '1 == 5' } }]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,12 +13,14 @@ export interface Props {
|
|||
onClick: () => void;
|
||||
}
|
||||
|
||||
export const AddProcessorButton: FunctionComponent<Props> = ({ onClick }) => {
|
||||
export const AddProcessorButton: FunctionComponent<Props> = (props) => {
|
||||
const { onClick } = props;
|
||||
const {
|
||||
state: { editor },
|
||||
} = usePipelineProcessorsContext();
|
||||
return (
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="addProcessorButton"
|
||||
disabled={editor.mode.id !== 'idle'}
|
||||
iconSide="left"
|
||||
iconType="plusInCircle"
|
||||
|
|
|
@ -16,19 +16,16 @@ interface Props {
|
|||
onDuplicate: () => void;
|
||||
onDelete: () => void;
|
||||
onAddOnFailure: () => void;
|
||||
'data-test-subj'?: string;
|
||||
}
|
||||
|
||||
export const ContextMenu: FunctionComponent<Props> = ({
|
||||
showAddOnFailure,
|
||||
onDuplicate,
|
||||
onAddOnFailure,
|
||||
onDelete,
|
||||
disabled,
|
||||
}) => {
|
||||
export const ContextMenu: FunctionComponent<Props> = (props) => {
|
||||
const { showAddOnFailure, onDuplicate, onAddOnFailure, onDelete, disabled } = props;
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
|
||||
const contextMenuItems = [
|
||||
<EuiContextMenuItem
|
||||
data-test-subj="duplicateButton"
|
||||
key="duplicate"
|
||||
icon="copy"
|
||||
onClick={() => {
|
||||
|
@ -40,6 +37,7 @@ export const ContextMenu: FunctionComponent<Props> = ({
|
|||
</EuiContextMenuItem>,
|
||||
showAddOnFailure ? (
|
||||
<EuiContextMenuItem
|
||||
data-test-subj="addOnFailureButton"
|
||||
key="addOnFailure"
|
||||
icon="indexClose"
|
||||
onClick={() => {
|
||||
|
@ -51,6 +49,7 @@ export const ContextMenu: FunctionComponent<Props> = ({
|
|||
</EuiContextMenuItem>
|
||||
) : undefined,
|
||||
<EuiContextMenuItem
|
||||
data-test-subj="deleteButton"
|
||||
key="delete"
|
||||
icon="trash"
|
||||
color="danger"
|
||||
|
@ -65,12 +64,14 @@ export const ContextMenu: FunctionComponent<Props> = ({
|
|||
|
||||
return (
|
||||
<EuiPopover
|
||||
data-test-subj={props['data-test-subj']}
|
||||
anchorPosition="leftCenter"
|
||||
panelPaddingSize="none"
|
||||
isOpen={isOpen}
|
||||
closePopover={() => setIsOpen(false)}
|
||||
button={
|
||||
<EuiButtonIcon
|
||||
data-test-subj="button"
|
||||
disabled={disabled}
|
||||
onClick={() => setIsOpen((v) => !v)}
|
||||
iconType="boxesHorizontal"
|
||||
|
|
|
@ -8,6 +8,7 @@ import React, { FunctionComponent, memo } from 'react';
|
|||
import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiText, EuiToolTip } from '@elastic/eui';
|
||||
|
||||
import { ProcessorInternal, ProcessorSelector } from '../../types';
|
||||
import { selectorToDataTestSubject } from '../../utils';
|
||||
|
||||
import { usePipelineProcessorsContext } from '../../context';
|
||||
|
||||
|
@ -46,6 +47,7 @@ export const PipelineProcessorsEditorItem: FunctionComponent<Props> = memo(
|
|||
responsive={false}
|
||||
alignItems="center"
|
||||
justifyContent="spaceBetween"
|
||||
data-test-subj={selectorToDataTestSubject(selector)}
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup gutterSize="m" alignItems="center" responsive={false}>
|
||||
|
@ -85,6 +87,7 @@ export const PipelineProcessorsEditorItem: FunctionComponent<Props> = memo(
|
|||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonIcon
|
||||
data-test-subj="editItemButton"
|
||||
disabled={disabled}
|
||||
aria-label={editorItemMessages.editorButtonLabel}
|
||||
iconType="pencil"
|
||||
|
@ -100,6 +103,7 @@ export const PipelineProcessorsEditorItem: FunctionComponent<Props> = memo(
|
|||
<EuiFlexItem grow={false}>
|
||||
{selected ? (
|
||||
<EuiButtonIcon
|
||||
data-test-subj="cancelMoveItemButton"
|
||||
aria-label={editorItemMessages.cancelMoveButtonLabel}
|
||||
size="s"
|
||||
onClick={onCancelMove}
|
||||
|
@ -108,6 +112,7 @@ export const PipelineProcessorsEditorItem: FunctionComponent<Props> = memo(
|
|||
) : (
|
||||
<EuiToolTip content={editorItemMessages.moveButtonLabel}>
|
||||
<EuiButtonIcon
|
||||
data-test-subj="moveItemButton"
|
||||
disabled={disabled}
|
||||
aria-label={editorItemMessages.moveButtonLabel}
|
||||
size="s"
|
||||
|
@ -121,6 +126,7 @@ export const PipelineProcessorsEditorItem: FunctionComponent<Props> = memo(
|
|||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<ContextMenu
|
||||
data-test-subj="moreMenu"
|
||||
disabled={disabled}
|
||||
showAddOnFailure={!processor.onFailure?.length}
|
||||
onAddOnFailure={() => {
|
||||
|
|
|
@ -64,7 +64,7 @@ export const ProcessorSettingsForm: FunctionComponent<Props> = memo(
|
|||
);
|
||||
|
||||
return (
|
||||
<Form form={form}>
|
||||
<Form data-test-subj="processorSettingsForm" form={form}>
|
||||
<EuiFlyout onClose={onClose}>
|
||||
<EuiFlyoutHeader>
|
||||
<EuiFlexGroup gutterSize="xs">
|
||||
|
@ -122,7 +122,7 @@ export const ProcessorSettingsForm: FunctionComponent<Props> = memo(
|
|||
return (
|
||||
<>
|
||||
{formContent}
|
||||
<EuiButton onClick={form.submit}>
|
||||
<EuiButton data-test-subj="submitButton" onClick={form.submit}>
|
||||
{i18n.translate(
|
||||
'xpack.ingestPipelines.pipelineEditor.settingsForm.submitButtonLabel',
|
||||
{ defaultMessage: 'Submit' }
|
||||
|
|
|
@ -54,6 +54,7 @@ export const ProcessorTypeField: FunctionComponent<Props> = ({ initialType }) =>
|
|||
component={ComboBoxField}
|
||||
componentProps={{
|
||||
euiFieldProps: {
|
||||
'data-test-subj': 'processorTypeSelector',
|
||||
fullWidth: true,
|
||||
options: types.map((type) => ({ label: type, value: type })),
|
||||
noSuggestions: false,
|
||||
|
|
|
@ -76,6 +76,7 @@ export const Custom: FunctionComponent<Props> = ({ defaultOptions }) => {
|
|||
defaultValue={defaultOptions}
|
||||
componentProps={{
|
||||
euiCodeEditorProps: {
|
||||
'data-test-subj': 'processorOptionsEditor',
|
||||
height: '300px',
|
||||
'aria-label': i18n.translate(
|
||||
'xpack.ingestPipelines.pipelineEditor.customForm.optionsFieldAriaLabel',
|
||||
|
|
|
@ -12,13 +12,15 @@ import { EuiButtonIcon, EuiFlexItem } from '@elastic/eui';
|
|||
export interface Props {
|
||||
isDisabled: boolean;
|
||||
onClick: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
'data-test-subj'?: string;
|
||||
}
|
||||
|
||||
const MOVE_HERE_LABEL = i18n.translate('xpack.ingestPipelines.pipelineEditor.moveTargetLabel', {
|
||||
defaultMessage: 'Move here',
|
||||
});
|
||||
|
||||
export const DropZoneButton: FunctionComponent<Props> = ({ onClick, isDisabled }) => {
|
||||
export const DropZoneButton: FunctionComponent<Props> = (props) => {
|
||||
const { onClick, isDisabled } = props;
|
||||
const containerClasses = classNames({
|
||||
'pipelineProcessorsEditor__tree__dropZoneContainer--active': !isDisabled,
|
||||
});
|
||||
|
@ -31,6 +33,7 @@ export const DropZoneButton: FunctionComponent<Props> = ({ onClick, isDisabled }
|
|||
className={`pipelineProcessorsEditor__tree__dropZoneContainer ${containerClasses}`}
|
||||
>
|
||||
<EuiButtonIcon
|
||||
data-test-subj={props['data-test-subj']}
|
||||
className={`pipelineProcessorsEditor__tree__dropZoneButton ${buttonClasses}`}
|
||||
aria-label={MOVE_HERE_LABEL}
|
||||
disabled={isDisabled}
|
||||
|
|
|
@ -11,6 +11,7 @@ import { AutoSizer, List, WindowScroller } from 'react-virtualized';
|
|||
import { DropSpecialLocations } from '../../../constants';
|
||||
import { ProcessorInternal, ProcessorSelector } from '../../../types';
|
||||
import { isChildPath } from '../../../processors_reducer';
|
||||
import { selectorToDataTestSubject } from '../../../utils';
|
||||
|
||||
import { DropZoneButton } from '.';
|
||||
import { TreeNode } from '.';
|
||||
|
@ -73,10 +74,12 @@ export const PrivateTree: FunctionComponent<PrivateProps> = ({
|
|||
info: ProcessorInfo;
|
||||
processor: ProcessorInternal;
|
||||
}) => {
|
||||
const stringifiedSelector = selectorToDataTestSubject(info.selector);
|
||||
return (
|
||||
<>
|
||||
{idx === 0 ? (
|
||||
<DropZoneButton
|
||||
data-test-subj={`dropButtonAbove-${stringifiedSelector}`}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
onAction({
|
||||
|
@ -102,6 +105,7 @@ export const PrivateTree: FunctionComponent<PrivateProps> = ({
|
|||
/>
|
||||
</EuiFlexItem>
|
||||
<DropZoneButton
|
||||
data-test-subj={`dropButtonBelow-${stringifiedSelector}`}
|
||||
isDisabled={Boolean(!movingProcessor || isDropZoneBelowDisabled(info, movingProcessor!))}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
|
|
|
@ -89,6 +89,7 @@ export const TreeNode: FunctionComponent<Props> = ({
|
|||
processors={processor.onFailure}
|
||||
/>
|
||||
<AddProcessorButton
|
||||
data-test-subj={stringSelector}
|
||||
onClick={() =>
|
||||
onAction({
|
||||
type: 'addProcessor',
|
||||
|
|
|
@ -8,6 +8,7 @@ import { EuiFlexGroup, EuiFlexItem, keyCodes } from '@elastic/eui';
|
|||
import { List, WindowScroller } from 'react-virtualized';
|
||||
|
||||
import { ProcessorInternal, ProcessorSelector } from '../../types';
|
||||
import { selectorToDataTestSubject } from '../../utils';
|
||||
|
||||
import './processors_tree.scss';
|
||||
import { AddProcessorButton } from '../add_processor_button';
|
||||
|
@ -96,7 +97,7 @@ export const ProcessorsTree: FunctionComponent<Props> = memo((props) => {
|
|||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup responsive={false} justifyContent="flexStart" gutterSize="none">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexItem data-test-subj={selectorToDataTestSubject(baseSelector)} grow={false}>
|
||||
<AddProcessorButton
|
||||
onClick={() => {
|
||||
onAction({ type: 'addProcessor', payload: { target: baseSelector } });
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
import { ProcessorSelector } from './types';
|
||||
|
||||
export const selectorToDataTestSubject = (selector: ProcessorSelector) => selector.join('>');
|
||||
|
||||
type Path = string[];
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue