mirror of
https://github.com/grafana/grafana.git
synced 2025-07-30 18:32:28 +08:00
Dashboard edit panel e2e (#104775)
setup suite for edit panel; start adding test for custom variable edit
This commit is contained in:
@ -0,0 +1,60 @@
|
||||
import { e2e } from '../utils';
|
||||
|
||||
const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output';
|
||||
const DASHBOARD_NAME = 'Test variable output';
|
||||
|
||||
describe('Dashboard edit variables', () => {
|
||||
beforeEach(() => {
|
||||
e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD'));
|
||||
});
|
||||
|
||||
it('can add a new custom variable', () => {
|
||||
e2e.pages.Dashboards.visit();
|
||||
|
||||
e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` });
|
||||
cy.contains(DASHBOARD_NAME).should('be.visible');
|
||||
|
||||
const variable: Variable = {
|
||||
type: 'custom',
|
||||
name: 'foo',
|
||||
label: 'Foo',
|
||||
value: 'one,two,three',
|
||||
};
|
||||
|
||||
// common steps to add a new variable
|
||||
flows.newEditPaneVariableClick();
|
||||
flows.newEditPanelCommonVariableInputs(variable);
|
||||
|
||||
// set the custom variable value
|
||||
e2e.pages.Dashboard.Settings.Variables.Edit.CustomVariable.customValueInput().clear().type(variable.value).blur();
|
||||
|
||||
// assert the dropdown for the variable is visible and has the correct values
|
||||
e2e.pages.Dashboard.SubMenu.submenuItemLabels(variable.label).should('be.visible').contains(variable.label);
|
||||
const values = variable.value.split(',');
|
||||
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts(values[0]).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
// Common flows for adding/editing variables
|
||||
// TODO: maybe move to e2e flows
|
||||
const flows = {
|
||||
newEditPaneVariableClick() {
|
||||
e2e.components.NavToolbar.editDashboard.editButton().should('be.visible').click();
|
||||
e2e.components.PanelEditor.Outline.section().should('be.visible').click();
|
||||
e2e.components.PanelEditor.Outline.item('Variables').should('be.visible').click();
|
||||
e2e.components.PanelEditor.ElementEditPane.addVariableButton().should('be.visible').click();
|
||||
},
|
||||
newEditPanelCommonVariableInputs(variable: Variable) {
|
||||
e2e.components.PanelEditor.ElementEditPane.variableType(variable.type).should('be.visible').click();
|
||||
e2e.components.PanelEditor.ElementEditPane.variableNameInput().clear().type(variable.name).blur();
|
||||
e2e.components.PanelEditor.ElementEditPane.variableLabelInput().clear().type(variable.label).blur();
|
||||
},
|
||||
};
|
||||
|
||||
type Variable = {
|
||||
type: string;
|
||||
name: string;
|
||||
label: string;
|
||||
description?: string;
|
||||
value: string;
|
||||
};
|
@ -30,6 +30,7 @@ rootForEnterpriseSuite="./e2e/extensions-suite"
|
||||
rootForOldArch="./e2e/old-arch"
|
||||
rootForKubernetesDashboards="./e2e/dashboards-suite"
|
||||
rootForSearchDashboards="./e2e/dashboards-search-suite"
|
||||
rootForEditDashboards="./e2e/dashboards-edit-v2-suite"
|
||||
|
||||
declare -A cypressConfig=(
|
||||
[screenshotsFolder]=./e2e/"${args[0]}"/screenshots
|
||||
@ -149,6 +150,25 @@ case "$1" in
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
"dashboards-edit-v2")
|
||||
env[kubernetesDashboards]=true
|
||||
env[dashboardNewLayouts]=true
|
||||
cypressConfig[specPattern]=$rootForEditDashboards/$testFilesForSingleSuite
|
||||
cypressConfig[video]=false
|
||||
case "$2" in
|
||||
"debug")
|
||||
echo -e "Debug mode"
|
||||
env[SLOWMO]=1
|
||||
PARAMS="--no-exit"
|
||||
enterpriseSuite=$(basename "${args[2]}")
|
||||
;;
|
||||
"dev")
|
||||
echo "Dev mode"
|
||||
CMD="cypress open"
|
||||
enterpriseSuite=$(basename "${args[2]}")
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
"enterprise-smtp")
|
||||
env[SMTP_PLUGIN_ENABLED]=true
|
||||
cypressConfig[specPattern]=./e2e/extensions/enterprise/smtp-suite/$testFilesForSingleSuite
|
||||
|
@ -14,6 +14,8 @@
|
||||
"e2e:old-arch": "./e2e/start-and-run-suite old-arch",
|
||||
"e2e:schema-v2": "./e2e/start-and-run-suite dashboards-schema-v2",
|
||||
"e2e:dashboards-search": "./e2e/start-and-run-suite dashboards-search",
|
||||
"e2e:dashboards-edit-v2": "./e2e/start-and-run-suite dashboards-edit-v2",
|
||||
"e2e:dashboards-edit-v2:dev": "./e2e/start-and-run-suite dashboards-edit-v2 dev",
|
||||
"e2e:debug": "./e2e/start-and-run-suite debug",
|
||||
"e2e:dev": "./e2e/start-and-run-suite dev",
|
||||
"e2e:benchmark:live": "./e2e/start-and-run-suite benchmark live",
|
||||
|
@ -532,6 +532,33 @@ export const versionedComponents = {
|
||||
measureButton: {
|
||||
'9.2.0': 'show measure tools',
|
||||
},
|
||||
|
||||
Outline: {
|
||||
section: {
|
||||
'12.0.0': 'data-testid Outline section',
|
||||
},
|
||||
node: {
|
||||
'12.0.0': (type: string) => `data-testid outline node ${type}`,
|
||||
},
|
||||
item: {
|
||||
'12.0.0': (type: string) => `data-testid outline item ${type}`,
|
||||
},
|
||||
},
|
||||
|
||||
ElementEditPane: {
|
||||
variableType: {
|
||||
'12.0.0': (type?: string) => `data-testid variable type ${type}`,
|
||||
},
|
||||
addVariableButton: {
|
||||
'12.0.0': 'data-testid add variable button',
|
||||
},
|
||||
variableNameInput: {
|
||||
'12.0.0': 'data-testid variable name input',
|
||||
},
|
||||
variableLabelInput: {
|
||||
'12.0.0': 'data-testid variable label input',
|
||||
},
|
||||
},
|
||||
},
|
||||
PanelInspector: {
|
||||
Data: {
|
||||
|
@ -3,6 +3,7 @@ import { Resizable } from 're-resizable';
|
||||
import { useLocalStorage } from 'react-use';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { SceneObjectState, SceneObjectBase, SceneObject, sceneGraph, useSceneObjectState } from '@grafana/scenes';
|
||||
import {
|
||||
ElementSelectionContextItem,
|
||||
@ -272,11 +273,12 @@ export function DashboardEditPaneRenderer({ editPane, isCollapsed, onToggleColla
|
||||
role="button"
|
||||
onClick={() => setOutlineCollapsed(!outlineCollapsed)}
|
||||
className={styles.outlineCollapseButton}
|
||||
data-testid={selectors.components.PanelEditor.Outline.section}
|
||||
>
|
||||
<Text weight="medium">
|
||||
<Trans i18nKey="dashboard-scene.dashboard-edit-pane-renderer.outline">Outline</Trans>
|
||||
</Text>
|
||||
<Icon name="angle-up" />
|
||||
<Icon name={outlineCollapsed ? 'angle-up' : 'angle-down'} />
|
||||
</div>
|
||||
{!outlineCollapsed && (
|
||||
<div className={styles.outlineContainer}>
|
||||
|
@ -3,6 +3,7 @@ import { sortBy } from 'lodash';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { SceneObject } from '@grafana/scenes';
|
||||
import { Box, Icon, Text, useElementSelection, useStyles2, useTheme2 } from '@grafana/ui';
|
||||
import { t, Trans } from 'app/core/internationalization';
|
||||
@ -88,7 +89,12 @@ function DashboardOutlineNode({
|
||||
onPointerDown={onNodeClicked}
|
||||
>
|
||||
{elementInfo.isContainer && (
|
||||
<button role="treeitem" className={styles.angleButton} onPointerDown={onToggleCollapse}>
|
||||
<button
|
||||
role="treeitem"
|
||||
className={styles.angleButton}
|
||||
onPointerDown={onToggleCollapse}
|
||||
data-testid={selectors.components.PanelEditor.Outline.node(instanceName)}
|
||||
>
|
||||
<Icon name={!isCollapsed ? 'angle-down' : 'angle-right'} />
|
||||
</button>
|
||||
)}
|
||||
@ -96,6 +102,7 @@ function DashboardOutlineNode({
|
||||
role="button"
|
||||
className={cx(styles.nodeName, isCloned && styles.nodeNameClone)}
|
||||
onDoubleClick={outlineRename.onNameDoubleClicked}
|
||||
data-testid={selectors.components.PanelEditor.Outline.item(instanceName)}
|
||||
>
|
||||
<Icon size="sm" name={elementInfo.icon} />
|
||||
{outlineRename.isRenaming ? (
|
||||
|
@ -11,7 +11,7 @@ interface Props {
|
||||
checkedIcon?: IconName;
|
||||
checkedLabel?: string;
|
||||
disabled?: boolean;
|
||||
'data-testId'?: string;
|
||||
'data-testid'?: string;
|
||||
onClick: (evt: MouseEvent<HTMLDivElement>) => void;
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ export const ToolbarSwitch = ({
|
||||
checkedLabel,
|
||||
disabled,
|
||||
onClick,
|
||||
'data-testId': dataTestId,
|
||||
'data-testid': dataTestId,
|
||||
}: Props) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { FormEvent, useMemo, useState } from 'react';
|
||||
|
||||
import { VariableHide } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { LocalValueVariable, MultiValueVariable, SceneVariable, SceneVariableSet } from '@grafana/scenes';
|
||||
import { Input, TextArea, Button, Field, Box, Stack } from '@grafana/ui';
|
||||
@ -143,14 +144,27 @@ function VariableNameInput({ variable, isNewElement }: { variable: SceneVariable
|
||||
|
||||
return (
|
||||
<Field label={t('dashboard.edit-pane.variable.name', 'Name')} invalid={!!nameError} error={nameError}>
|
||||
<Input ref={ref} value={name} onChange={onChange} required onBlur={onBlur} />
|
||||
<Input
|
||||
ref={ref}
|
||||
value={name}
|
||||
onChange={onChange}
|
||||
required
|
||||
onBlur={onBlur}
|
||||
data-testid={selectors.components.PanelEditor.ElementEditPane.variableNameInput}
|
||||
/>
|
||||
</Field>
|
||||
);
|
||||
}
|
||||
|
||||
function VariableLabelInput({ variable }: VariableInputProps) {
|
||||
const { label } = variable.useState();
|
||||
return <Input value={label} onChange={(e) => variable.setState({ label: e.currentTarget.value })} />;
|
||||
return (
|
||||
<Input
|
||||
value={label}
|
||||
onChange={(e) => variable.setState({ label: e.currentTarget.value })}
|
||||
data-testid={selectors.components.PanelEditor.ElementEditPane.variableLabelInput}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function VariableDescriptionTextArea({ variable }: VariableInputProps) {
|
||||
|
@ -3,6 +3,7 @@ import { useMemo } from 'react';
|
||||
import { useToggle } from 'react-use';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { SceneVariable, SceneVariableSet } from '@grafana/scenes';
|
||||
import { Stack, Button, useStyles2, Text, Box, Card } from '@grafana/ui';
|
||||
import { t, Trans } from 'app/core/internationalization';
|
||||
@ -87,7 +88,14 @@ function VariableList({ set }: { set: SceneVariableSet }) {
|
||||
))}
|
||||
{canAdd && (
|
||||
<Box paddingBottom={1} display={'flex'}>
|
||||
<Button fullWidth icon="plus" size="sm" variant="secondary" onClick={setIsAdding}>
|
||||
<Button
|
||||
fullWidth
|
||||
icon="plus"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
onClick={setIsAdding}
|
||||
data-testid={selectors.components.PanelEditor.ElementEditPane.addVariableButton}
|
||||
>
|
||||
<Trans i18nKey="dashboard.edit-pane.variables.add-variable">Add variable</Trans>
|
||||
</Button>
|
||||
</Box>
|
||||
@ -115,6 +123,7 @@ function VariableTypeSelection({ onAddVariable }: VariableTypeSelectionProps) {
|
||||
onClick={() => onAddVariable(option.value!)}
|
||||
key={option.value}
|
||||
title={t('dashboard.edit-pane.variables.select-type-card-tooltip', 'Click to select type')}
|
||||
data-testid={selectors.components.PanelEditor.ElementEditPane.variableType(option.value!)}
|
||||
>
|
||||
<Card.Heading>{option.label}</Card.Heading>
|
||||
<Card.Description className={styles.cardDescription}>{option.description}</Card.Description>
|
||||
|
Reference in New Issue
Block a user