From 3d5689cd07ea748badbefd9a91ee5ae0270e006b Mon Sep 17 00:00:00 2001 From: kay delaney <45561153+kaydelaney@users.noreply.github.com> Date: Tue, 13 May 2025 20:27:40 +0100 Subject: [PATCH] Dashboards/E2E: Add tests for drag and drop (#105066) --- e2e/cypress/support/assertions.js | 45 +++++++++++++++++++ e2e/cypress/support/e2e.js | 1 + e2e/cypress/support/index.d.ts | 7 +++ .../dashboards-move-panel.spec.ts | 34 ++++++++++++++ e2e/utils/flows/scenes/index.ts | 1 + e2e/utils/flows/scenes/movePanel.ts | 15 +++++++ 6 files changed, 103 insertions(+) create mode 100644 e2e/cypress/support/assertions.js create mode 100644 e2e/dashboard-new-layouts/dashboards-move-panel.spec.ts create mode 100644 e2e/utils/flows/scenes/movePanel.ts diff --git a/e2e/cypress/support/assertions.js b/e2e/cypress/support/assertions.js new file mode 100644 index 00000000000..582d2a5522f --- /dev/null +++ b/e2e/cypress/support/assertions.js @@ -0,0 +1,45 @@ +const elementPositions = (_chai) => { + function assertIsHigherThan(el) { + this.assert( + this._obj.offset().top < el.offset().top, + 'expected #{this} to be above target', + 'expected #{this} to not be above target', + this._obj + ); + } + + function assertIsLowerThan(el) { + this.assert( + this._obj.offset().top > el.offset().top, + 'expected #{this} to be below target', + 'expected #{this} to not be below target', + this._obj + ); + } + + function assertIsLeftOf(el) { + this.assert( + this._obj.offset().left < el.offset().left, + 'expected #{this} to be left of target', + 'expected #{this} to not be left of target', + this._obj + ); + } + + function assertIsRightOf(el) { + this.assert( + this._obj.offset().left > el.offset().left, + 'expected #{this} to be right of target', + 'expected #{this} to not be right of target', + this._obj + ); + } + + // Would prefer 'above' and 'below', but those already exist for numeric comparisons. Not sure they can be overloaded. + _chai.Assertion.addMethod('higherThan', assertIsHigherThan); + _chai.Assertion.addMethod('lowerThan', assertIsLowerThan); + _chai.Assertion.addMethod('leftOf', assertIsLeftOf); + _chai.Assertion.addMethod('rightOf', assertIsRightOf); +}; + +chai.use(elementPositions); diff --git a/e2e/cypress/support/e2e.js b/e2e/cypress/support/e2e.js index 912e99494cc..15cecf637f8 100644 --- a/e2e/cypress/support/e2e.js +++ b/e2e/cypress/support/e2e.js @@ -1,4 +1,5 @@ require('./commands'); +require('./assertions'); Cypress.Screenshot.defaults({ screenshotOnRunFailure: false, diff --git a/e2e/cypress/support/index.d.ts b/e2e/cypress/support/index.d.ts index c7d0acb7bcf..a473fe03c85 100644 --- a/e2e/cypress/support/index.d.ts +++ b/e2e/cypress/support/index.d.ts @@ -10,4 +10,11 @@ declare namespace Cypress { checkHealthRetryable(fn: Function, retryCount: number): Chainable; setLocalStorage(key: string, value: string); } + + interface Chainer> { + (chainer: 'be.higherThan'): Chainable; + (chainer: 'be.lowerThan'): Chainable; + (chainer: 'be.leftOf'): Chainable; + (chainer: 'be.rightOf'): Chainable; + } } diff --git a/e2e/dashboard-new-layouts/dashboards-move-panel.spec.ts b/e2e/dashboard-new-layouts/dashboards-move-panel.spec.ts new file mode 100644 index 00000000000..43cdf132b18 --- /dev/null +++ b/e2e/dashboard-new-layouts/dashboards-move-panel.spec.ts @@ -0,0 +1,34 @@ +import { e2e } from '../utils'; + +const PAGE_UNDER_TEST = 'ed155665/annotation-filtering'; + +describe('Dashboard', () => { + beforeEach(() => { + e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); + }); + + it('can drag and drop panels', () => { + e2e.pages.Dashboards.visit(); + e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); + + e2e.flows.scenes.toggleEditMode(); + + e2e.flows.scenes.movePanel(/^Panel three$/, /^Panel one$/); + e2e.components.Panels.Panel.headerContainer() + .contains(/^Panel three$/) + .then((panel3) => { + e2e.components.Panels.Panel.headerContainer() + .contains(/^Panel one$/) + .should('be.lowerThan', panel3); + }); + + e2e.flows.scenes.movePanel(/^Panel two$/, /^Panel three$/); + e2e.components.Panels.Panel.headerContainer() + .contains(/^Panel three$/) + .then((panel3) => { + e2e.components.Panels.Panel.headerContainer() + .contains(/^Panel two$/) + .should('be.higherThan', panel3); + }); + }); +}); diff --git a/e2e/utils/flows/scenes/index.ts b/e2e/utils/flows/scenes/index.ts index 314f5e4bcaa..c933c1e89d1 100644 --- a/e2e/utils/flows/scenes/index.ts +++ b/e2e/utils/flows/scenes/index.ts @@ -2,5 +2,6 @@ export * from './addPanel'; export * from './configurePanel'; export * from './removePanel'; export * from './toggleEditMode'; +export * from './movePanel'; export * from './groupPanels'; export * from './saveDashboard'; diff --git a/e2e/utils/flows/scenes/movePanel.ts b/e2e/utils/flows/scenes/movePanel.ts new file mode 100644 index 00000000000..111af14cdb9 --- /dev/null +++ b/e2e/utils/flows/scenes/movePanel.ts @@ -0,0 +1,15 @@ +import { e2e } from '../..'; + +/** Drags and drops the panel with title `sourcePanel` to the location of the panel with title `targetPanel` */ +export const movePanel = (sourcePanel: string | RegExp, targetPanel: string | RegExp) => { + e2e.components.Panels.Panel.headerContainer() + .contains(targetPanel) + .then((el) => { + const rect = el.offset(); + e2e.components.Panels.Panel.headerContainer() + .contains(sourcePanel) + .trigger('mousedown', { which: 1 }) + .trigger('mousemove', { clientX: rect.left, clientY: rect.top }) + .trigger('mouseup', { force: true }); + }); +};