From e2a24e8ee6dc3553f01f5e3a3c70b9ef35ed1bbb Mon Sep 17 00:00:00 2001 From: Marta Bondyra <4283304+mbondyra@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:35:34 +0100 Subject: [PATCH] [Lens] [Datatable] toolbar tests rewritten to testing-library/react (#173075) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Rewrites datatable toolbar tests to testing-library. It also starts a new package – shared space to park EUI component test helpers that we eventually donate to EUI for ongoing maintenance. So far it's just one helper but hopefully we'll be adding helpers soon! --- .github/CODEOWNERS | 1 + .github/codeql/codeql-config.yml | 1 + package.json | 1 + packages/kbn-test-eui-helpers/index.ts | 9 + packages/kbn-test-eui-helpers/jest.config.js | 13 + packages/kbn-test-eui-helpers/kibana.jsonc | 6 + packages/kbn-test-eui-helpers/package.json | 6 + .../kbn-test-eui-helpers/src/rtl_helpers.tsx | 14 ++ packages/kbn-test-eui-helpers/tsconfig.json | 15 ++ tsconfig.base.json | 2 + .../shared_components/toolbar_popover.tsx | 1 + .../datatable/components/toolbar.test.tsx | 226 +++++++++--------- x-pack/plugins/lens/tsconfig.json | 1 + yarn.lock | 4 + 14 files changed, 193 insertions(+), 107 deletions(-) create mode 100644 packages/kbn-test-eui-helpers/index.ts create mode 100644 packages/kbn-test-eui-helpers/jest.config.js create mode 100644 packages/kbn-test-eui-helpers/kibana.jsonc create mode 100644 packages/kbn-test-eui-helpers/package.json create mode 100644 packages/kbn-test-eui-helpers/src/rtl_helpers.tsx create mode 100644 packages/kbn-test-eui-helpers/tsconfig.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d2d3d6b0f1b33..74beea70c0a01 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -789,6 +789,7 @@ src/plugins/telemetry @elastic/kibana-core test/plugin_functional/plugins/telemetry @elastic/kibana-core packages/kbn-telemetry-tools @elastic/kibana-core packages/kbn-test @elastic/kibana-operations @elastic/appex-qa +packages/kbn-test-eui-helpers @elastic/kibana-visualizations x-pack/test/licensing_plugin/plugins/test_feature_usage @elastic/kibana-security packages/kbn-test-jest-helpers @elastic/kibana-operations @elastic/appex-qa packages/kbn-test-subj-selector @elastic/kibana-operations @elastic/appex-qa diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 32b0326085929..461d850e4203c 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -61,6 +61,7 @@ paths-ignore: - packages/kbn-telemetry-tools - packages/kbn-test - packages/kbn-test-jest-helpers + - packages/kbn-test-eui-helpers - packages/kbn-test-subj-selector - packages/kbn-tooling-log - packages/kbn-ts-project-linter diff --git a/package.json b/package.json index 8f46f3cd06bde..d1e552344a70c 100644 --- a/package.json +++ b/package.json @@ -1295,6 +1295,7 @@ "@kbn/storybook": "link:packages/kbn-storybook", "@kbn/telemetry-tools": "link:packages/kbn-telemetry-tools", "@kbn/test": "link:packages/kbn-test", + "@kbn/test-eui-helpers": "link:packages/kbn-test-eui-helpers", "@kbn/test-jest-helpers": "link:packages/kbn-test-jest-helpers", "@kbn/test-subj-selector": "link:packages/kbn-test-subj-selector", "@kbn/tooling-log": "link:packages/kbn-tooling-log", diff --git a/packages/kbn-test-eui-helpers/index.ts b/packages/kbn-test-eui-helpers/index.ts new file mode 100644 index 0000000000000..7e514b179b9c4 --- /dev/null +++ b/packages/kbn-test-eui-helpers/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export * from './src/rtl_helpers'; diff --git a/packages/kbn-test-eui-helpers/jest.config.js b/packages/kbn-test-eui-helpers/jest.config.js new file mode 100644 index 0000000000000..a902329d1426a --- /dev/null +++ b/packages/kbn-test-eui-helpers/jest.config.js @@ -0,0 +1,13 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-test-eui-helpers'], +}; diff --git a/packages/kbn-test-eui-helpers/kibana.jsonc b/packages/kbn-test-eui-helpers/kibana.jsonc new file mode 100644 index 0000000000000..fc97c720f827d --- /dev/null +++ b/packages/kbn-test-eui-helpers/kibana.jsonc @@ -0,0 +1,6 @@ +{ + "type": "shared-common", + "id": "@kbn/test-eui-helpers", + "devOnly": true, + "owner": ["@elastic/kibana-visualizations"], +} diff --git a/packages/kbn-test-eui-helpers/package.json b/packages/kbn-test-eui-helpers/package.json new file mode 100644 index 0000000000000..fb416ef292622 --- /dev/null +++ b/packages/kbn-test-eui-helpers/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/test-eui-helpers", + "version": "1.0.0", + "private": true, + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/kbn-test-eui-helpers/src/rtl_helpers.tsx b/packages/kbn-test-eui-helpers/src/rtl_helpers.tsx new file mode 100644 index 0000000000000..e5a44615e980d --- /dev/null +++ b/packages/kbn-test-eui-helpers/src/rtl_helpers.tsx @@ -0,0 +1,14 @@ +/* + * 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 { screen, within } from '@testing-library/react'; + +export const getButtonGroupInputValue = (testId: string) => () => { + const buttonGroup = screen.getByTestId(testId); + return within(buttonGroup).getByRole('button', { pressed: true }); +}; diff --git a/packages/kbn-test-eui-helpers/tsconfig.json b/packages/kbn-test-eui-helpers/tsconfig.json new file mode 100644 index 0000000000000..9f1c443c02ee8 --- /dev/null +++ b/packages/kbn-test-eui-helpers/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": ["jest", "node"] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "kbn_references": [], + "exclude": [ + "target/**/*", + ], +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 086fd83ee3631..b8c20aa8d2da3 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1572,6 +1572,8 @@ "@kbn/telemetry-tools/*": ["packages/kbn-telemetry-tools/*"], "@kbn/test": ["packages/kbn-test"], "@kbn/test/*": ["packages/kbn-test/*"], + "@kbn/test-eui-helpers": ["packages/kbn-test-eui-helpers"], + "@kbn/test-eui-helpers/*": ["packages/kbn-test-eui-helpers/*"], "@kbn/test-feature-usage-plugin": ["x-pack/test/licensing_plugin/plugins/test_feature_usage"], "@kbn/test-feature-usage-plugin/*": ["x-pack/test/licensing_plugin/plugins/test_feature_usage/*"], "@kbn/test-jest-helpers": ["packages/kbn-test-jest-helpers"], diff --git a/x-pack/plugins/lens/public/shared_components/toolbar_popover.tsx b/x-pack/plugins/lens/public/shared_components/toolbar_popover.tsx index c8e096cbbb8a7..98a0eb609f9a8 100644 --- a/x-pack/plugins/lens/public/shared_components/toolbar_popover.tsx +++ b/x-pack/plugins/lens/public/shared_components/toolbar_popover.tsx @@ -68,6 +68,7 @@ export const ToolbarPopover: React.FunctionComponent = ({ onClick={() => { setOpen(!open); }} + label={title} aria-label={title} isDisabled={isDisabled} groupPosition={groupPosition} diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/toolbar.test.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/toolbar.test.tsx index f8cc197e1d78e..8807929360c29 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/toolbar.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/toolbar.test.tsx @@ -5,14 +5,14 @@ * 2.0. */ -import React, { ChangeEvent, FormEvent } from 'react'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; +import React from 'react'; +import { getButtonGroupInputValue } from '@kbn/test-eui-helpers'; import { DataTableToolbar } from './toolbar'; import { DatatableVisualizationState } from '../visualization'; import { FramePublicAPI, VisualizationToolbarProps } from '../../../types'; -import { ReactWrapper } from 'enzyme'; import { PagingState } from '../../../../common/expressions'; -import { EuiButtonGroup, EuiRange } from '@elastic/eui'; +import { fireEvent, render, screen, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; // mocking random id generator function jest.mock('@elastic/eui', () => { @@ -26,62 +26,12 @@ jest.mock('@elastic/eui', () => { }; }); -class Harness { - wrapper: ReactWrapper; - - constructor(wrapper: ReactWrapper) { - this.wrapper = wrapper; - } - - togglePopover() { - this.wrapper.find('button[data-test-subj="lnsVisualOptionsButton"]').simulate('click'); - } - - public get rowHeight() { - return this.wrapper.find('[data-test-subj="lnsRowHeightSettings"]').find(EuiButtonGroup); - } - - public get headerRowHeight() { - return this.wrapper.find('[data-test-subj="lnsHeaderHeightSettings"]').find(EuiButtonGroup); - } - - changeRowHeight(newMode: 'single' | 'auto' | 'custom') { - this.rowHeight.prop('onChange')!(newMode); - } - - changeHeaderRowHeight(newMode: 'single' | 'auto' | 'custom') { - this.headerRowHeight.prop('onChange')!(newMode); - } - - public get rowHeightLines() { - return this.wrapper.find(EuiRange); - } - - changeRowHeightLines(lineCount: number) { - this.rowHeightLines.prop('onChange')!( - { - currentTarget: { value: lineCount }, - } as unknown as ChangeEvent, - true - ); - } - - public get paginationSwitch() { - return this.wrapper.find('EuiSwitch[data-test-subj="lens-table-pagination-switch"]'); - } - - togglePagination() { - this.paginationSwitch.prop('onChange')!({} as FormEvent); - } -} - describe('datatable toolbar', () => { const defaultPagingState: PagingState = { size: 10, enabled: true, }; - let harness: Harness; let defaultProps: VisualizationToolbarProps; beforeEach(() => { @@ -93,57 +43,113 @@ describe('datatable toolbar', () => { headerRowHeight: 'single', } as DatatableVisualizationState, }; - - harness = new Harness(mountWithIntl()); }); - it('should reflect state in the UI', async () => { - harness.togglePopover(); + const renderToolbar = (overrides = {}) => { + const ROW_HEIGHT_SETTINGS_TEST_ID = 'lnsRowHeightSettings'; + const HEADER_HEIGHT_SETTINGS_TEST_ID = 'lnsHeaderHeightSettings'; - expect(harness.rowHeight.prop('idSelected')).toBe('single'); - expect(harness.headerRowHeight.prop('idSelected')).toBe('single'); - expect(harness.paginationSwitch.prop('checked')).toBe(false); + const rtlRender = render(); - harness.wrapper.setProps({ + const togglePopover = () => { + userEvent.click(screen.getByRole('button', { name: /visual options/i })); + }; + + const selectOptionFromButtonGroup = (testId: string) => (optionName: string | RegExp) => { + const buttonGroup = screen.getByTestId(testId); + const option = within(buttonGroup).getByRole('button', { name: optionName }); + fireEvent.click(option); + }; + + const getNumberInput = (testId: string) => + within(screen.getByTestId(testId)).queryByRole('spinbutton'); + + const getPaginationSwitch = () => screen.getByTestId('lens-table-pagination-switch'); // TODO: use getByLabel when EUI fixes the generated-id issue + const clickPaginationSwitch = () => { + fireEvent.click(getPaginationSwitch()); + }; + + return { + ...rtlRender, + togglePopover, + getRowHeightValue: getButtonGroupInputValue(ROW_HEIGHT_SETTINGS_TEST_ID), + getRowHeightCustomValue: () => getNumberInput(ROW_HEIGHT_SETTINGS_TEST_ID), + selectRowHeightOption: selectOptionFromButtonGroup(ROW_HEIGHT_SETTINGS_TEST_ID), + getHeaderHeightValue: getButtonGroupInputValue(HEADER_HEIGHT_SETTINGS_TEST_ID), + getHeaderHeightCustomValue: () => getNumberInput(HEADER_HEIGHT_SETTINGS_TEST_ID), + selectHeaderHeightOption: selectOptionFromButtonGroup(HEADER_HEIGHT_SETTINGS_TEST_ID), + getPaginationSwitch, + clickPaginationSwitch, + }; + }; + + it('should reflect default state in the UI', async () => { + const { togglePopover, getRowHeightValue, getHeaderHeightValue, getPaginationSwitch } = + renderToolbar(); + togglePopover(); + + expect(getRowHeightValue()).toHaveTextContent(/single/i); + expect(getHeaderHeightValue()).toHaveTextContent(/single/i); + expect(getPaginationSwitch()).not.toBeChecked(); + }); + + it('should reflect passed state in the UI', async () => { + const { + togglePopover, + getRowHeightValue, + getHeaderHeightValue, + getPaginationSwitch, + getHeaderHeightCustomValue, + getRowHeightCustomValue, + } = renderToolbar({ state: { - rowHeight: 'auto', - paging: defaultPagingState, + ...defaultProps.state, + rowHeight: 'custom', + rowHeightLines: 2, + headerRowHeight: 'custom', + headerRowHeightLines: 3, + paging: { size: 10, enabled: true }, }, }); - expect(harness.rowHeight.prop('idSelected')).toBe('auto'); - expect(harness.paginationSwitch.prop('checked')).toBe(true); - }); + togglePopover(); - it('should change row height to "Auto" mode', async () => { - harness.togglePopover(); + expect(getRowHeightValue()).toHaveTextContent(/custom/i); + expect(getRowHeightCustomValue()).toHaveValue(2); + expect(getHeaderHeightValue()).toHaveTextContent(/custom/i); + expect(getHeaderHeightCustomValue()).toHaveValue(3); + expect(getPaginationSwitch()).toBeChecked(); + }); - harness.changeRowHeight('auto'); + it('should change row height to "Auto" mode when selected', async () => { + const { togglePopover, selectRowHeightOption } = renderToolbar(); + togglePopover(); + selectRowHeightOption(/auto fit/i); expect(defaultProps.setState).toHaveBeenCalledTimes(1); - expect(defaultProps.setState).toHaveBeenNthCalledWith(1, { - headerRowHeight: 'single', - rowHeight: 'auto', - rowHeightLines: undefined, - }); + expect(defaultProps.setState).toHaveBeenCalledWith( + expect.objectContaining({ rowHeight: 'auto' }) + ); + }); - harness.changeRowHeight('single'); // turn it off + it('should toggle pagination on click', async () => { + const { togglePopover, clickPaginationSwitch } = renderToolbar(); + togglePopover(); - expect(defaultProps.setState).toHaveBeenCalledTimes(2); - expect(defaultProps.setState).toHaveBeenNthCalledWith(2, { - rowHeight: 'single', - headerRowHeight: 'single', - rowHeightLines: 1, - }); + clickPaginationSwitch(); + expect(defaultProps.setState).toHaveBeenCalledTimes(1); + expect(defaultProps.setState).toHaveBeenCalledWith( + expect.objectContaining({ paging: { enabled: true, size: 10 } }) + ); }); - it('should change row height to "Custom" mode', async () => { - harness.togglePopover(); - - harness.changeRowHeight('custom'); + it('should change row height to "Custom" mode when selected', async () => { + const { togglePopover, selectRowHeightOption } = renderToolbar(); + togglePopover(); + selectRowHeightOption(/custom/i); expect(defaultProps.setState).toHaveBeenCalledTimes(1); - expect(defaultProps.setState).toHaveBeenNthCalledWith(1, { + expect(defaultProps.setState).toHaveBeenCalledWith({ rowHeight: 'custom', headerRowHeight: 'single', rowHeightLines: 2, @@ -151,38 +157,44 @@ describe('datatable toolbar', () => { }); it('should change header height to "Custom" mode', async () => { - harness.togglePopover(); - - harness.changeHeaderRowHeight('custom'); + const { togglePopover, selectHeaderHeightOption } = renderToolbar(); + togglePopover(); + selectHeaderHeightOption(/custom/i); expect(defaultProps.setState).toHaveBeenCalledTimes(1); - expect(defaultProps.setState).toHaveBeenNthCalledWith(1, { + expect(defaultProps.setState).toHaveBeenCalledWith({ rowHeight: 'single', headerRowHeight: 'custom', headerRowHeightLines: 2, }); }); - it('should toggle table pagination', async () => { - harness.togglePopover(); - - harness.togglePagination(); + it('should toggle on table pagination', async () => { + const { togglePopover, clickPaginationSwitch } = renderToolbar(); + togglePopover(); + clickPaginationSwitch(); expect(defaultProps.setState).toHaveBeenCalledTimes(1); - expect(defaultProps.setState).toHaveBeenNthCalledWith(1, { - paging: defaultPagingState, - rowHeight: 'single', - headerRowHeight: 'single', - }); - - // update state manually - harness.wrapper.setProps({ - state: { rowHeight: 'single', headerRowHeight: 'single', paging: defaultPagingState }, + expect(defaultProps.setState).toHaveBeenCalledWith( + expect.objectContaining({ + paging: defaultPagingState, + rowHeight: 'single', + headerRowHeight: 'single', + }) + ); + }); + it('should toggle off table pagination', async () => { + const { togglePopover, clickPaginationSwitch } = renderToolbar({ + state: { + ...defaultProps.state, + paging: defaultPagingState, + }, }); - harness.togglePagination(); // turn it off. this should disable pagination but preserve the default page size + togglePopover(); + clickPaginationSwitch(); - expect(defaultProps.setState).toHaveBeenCalledTimes(2); - expect(defaultProps.setState).toHaveBeenNthCalledWith(2, { + expect(defaultProps.setState).toHaveBeenCalledTimes(1); + expect(defaultProps.setState).toHaveBeenCalledWith({ rowHeight: 'single', headerRowHeight: 'single', paging: { ...defaultPagingState, enabled: false }, diff --git a/x-pack/plugins/lens/tsconfig.json b/x-pack/plugins/lens/tsconfig.json index 3998fd28d896b..350cd1ad19a9e 100644 --- a/x-pack/plugins/lens/tsconfig.json +++ b/x-pack/plugins/lens/tsconfig.json @@ -102,6 +102,7 @@ "@kbn/discover-utils", "@kbn/lens-formula-docs", "@kbn/visualization-utils", + "@kbn/test-eui-helpers", "@kbn/shared-ux-utility" ], "exclude": [ diff --git a/yarn.lock b/yarn.lock index 3215adf87ef57..f0e621fde0473 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6199,6 +6199,10 @@ version "0.0.0" uid "" +"@kbn/test-eui-helpers@link:packages/kbn-test-eui-helpers": + version "0.0.0" + uid "" + "@kbn/test-feature-usage-plugin@link:x-pack/test/licensing_plugin/plugins/test_feature_usage": version "0.0.0" uid ""