Chore: Migrate frontend platform code to use data-testid for selectors (#81787)

* migrate some stuff from aria-label to data-testid

* convert styles to objects

* fix unit tests

* empty commit to kick drone now enterprise branch is there
This commit is contained in:
Ashley Harrison 2024-02-02 13:26:37 +00:00 committed by GitHub
parent cf6ebb0548
commit a30f8645d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 50 additions and 65 deletions

View File

@ -637,9 +637,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "6"], [0, 0, 0, "Unexpected any. Specify a different type.", "6"],
[0, 0, 0, "Unexpected any. Specify a different type.", "7"] [0, 0, 0, "Unexpected any. Specify a different type.", "7"]
], ],
"packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.tsx:5381": [
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"]
],
"packages/grafana-ui/src/components/Forms/Legacy/Input/Input.tsx:5381": [ "packages/grafana-ui/src/components/Forms/Legacy/Input/Input.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"], [0, 0, 0, "Do not use any type assertions.", "1"],
@ -1006,9 +1003,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "0"],
[0, 0, 0, "Styles should be written using objects.", "1"] [0, 0, 0, "Styles should be written using objects.", "1"]
], ],
"public/app/core/components/PageHeader/PanelHeaderMenuItem.tsx:5381": [
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"]
],
"public/app/core/components/PanelTypeFilter/PanelTypeFilter.tsx:5381": [ "public/app/core/components/PanelTypeFilter/PanelTypeFilter.tsx:5381": [
[0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "0"],
[0, 0, 0, "Styles should be written using objects.", "1"] [0, 0, 0, "Styles should be written using objects.", "1"]
@ -1016,11 +1010,6 @@ exports[`better eslint`] = {
"public/app/core/components/QueryOperationRow/OperationRowHelp.tsx:5381": [ "public/app/core/components/QueryOperationRow/OperationRowHelp.tsx:5381": [
[0, 0, 0, "Styles should be written using objects.", "0"] [0, 0, 0, "Styles should be written using objects.", "0"]
], ],
"public/app/core/components/QueryOperationRow/QueryOperationAction.tsx:5381": [
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"],
[0, 0, 0, "Styles should be written using objects.", "1"],
[0, 0, 0, "Styles should be written using objects.", "2"]
],
"public/app/core/components/QueryOperationRow/QueryOperationRow.tsx:5381": [ "public/app/core/components/QueryOperationRow/QueryOperationRow.tsx:5381": [
[0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "0"],
[0, 0, 0, "Styles should be written using objects.", "1"] [0, 0, 0, "Styles should be written using objects.", "1"]
@ -1046,10 +1035,6 @@ exports[`better eslint`] = {
"public/app/core/components/RolePicker/ValueContainer.tsx:5381": [ "public/app/core/components/RolePicker/ValueContainer.tsx:5381": [
[0, 0, 0, "Styles should be written using objects.", "0"] [0, 0, 0, "Styles should be written using objects.", "0"]
], ],
"public/app/core/components/Select/OldFolderPicker.tsx:5381": [
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"],
[0, 0, 0, "Styles should be written using objects.", "1"]
],
"public/app/core/components/TagFilter/TagFilter.tsx:5381": [ "public/app/core/components/TagFilter/TagFilter.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"],

View File

@ -285,7 +285,7 @@ export const Components = {
rows: 'Query editor row', rows: 'Query editor row',
}, },
QueryEditorRow: { QueryEditorRow: {
actionButton: (title: string) => `${title}`, actionButton: (title: string) => `data-testid ${title}`,
title: (refId: string) => `Query editor row title ${refId}`, title: (refId: string) => `Query editor row title ${refId}`,
container: (refId: string) => `Query editor row ${refId}`, container: (refId: string) => `Query editor row ${refId}`,
}, },
@ -392,7 +392,7 @@ export const Components = {
*/ */
container: 'Folder picker select container', container: 'Folder picker select container',
containerV2: 'data-testid Folder picker select container', containerV2: 'data-testid Folder picker select container',
input: 'Select a folder', input: 'data-testid folder-picker-input',
}, },
ReadonlyFolderPicker: { ReadonlyFolderPicker: {
container: 'data-testid Readonly folder picker select container', container: 'data-testid Readonly folder picker select container',

View File

@ -78,7 +78,7 @@ export const TimeRangeInput = ({
<button <button
type="button" type="button"
className={styles.pickerInput} className={styles.pickerInput}
aria-label={selectors.components.TimePicker.openButton} data-testid={selectors.components.TimePicker.openButton}
onClick={onOpen} onClick={onOpen}
> >
{showIcon && <Icon name="clock-nine" size={'sm'} className={styles.icon} />} {showIcon && <Icon name="clock-nine" size={'sm'} className={styles.icon} />}

View File

@ -33,7 +33,10 @@ export const PanelHeaderMenuItem = (props: Props & PanelMenuItem) => {
> >
<a onClick={props.onClick} href={props.href} role="menuitem"> <a onClick={props.onClick} href={props.href} role="menuitem">
{icon && <Icon name={icon} className={styles.menuIconClassName} />} {icon && <Icon name={icon} className={styles.menuIconClassName} />}
<span className="dropdown-item-text" aria-label={selectors.components.Panels.Panel.headerItems(props.text)}> <span
className="dropdown-item-text"
data-testid={selectors.components.Panels.Panel.headerItems(props.text)}
>
{props.text} {props.text}
{isSubMenu && <Icon name="angle-right" className={styles.shortcutIconClassName} />} {isSubMenu && <Icon name="angle-right" className={styles.shortcutIconClassName} />}
</span> </span>

View File

@ -2,8 +2,6 @@ import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
import React, { ComponentPropsWithoutRef } from 'react'; import React, { ComponentPropsWithoutRef } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { QueryOperationAction, QueryOperationToggleAction } from './QueryOperationAction'; import { QueryOperationAction, QueryOperationToggleAction } from './QueryOperationAction';
describe('QueryOperationAction tests', () => { describe('QueryOperationAction tests', () => {
@ -22,9 +20,7 @@ describe('QueryOperationAction tests', () => {
it('should render component', () => { it('should render component', () => {
setup(); setup();
expect( expect(screen.getByRole('button', { name: 'test' })).toBeInTheDocument();
screen.getByRole('button', { name: selectors.components.QueryEditorRow.actionButton('test') })
).toBeInTheDocument();
}); });
it('should call on click handler', async () => { it('should call on click handler', async () => {
@ -32,7 +28,7 @@ describe('QueryOperationAction tests', () => {
setup({ disabled: false, onClick: clickSpy }); setup({ disabled: false, onClick: clickSpy });
expect(clickSpy).not.toHaveBeenCalled(); expect(clickSpy).not.toHaveBeenCalled();
const queryButton = screen.getByRole('button', { name: selectors.components.QueryEditorRow.actionButton('test') }); const queryButton = screen.getByRole('button', { name: 'test' });
await userEvent.click(queryButton); await userEvent.click(queryButton);
@ -44,7 +40,7 @@ describe('QueryOperationAction tests', () => {
setup({ disabled: true, onClick: clickSpy }); setup({ disabled: true, onClick: clickSpy });
expect(clickSpy).not.toHaveBeenCalled(); expect(clickSpy).not.toHaveBeenCalled();
const queryButton = screen.getByRole('button', { name: selectors.components.QueryEditorRow.actionButton('test') }); const queryButton = screen.getByRole('button', { name: 'test' });
await userEvent.click(queryButton); await userEvent.click(queryButton);
@ -69,7 +65,7 @@ describe('QueryOperationToggleAction', () => {
expect( expect(
screen.getByRole('button', { screen.getByRole('button', {
name: selectors.components.QueryEditorRow.actionButton('test'), name: 'test',
pressed: false, pressed: false,
}) })
).toBeInTheDocument(); ).toBeInTheDocument();
@ -78,7 +74,7 @@ describe('QueryOperationToggleAction', () => {
expect( expect(
screen.getByRole('button', { screen.getByRole('button', {
name: selectors.components.QueryEditorRow.actionButton('test'), name: 'test',
pressed: true, pressed: true,
}) })
).toBeInTheDocument(); ).toBeInTheDocument();

View File

@ -25,8 +25,7 @@ function BaseQueryOperationAction(props: QueryOperationActionProps | QueryOperat
disabled={!!props.disabled} disabled={!!props.disabled}
onClick={props.onClick} onClick={props.onClick}
type="button" type="button"
aria-label={selectors.components.QueryEditorRow.actionButton(props.title)} data-testid={props.dataTestId ?? selectors.components.QueryEditorRow.actionButton(props.title)}
data-testid={props.dataTestId}
{...('active' in props && { 'aria-pressed': props.active })} {...('active' in props && { 'aria-pressed': props.active })}
/> />
</div> </div>
@ -47,23 +46,23 @@ export const QueryOperationToggleAction = (props: QueryOperationToggleActionProp
const getStyles = (theme: GrafanaTheme2) => { const getStyles = (theme: GrafanaTheme2) => {
return { return {
icon: css` icon: css({
display: flex; display: 'flex',
position: relative; position: 'relative',
color: ${theme.colors.text.secondary}; color: theme.colors.text.secondary,
`, }),
active: css` active: css({
&::before { '&:before': {
display: block; display: 'block',
content: ' '; content: '" "',
position: absolute; position: 'absolute',
left: -1px; left: -1,
right: 2px; right: 2,
height: 3px; height: 3,
border-radius: ${theme.shape.radius.default}; borderRadius: theme.shape.radius.default,
bottom: -8px; bottom: -8,
background-image: ${theme.colors.gradients.brandHorizontal} !important; backgroundImage: theme.colors.gradients.brandHorizontal,
} },
`, }),
}; };
}; };

View File

@ -35,7 +35,7 @@ describe('OldFolderPicker', () => {
render(<OldFolderPicker onChange={jest.fn()} filter={(hits) => hits.filter((h) => h.uid !== 'wfTJJL5Wz')} />); render(<OldFolderPicker onChange={jest.fn()} filter={(hits) => hits.filter((h) => h.uid !== 'wfTJJL5Wz')} />);
const pickerContainer = screen.getByLabelText(selectors.components.FolderPicker.input); const pickerContainer = screen.getByTestId(selectors.components.FolderPicker.input);
selectEvent.openMenu(pickerContainer); selectEvent.openMenu(pickerContainer);
const pickerOptions = await screen.findAllByLabelText('Select option'); const pickerOptions = await screen.findAllByLabelText('Select option');
@ -62,7 +62,7 @@ describe('OldFolderPicker', () => {
render(<OldFolderPicker onChange={onChangeFn} enableCreateNew={true} allowEmpty={true} />); render(<OldFolderPicker onChange={onChangeFn} enableCreateNew={true} allowEmpty={true} />);
expect(await screen.findByTestId(selectors.components.FolderPicker.containerV2)).toBeInTheDocument(); expect(await screen.findByTestId(selectors.components.FolderPicker.containerV2)).toBeInTheDocument();
await userEvent.type(screen.getByLabelText('Select a folder'), newFolder.title); await userEvent.type(screen.getByTestId(selectors.components.FolderPicker.input), newFolder.title);
const enter = await screen.findByText('Hit enter to add'); const enter = await screen.findByText('Hit enter to add');
await userEvent.click(enter); await userEvent.click(enter);
@ -89,7 +89,7 @@ describe('OldFolderPicker', () => {
const onChangeFn = jest.fn(); const onChangeFn = jest.fn();
render(<OldFolderPicker onChange={onChangeFn} />); render(<OldFolderPicker onChange={onChangeFn} />);
expect(await screen.findByTestId(selectors.components.FolderPicker.containerV2)).toBeInTheDocument(); expect(await screen.findByTestId(selectors.components.FolderPicker.containerV2)).toBeInTheDocument();
const pickerContainer = screen.getByLabelText(selectors.components.FolderPicker.input); const pickerContainer = screen.getByTestId(selectors.components.FolderPicker.input);
selectEvent.openMenu(pickerContainer); selectEvent.openMenu(pickerContainer);
const pickerOptions = await screen.findAllByLabelText('Select option'); const pickerOptions = await screen.findAllByLabelText('Select option');
@ -110,7 +110,7 @@ describe('OldFolderPicker', () => {
const onChangeFn = jest.fn(); const onChangeFn = jest.fn();
render(<OldFolderPicker onChange={onChangeFn} showRoot={false} />); render(<OldFolderPicker onChange={onChangeFn} showRoot={false} />);
expect(await screen.findByTestId(selectors.components.FolderPicker.containerV2)).toBeInTheDocument(); expect(await screen.findByTestId(selectors.components.FolderPicker.containerV2)).toBeInTheDocument();
const pickerContainer = screen.getByLabelText(selectors.components.FolderPicker.input); const pickerContainer = screen.getByTestId(selectors.components.FolderPicker.input);
selectEvent.openMenu(pickerContainer); selectEvent.openMenu(pickerContainer);
const pickerOptions = await screen.findAllByLabelText('Select option'); const pickerOptions = await screen.findAllByLabelText('Select option');
@ -131,7 +131,7 @@ describe('OldFolderPicker', () => {
const onChangeFn = jest.fn(); const onChangeFn = jest.fn();
render(<OldFolderPicker onChange={onChangeFn} />); render(<OldFolderPicker onChange={onChangeFn} />);
expect(await screen.findByTestId(selectors.components.FolderPicker.containerV2)).toBeInTheDocument(); expect(await screen.findByTestId(selectors.components.FolderPicker.containerV2)).toBeInTheDocument();
const pickerContainer = screen.getByLabelText(selectors.components.FolderPicker.input); const pickerContainer = screen.getByTestId(selectors.components.FolderPicker.input);
selectEvent.openMenu(pickerContainer); selectEvent.openMenu(pickerContainer);
const pickerOptions = await screen.findAllByLabelText('Select option'); const pickerOptions = await screen.findAllByLabelText('Select option');
@ -152,7 +152,7 @@ describe('OldFolderPicker', () => {
const onChangeFn = jest.fn(); const onChangeFn = jest.fn();
render(<OldFolderPicker onChange={onChangeFn} />); render(<OldFolderPicker onChange={onChangeFn} />);
const pickerContainer = screen.getByLabelText(selectors.components.FolderPicker.input); const pickerContainer = screen.getByTestId(selectors.components.FolderPicker.input);
await userEvent.type(pickerContainer, 'Test'); await userEvent.type(pickerContainer, 'Test');
expect(await screen.findByText('Dash Test')).toBeInTheDocument(); expect(await screen.findByText('Dash Test')).toBeInTheDocument();

View File

@ -340,7 +340,7 @@ export function OldFolderPicker(props: Props) {
<FolderWarningWhenSearching /> <FolderWarningWhenSearching />
<AsyncVirtualizedSelect <AsyncVirtualizedSelect
inputId={inputId} inputId={inputId}
aria-label={selectors.components.FolderPicker.input} data-testid={selectors.components.FolderPicker.input}
loadingMessage={t('folder-picker.loading', 'Loading folders...')} loadingMessage={t('folder-picker.loading', 'Loading folders...')}
defaultOptions defaultOptions
defaultValue={folder} defaultValue={folder}
@ -383,9 +383,9 @@ export async function getInitialValues({ folderName, folderUid, getFolder }: Arg
} }
const getStyles = (theme: GrafanaTheme2) => ({ const getStyles = (theme: GrafanaTheme2) => ({
newFolder: css` newFolder: css({
color: ${theme.colors.warning.main}; color: theme.colors.warning.main,
font-size: ${theme.typography.bodySmall.fontSize}; fontSize: theme.typography.bodySmall.fontSize,
padding-bottom: ${theme.spacing(1)}; paddingBottom: theme.spacing(1),
`, }),
}); });

View File

@ -5,6 +5,7 @@ import { TestProvider } from 'test/helpers/TestProvider';
import { byLabelText, byPlaceholderText, byRole, byTestId, byText } from 'testing-library-selector'; import { byLabelText, byPlaceholderText, byRole, byTestId, byText } from 'testing-library-selector';
import { dateTime } from '@grafana/data'; import { dateTime } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { config, locationService, setDataSourceSrv } from '@grafana/runtime'; import { config, locationService, setDataSourceSrv } from '@grafana/runtime';
import { contextSrv } from 'app/core/services/context_srv'; import { contextSrv } from 'app/core/services/context_srv';
import { AlertState, MatcherOperator } from 'app/plugins/datasource/alertmanager/types'; import { AlertState, MatcherOperator } from 'app/plugins/datasource/alertmanager/types';
@ -62,7 +63,7 @@ const ui = {
addSilenceButton: byRole('link', { name: /add silence/i }), addSilenceButton: byRole('link', { name: /add silence/i }),
queryBar: byPlaceholderText('Search'), queryBar: byPlaceholderText('Search'),
editor: { editor: {
timeRange: byLabelText('Timepicker', { exact: false }), timeRange: byTestId(selectors.components.TimePicker.openButton),
durationField: byLabelText('Duration'), durationField: byLabelText('Duration'),
durationInput: byRole('textbox', { name: /duration/i }), durationInput: byRole('textbox', { name: /duration/i }),
matchersField: byTestId('matcher'), matchersField: byTestId('matcher'),

View File

@ -4,6 +4,7 @@ import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider'; import { TestProvider } from 'test/helpers/TestProvider';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest'; import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { selectors } from '@grafana/e2e-selectors';
import { setBackendSrv } from '@grafana/runtime'; import { setBackendSrv } from '@grafana/runtime';
import { backendSrv } from 'app/core/services/__mocks__/backend_srv'; import { backendSrv } from 'app/core/services/__mocks__/backend_srv';
import * as api from 'app/features/manage-dashboards/state/actions'; import * as api from 'app/features/manage-dashboards/state/actions';
@ -70,7 +71,7 @@ describe('browse-dashboards MoveModal', () => {
it('displays a folder picker', async () => { it('displays a folder picker', async () => {
render(<MoveModal {...props} />); render(<MoveModal {...props} />);
expect(await screen.findByRole('combobox', { name: 'Select a folder' })).toBeInTheDocument(); expect(await screen.findByTestId(selectors.components.FolderPicker.input)).toBeInTheDocument();
}); });
it('displays a warning about permissions if a folder is selected', async () => { it('displays a warning about permissions if a folder is selected', async () => {
@ -88,7 +89,7 @@ describe('browse-dashboards MoveModal', () => {
render(<MoveModal {...props} />); render(<MoveModal {...props} />);
expect(await screen.findByRole('button', { name: 'Move' })).toBeDisabled(); expect(await screen.findByRole('button', { name: 'Move' })).toBeDisabled();
const folderPicker = await screen.findByRole('combobox', { name: 'Select a folder' }); const folderPicker = await screen.findByTestId(selectors.components.FolderPicker.input);
await selectOptionInTest(folderPicker, mockFolders[1].title); await selectOptionInTest(folderPicker, mockFolders[1].title);
expect(await screen.findByRole('button', { name: 'Move' })).toBeEnabled(); expect(await screen.findByRole('button', { name: 'Move' })).toBeEnabled();
@ -96,7 +97,7 @@ describe('browse-dashboards MoveModal', () => {
it('calls onConfirm when clicking the `Move` button', async () => { it('calls onConfirm when clicking the `Move` button', async () => {
render(<MoveModal {...props} />); render(<MoveModal {...props} />);
const folderPicker = await screen.findByRole('combobox', { name: 'Select a folder' }); const folderPicker = await screen.findByTestId(selectors.components.FolderPicker.input);
await selectOptionInTest(folderPicker, mockFolders[1].title); await selectOptionInTest(folderPicker, mockFolders[1].title);
await userEvent.click(await screen.findByRole('button', { name: 'Move' })); await userEvent.click(await screen.findByRole('button', { name: 'Move' }));

View File

@ -93,7 +93,7 @@ describe('TransformationsEditor', () => {
expect(screen.queryByTestId(debuggerSelector)).toBeNull(); expect(screen.queryByTestId(debuggerSelector)).toBeNull();
const debugButton = screen.getByLabelText(selectors.components.QueryEditorRow.actionButton('Debug')); const debugButton = screen.getByTestId(selectors.components.QueryEditorRow.actionButton('Debug'));
await userEvent.click(debugButton); await userEvent.click(debugButton);
expect(screen.getByTestId(debuggerSelector)).toBeInTheDocument(); expect(screen.getByTestId(debuggerSelector)).toBeInTheDocument();