diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fb50ac01cbf..9df8a70c52a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -172,6 +172,7 @@ /devenv/bulk-dashboards/ @grafana/dashboards-squad /devenv/bulk-folders/ @grafana/grafana-frontend-platform /devenv/create_docker_compose.sh @grafana/backend-platform +/devenv/alert_rules.yaml @grafana/alerting-backend-product /devenv/dashboards.yaml @grafana/dashboards-squad /devenv/datasources.yaml @grafana/backend-platform /devenv/datasources_docker.yaml @grafana/backend-platform diff --git a/.pa11yci-pr.conf.js b/.pa11yci-pr.conf.js index 1b29b930222..7424adf4c2d 100644 --- a/.pa11yci-pr.conf.js +++ b/.pa11yci-pr.conf.js @@ -103,7 +103,7 @@ var config = { rootElement: '.main-view', // the unified alerting promotion alert's content contrast is too low // see https://github.com/grafana/grafana/pull/41829 - threshold: 6, + threshold: 7, }, { url: '${HOST}/datasources', diff --git a/devenv/alert_rules.yaml b/devenv/alert_rules.yaml new file mode 100644 index 00000000000..dbf2f996576 --- /dev/null +++ b/devenv/alert_rules.yaml @@ -0,0 +1,158 @@ +apiVersion: 1 +groups: + - orgId: 1 + name: testEvaluationGroup + folder: gdev dashboards + interval: 5m + rules: + - uid: bddn0v6f1kgzkc + title: e2e-ReturnToPrevious-test + condition: C + data: + - refId: A + relativeTimeRange: + from: 600 + to: 0 + datasourceUid: PD8C576611E62080A + model: + intervalMs: 1000 + maxDataPoints: 43200 + refId: A + - refId: B + datasourceUid: __expr__ + model: + conditions: + - evaluator: + params: [] + type: gt + operator: + type: and + query: + params: + - B + reducer: + params: [] + type: last + type: query + datasource: + type: __expr__ + uid: __expr__ + expression: A + intervalMs: 1000 + maxDataPoints: 43200 + reducer: last + refId: B + type: reduce + - refId: C + datasourceUid: __expr__ + model: + conditions: + - evaluator: + params: + - 0 + type: gt + operator: + type: and + query: + params: + - C + reducer: + params: [] + type: last + type: query + datasource: + type: __expr__ + uid: __expr__ + expression: B + intervalMs: 1000 + maxDataPoints: 43200 + refId: C + type: threshold + dashboardUid: j6T00KRZz + panelId: 7 + noDataState: NoData + execErrState: Error + for: 5m + annotations: + __dashboardUid__: j6T00KRZz + __panelId__: "7" + labels: {} + isPaused: false + - orgId: 1 + name: testEvaluationGroup2 + folder: gdev dashboards + interval: 10m + rules: + - uid: dddyksihq7h1ca + title: e2e-ReturnToPrevious-test-2 + condition: C + data: + - refId: A + relativeTimeRange: + from: 600 + to: 0 + datasourceUid: PD8C576611E62080A + model: + intervalMs: 1000 + maxDataPoints: 43200 + refId: A + - refId: B + datasourceUid: __expr__ + model: + conditions: + - evaluator: + params: [] + type: gt + operator: + type: and + query: + params: + - B + reducer: + params: [] + type: last + type: query + datasource: + type: __expr__ + uid: __expr__ + expression: A + intervalMs: 1000 + maxDataPoints: 43200 + reducer: last + refId: B + type: reduce + - refId: C + datasourceUid: __expr__ + model: + conditions: + - evaluator: + params: + - 0 + type: gt + operator: + type: and + query: + params: + - C + reducer: + params: [] + type: last + type: query + datasource: + type: __expr__ + uid: __expr__ + expression: B + intervalMs: 1000 + maxDataPoints: 43200 + refId: C + type: threshold + dashboardUid: j6T00KRZz + panelId: 3 + noDataState: NoData + execErrState: Error + for: 10m + annotations: + __dashboardUid__: j6T00KRZz + __panelId__: "3" + labels: {} + isPaused: false diff --git a/e2e/various-suite/return-to-previous.spec.ts b/e2e/various-suite/return-to-previous.spec.ts new file mode 100644 index 00000000000..85b3f937e98 --- /dev/null +++ b/e2e/various-suite/return-to-previous.spec.ts @@ -0,0 +1,86 @@ +import { e2e } from '../utils'; + +describe('ReturnToPrevious button', () => { + beforeEach(() => { + e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); + cy.window().then((win) => { + win.localStorage.setItem('grafana.featureToggles', 'returnToPrevious=1'); + }); + + cy.visit('/alerting/list'); + e2e.components.AlertRules.groupToggle().first().click(); + e2e.components.AlertRules.toggle().click(); + cy.get('a[title="View"]').click(); + cy.url().as('alertRuleUrl'); + cy.get('a').contains('View panel').click(); + }); + + it('should appear when changing context and go back to alert rule when clicking "Back"', () => { + // make sure the dashboard finished loading + cy.get('button[aria-label*="BarChart - Label Rotation & Skipping"]').should('be.visible'); + + // check whether all elements of RTP are available + e2e.components.ReturnToPrevious.buttonGroup().should('be.visible'); + e2e.components.ReturnToPrevious.dismissButton().should('be.visible'); + e2e.components.ReturnToPrevious.backButton() + .find('span') + .contains('Back to e2e-ReturnToPrevious-test') + .should('be.visible') + .click(); + + // check whether the RTP button leads back to alert rule + cy.get('@alertRuleUrl').then((alertRuleUrl) => { + cy.url().should('eq', alertRuleUrl); + }); + }); + + it('should disappear when clicking "Dismiss"', () => { + e2e.components.ReturnToPrevious.dismissButton().should('be.visible').click(); + e2e.components.ReturnToPrevious.buttonGroup().should('not.exist'); + }); + + it('should not persist when going back to the alert rule details view', () => { + e2e.components.ReturnToPrevious.buttonGroup().should('be.visible'); + + // make sure the dashboard finished loading + cy.get('button[aria-label*="BarChart - Label Rotation & Skipping"]').should('be.visible'); + + cy.visit('/alerting/list'); + e2e.components.AlertRules.groupToggle().first().click(); + cy.get('a[title="View"]').click(); + e2e.components.ReturnToPrevious.buttonGroup().should('not.exist'); + }); + + it('should override the button label and change the href when user changes alert rules', () => { + // make sure the dashboard finished loading + cy.get('button[aria-label*="BarChart - Label Rotation & Skipping"]').should('be.visible'); + + e2e.components.ReturnToPrevious.backButton() + .find('span') + .contains('Back to e2e-ReturnToPrevious-test') + .should('be.visible'); + + cy.visit('/alerting/list'); + + e2e.components.AlertRules.groupToggle().last().click(); + cy.get('a[title="View"]').click(); + cy.url().as('alertRule2Url'); + cy.get('a').contains('View panel').click(); + + // make sure the dashboard finished loading + cy.get('button[aria-label*="BarChart - Label Rotation & Skipping"]').should('be.visible'); + + e2e.components.ReturnToPrevious.backButton() + .find('span') + .contains('Back to e2e-ReturnToPrevious-test-2') + .should('be.visible') + .click(); + + e2e.components.ReturnToPrevious.buttonGroup().should('not.exist'); + + // check whether the RTP button leads back to alert rule + cy.get('@alertRule2Url').then((alertRule2Url) => { + cy.url().should('eq', alertRule2Url); + }); + }); +}); diff --git a/packages/grafana-e2e-selectors/src/selectors/components.ts b/packages/grafana-e2e-selectors/src/selectors/components.ts index a1576e2383b..bd8d01da9de 100644 --- a/packages/grafana-e2e-selectors/src/selectors/components.ts +++ b/packages/grafana-e2e-selectors/src/selectors/components.ts @@ -293,6 +293,11 @@ export const Components = { AlertTab: { content: 'data-testid Alert editor tab content', }, + AlertRules: { + groupToggle: 'data-testid group-collapse-toggle', + toggle: 'data-testid collapse-toggle', + expandedContent: 'data-testid expanded-content', + }, Alert: { /** * @deprecated use alertV2 from Grafana 8.3 instead @@ -537,6 +542,11 @@ export const Components = { Tooltip: { container: 'data-testid tooltip', }, + ReturnToPrevious: { + buttonGroup: 'data-testid dismissable button group', + backButton: 'data-testid back', + dismissButton: 'data-testid dismiss', + }, SQLQueryEditor: { selectColumn: 'data-testid select-column', selectAggregation: 'data-testid select-aggregation', diff --git a/public/app/core/components/AppChrome/ReturnToPrevious/DismissableButton.tsx b/public/app/core/components/AppChrome/ReturnToPrevious/DismissableButton.tsx index 765dfed5306..a9fe92cdb24 100644 --- a/public/app/core/components/AppChrome/ReturnToPrevious/DismissableButton.tsx +++ b/public/app/core/components/AppChrome/ReturnToPrevious/DismissableButton.tsx @@ -2,6 +2,7 @@ import { css } from '@emotion/css'; import React from 'react'; import { GrafanaTheme2 } from '@grafana/data'; +import { selectors } from '@grafana/e2e-selectors'; import { Button, ButtonGroup, useStyles2 } from '@grafana/ui'; import { t } from 'app/core/internationalization'; @@ -24,6 +25,7 @@ export const DismissableButton = ({ label, onClick, onDismiss }: DismissableButt onClick={onClick} title={label} className={styles.mainDismissableButton} + data-testid={selectors.components.ReturnToPrevious.backButton} > {label} @@ -34,6 +36,7 @@ export const DismissableButton = ({ label, onClick, onDismiss }: DismissableButt fill="outline" size="sm" onClick={onDismiss} + data-testid={selectors.components.ReturnToPrevious.dismissButton} /> ); diff --git a/public/app/core/components/AppChrome/ReturnToPrevious/ReturnToPrevious.tsx b/public/app/core/components/AppChrome/ReturnToPrevious/ReturnToPrevious.tsx index 693aa72b83f..8d9ca18eabc 100644 --- a/public/app/core/components/AppChrome/ReturnToPrevious/ReturnToPrevious.tsx +++ b/public/app/core/components/AppChrome/ReturnToPrevious/ReturnToPrevious.tsx @@ -2,6 +2,7 @@ import { css } from '@emotion/css'; import React, { useCallback } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; +import { selectors } from '@grafana/e2e-selectors'; import { locationService } from '@grafana/runtime'; import { useStyles2 } from '@grafana/ui'; import { useGrafana } from 'app/core/context/GrafanaContext'; @@ -28,7 +29,7 @@ export const ReturnToPrevious = ({ href, title }: ReturnToPreviousProps) => { }, [chrome]); return ( -