Skip to content

Commit

Permalink
[controls] Refactor control group settings functional tests (elastic#…
Browse files Browse the repository at this point in the history
…190999)

Refactor control group settings tests
1. move non-functional test cases to unit tests
2. use pre-built dashboard to avoid time of building dashboard in test

### Before
Tests take 4 minutes to run locally
<img width="400" alt="Screenshot 2024-08-21 at 3 12 31 PM"
src="https://github.com/user-attachments/assets/96cf584c-2b32-4281-86ee-9791544bd5fa">


### After
Tests take 1 minute to run locally
<img width="400" alt="Screenshot 2024-08-21 at 2 53 37 PM"
src="https://github.com/user-attachments/assets/853a6f3a-74c5-4ca8-a488-99dd24477b1e">

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
nreese and elasticmachine authored Aug 22, 2024
1 parent b6ce155 commit 79051d4
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 140 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import React from 'react';
import { BehaviorSubject } from 'rxjs';
import { render } from '@testing-library/react';
import { ControlGroupEditor } from './control_group_editor';
import { ControlGroupApi, ControlStyle, ParentIgnoreSettings } from '../../..';
import { ControlGroupChainingSystem, DEFAULT_CONTROL_STYLE } from '../../../../common';
import { DefaultControlApi } from '../../controls/types';

describe('render', () => {
const children$ = new BehaviorSubject<{ [key: string]: DefaultControlApi }>({});
const props = {
api: {
children$,
} as unknown as ControlGroupApi,
onCancel: () => {},
onSave: () => {},
onDeleteAll: () => {},
stateManager: {
chainingSystem: new BehaviorSubject<ControlGroupChainingSystem>('HIERARCHICAL'),
labelPosition: new BehaviorSubject<ControlStyle>(DEFAULT_CONTROL_STYLE),
autoApplySelections: new BehaviorSubject<boolean>(true),
ignoreParentSettings: new BehaviorSubject<ParentIgnoreSettings | undefined>(undefined),
},
};

beforeEach(() => {
children$.next({});
});

test('should not display delete all controls button when there are no controls', () => {
const editor = render(<ControlGroupEditor {...props} />);
expect(editor.queryByTestId('delete-all-controls-button')).not.toBeInTheDocument();
});

test('should display delete all controls button when there are controls', () => {
children$.next({
alpha: {} as unknown as DefaultControlApi,
});
const editor = render(<ControlGroupEditor {...props} />);
expect(editor.queryByTestId('delete-all-controls-button')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ import {
} from '@elastic/eui';
import { css } from '@emotion/react';
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
import { ControlStyle, ParentIgnoreSettings } from '../..';
import { ControlStyle, ParentIgnoreSettings } from '../../..';

import { ControlStateManager } from '../controls/types';
import { ControlGroupStrings } from './control_group_strings';
import { ControlGroupApi, ControlGroupEditorState } from './types';
import { ControlStateManager } from '../../controls/types';
import { ControlGroupStrings } from '../control_group_strings';
import { ControlGroupApi, ControlGroupEditorState } from '../types';

const CONTROL_LAYOUT_OPTIONS = [
{
Expand All @@ -46,21 +46,15 @@ const CONTROL_LAYOUT_OPTIONS = [
},
];

interface EditControlGroupProps {
interface Props {
onCancel: () => void;
onSave: () => void;
onDeleteAll: () => void;
stateManager: ControlStateManager<ControlGroupEditorState>;
api: ControlGroupApi; // controls must always have a parent API
}

export const ControlGroupEditor = ({
onCancel,
onSave,
onDeleteAll,
stateManager,
api,
}: EditControlGroupProps) => {
export const ControlGroupEditor = ({ onCancel, onSave, onDeleteAll, stateManager, api }: Props) => {
const [
children,
selectedLabelPosition,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import React, { useImperativeHandle } from 'react';
import { BehaviorSubject } from 'rxjs';
import { render, waitFor } from '@testing-library/react';
import { ControlPanel } from './control_panel';
import { registry as presentationUtilServicesRegistry } from '@kbn/presentation-util-plugin/public/services/plugin_services.story';
import { pluginServices as presentationUtilPluginServices } from '@kbn/presentation-util-plugin/public/services';
import { ControlStyle, ControlWidth } from '../../..';

describe('render', () => {
let mockApi = {};
const Component = React.forwardRef((_, ref) => {
// expose the api into the imperative handle
useImperativeHandle(ref, () => mockApi, []);

return <div />;
}) as any;

beforeAll(() => {
presentationUtilServicesRegistry.start({});
presentationUtilPluginServices.setRegistry(presentationUtilServicesRegistry);
presentationUtilPluginServices.getServices().uiActions.getTriggerCompatibleActions = jest
.fn()
.mockImplementation(() => {
return [
{
isCompatible: jest.fn().mockResolvedValue(true),
id: 'testAction',
MenuItem: () => <div>test1</div>,
},
];
});
});

beforeEach(() => {
mockApi = {};
});

describe('control width', () => {
test('defaults to medium and grow enabled', async () => {
const controlPanel = render(<ControlPanel uuid="control1" Component={Component} />);
await waitFor(() => {
const controlFrame = controlPanel.getByTestId('control-frame');
expect(controlFrame.getAttribute('class')).toContain('controlFrameWrapper--medium');
expect(controlFrame.getAttribute('class')).toContain('controlFrameWrapper--grow');
});
});

test('should use small class when using small width', async () => {
mockApi = {
uuid: 'control1',
width: new BehaviorSubject<ControlWidth>('small'),
};
const controlPanel = render(<ControlPanel uuid="control1" Component={Component} />);
await waitFor(() => {
const controlFrame = controlPanel.getByTestId('control-frame');
expect(controlFrame.getAttribute('class')).toContain('controlFrameWrapper--small');
});
});
});

describe('label position', () => {
test('should use one line layout class when using one line layout', async () => {
mockApi = {
uuid: 'control1',
parentApi: {
labelPosition: new BehaviorSubject<ControlStyle>('oneLine'),
},
};
const controlPanel = render(<ControlPanel uuid="control1" Component={Component} />);
await waitFor(() => {
const floatingActions = controlPanel.getByTestId(
'presentationUtil__floatingActions__control1'
);
expect(floatingActions.getAttribute('class')).toContain(
'controlFrameFloatingActions--oneLine'
);
});
});

test('should use two line layout class when using two line layout', async () => {
mockApi = {
uuid: 'control1',
parentApi: {
labelPosition: new BehaviorSubject<ControlStyle>('twoLine'),
},
};
const controlPanel = render(<ControlPanel uuid="control1" Component={Component} />);
await waitFor(() => {
const floatingActions = controlPanel.getByTestId(
'presentationUtil__floatingActions__control1'
);
expect(floatingActions.getAttribute('class')).toContain(
'controlFrameFloatingActions--twoLine'
);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
useBatchedOptionalPublishingSubjects,
} from '@kbn/presentation-publishing';
import { FloatingActions } from '@kbn/presentation-util-plugin/public';
import { DEFAULT_CONTROL_WIDTH } from '../../../../common';
import { DEFAULT_CONTROL_GROW, DEFAULT_CONTROL_WIDTH } from '../../../../common';

import { ControlPanelProps, DefaultControlApi } from '../../controls/types';
import { ControlError } from './control_error';
Expand Down Expand Up @@ -121,17 +121,18 @@ export const ControlPanel = <ApiType extends DefaultControlApi = DefaultControlA
const viewMode = (rawViewMode ?? ViewMode.VIEW) as ViewMode;
const isEditable = viewMode === ViewMode.EDIT;
const controlWidth = width ?? DEFAULT_CONTROL_WIDTH;
const controlGrow = grow ?? DEFAULT_CONTROL_GROW;

return (
<EuiFlexItem
ref={setNodeRef}
style={style}
grow={grow}
grow={controlGrow}
data-control-id={uuid}
data-test-subj={`control-frame`}
data-test-subj="control-frame"
data-render-complete="true"
className={classNames('controlFrameWrapper', {
'controlFrameWrapper--grow': grow,
'controlFrameWrapper--grow': controlGrow,
'controlFrameWrapper--small': controlWidth === 'small',
'controlFrameWrapper--medium': controlWidth === 'medium',
'controlFrameWrapper--large': controlWidth === 'large',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import React from 'react';
import { BehaviorSubject } from 'rxjs';

import { ControlStateManager } from '../controls/types';
import { ControlGroupEditor } from './control_group_editor';
import { ControlGroupEditor } from './components/control_group_editor';
import { ControlGroupApi, ControlGroupEditorState } from './types';

export const openEditControlGroupFlyout = (
Expand Down
Loading

0 comments on commit 79051d4

Please sign in to comment.