From 90d847cdd33bc01a345d3e989754f3cd6c3bdac9 Mon Sep 17 00:00:00 2001 From: Ekhorn Date: Mon, 29 Jun 2026 14:20:13 +0200 Subject: [PATCH 1/2] Refactor widget resizing logic --- .../manager/test/fixtures/pages/insights.ts | 33 ++++++++++++------- ui/app/manager/test/insights.test.ts | 14 ++++---- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/ui/app/manager/test/fixtures/pages/insights.ts b/ui/app/manager/test/fixtures/pages/insights.ts index 2e82ddf66d..1eaa8d1624 100644 --- a/ui/app/manager/test/fixtures/pages/insights.ts +++ b/ui/app/manager/test/fixtures/pages/insights.ts @@ -44,6 +44,15 @@ export class InsightsPage implements BasePage { return this.getDashboardGrid().evaluate((el: any) => [el.gridstack.cellWidth(), el.gridstack.getCellHeight()]); } + /** + * Gets the parent Gridstack item container for a given widget. + * @param widget The `or-dashboard-widget-container` locator + * @returns The locator for the Gridstack item container + */ + getWidgetGSContainer(widget: Locator): Locator { + return widget.locator("..").locator(".."); + } + /** * Gets the x and y coordinates for the specified widget * @requires the locator to reference a `or-dashboard-widget-container` to be able to get the Gridstack node @@ -51,7 +60,7 @@ export class InsightsPage implements BasePage { * @returns The x and y grid cell coordinates */ getWidgetLocation(widget: Locator): Promise<[number, number]> { - return widget.locator("..").locator("..").evaluate((el: any) => [el.gridstackNode.x, el.gridstackNode.y]); + return this.getWidgetGSContainer(widget).evaluate((el: any) => [el.gridstackNode.x, el.gridstackNode.y]); } /** @@ -92,21 +101,23 @@ export class InsightsPage implements BasePage { * @param widget The locator of the widget * @param to The grid cell coordinates to resize the widget to */ - async resizeWidgetTo(widget: Locator, [cellsWidth, cellsHeight] = [8, 8]) { + async resizeWidgetTo(widget: Locator, [cellsWidth, cellsHeight] = [8, 8], { force } = { force: false }) { const [gridX, gridY] = await this.getWidgetLocation(widget); const [cellWidth, cellHeight] = await this.getGridCellDimensions(); const [width, height] = [cellsWidth * cellWidth, cellsHeight * cellHeight]; + const grid = this.page.locator(".maingrid"); + await this.getWidgetGSContainer(widget).locator(".ui-resizable-handle.ui-resizable-se").dragTo(grid, { + force, // We apply -cellWidth/Height / 2 as the handle causes the source position to be offset - const handle = widget.locator("..").locator("..").locator(".ui-resizable-handle.ui-resizable-se"); - const handleBox = await handle.boundingBox(); - const gridBox = await this.page.locator(".maingrid").boundingBox(); - const targetX = gridBox!.x + gridX * cellWidth + width - cellWidth / 2; - const targetY = gridBox!.y + gridY * cellHeight + height - cellHeight / 2; - await this.page.mouse.move(handleBox!.x + handleBox!.width / 2, handleBox!.y + handleBox!.height / 2); - await this.page.mouse.down(); - await this.page.mouse.move(targetX, targetY, { steps: 10 }); - await this.page.mouse.up(); + targetPosition: { + x: gridX * cellWidth + width - cellWidth / 2, + y: gridY * cellHeight + height - cellHeight / 2, + }, + steps: 10, + }); + + if (force) return; const bbox = await widget.boundingBox(); // The dashboard dimensions should be equal to the specified cells, diff --git a/ui/app/manager/test/insights.test.ts b/ui/app/manager/test/insights.test.ts index 1492d7e504..4fafe73a0b 100644 --- a/ui/app/manager/test/insights.test.ts +++ b/ui/app/manager/test/insights.test.ts @@ -176,15 +176,15 @@ test("Replace broken chart references while preserving custom colors", async ({ // Drop both widgets while the widget palette is available (no widget selected yet) await insightsPage.dragAndDropWidget("Line Chart", [0, 0]); await expect(insightsPage.getWidgets()).toHaveCount(1); - await insightsPage.dragAndDropWidget("Bar Chart", [0, 4]); + await insightsPage.dragAndDropWidget("Bar Chart", [6, 0]); await expect(insightsPage.getWidgets()).toHaveCount(2); const lineWidget = insightsPage.getWidgets({ hasText: "Line Chart" }).first(); const barWidget = insightsPage.getWidgets({ hasText: "Bar Chart" }).first(); // Line chart: add the Power attribute and give it a custom red colour await insightsPage.selectWidget(lineWidget); - await expect(insightsPage.getWidgetSettings({ hasText: "Line Chart" })).toBeVisible({ timeout: 30000 }); - await insightsPage.resizeWidgetTo(lineWidget, [4, 4]); + await expect(insightsPage.getWidgetSettings({ hasText: "Line Chart" })).toBeVisible(); + await insightsPage.resizeWidgetTo(lineWidget, [6, 6]); await insightsPage.addAttributes(referencedAsset.name!, ["Power"]); await expect(insightsPage.getWidgetAttributes()).toHaveCount(1); await insightsPage.setAttributeColor("#ff0000"); @@ -195,8 +195,8 @@ test("Replace broken chart references while preserving custom colors", async ({ // Bar chart: add the Power attribute and give it a custom green colour await insightsPage.selectWidget(barWidget); - await expect(insightsPage.getWidgetSettings({ hasText: "Bar Chart" })).toBeVisible({ timeout: 30000 }); - await insightsPage.resizeWidgetTo(barWidget, [4, 4]); + await expect(insightsPage.getWidgetSettings({ hasText: "Bar Chart" })).toBeVisible(); + await insightsPage.resizeWidgetTo(barWidget, [12, 6], { force: true }); await insightsPage.addAttributes(referencedAsset.name!, ["Power"]); await expect(insightsPage.getWidgetAttributes()).toHaveCount(1); await insightsPage.setAttributeColor("#00ff00"); @@ -213,8 +213,8 @@ test("Replace broken chart references while preserving custom colors", async ({ const adminToken = await manager.getAccessToken("master", "admin", users.admin.password!); await manager.deleteAssets({ headers: { Authorization: `Bearer ${adminToken}` } }); await page.reload(); - await expect(insightsPage.getBuilder()).toBeVisible({ timeout: 30000 }); - await expect(insightsPage.getPreview()).toBeVisible({ timeout: 30000 }); + await expect(insightsPage.getBuilder()).toBeVisible(); + await expect(insightsPage.getPreview()).toBeVisible(); await expect(insightsPage.getPreview()).toHaveJSProperty("isLoading", false); await expect(insightsPage.getWidgets()).toHaveCount(2); From b5a27bd6e8406e8cfd451cfe68a939747e4d0f3b Mon Sep 17 00:00:00 2001 From: Ekhorn Date: Mon, 29 Jun 2026 14:45:00 +0200 Subject: [PATCH 2/2] Add options to resizeWidgetTo jsdocs --- ui/app/manager/test/fixtures/pages/insights.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/app/manager/test/fixtures/pages/insights.ts b/ui/app/manager/test/fixtures/pages/insights.ts index 1eaa8d1624..d35d2ca27f 100644 --- a/ui/app/manager/test/fixtures/pages/insights.ts +++ b/ui/app/manager/test/fixtures/pages/insights.ts @@ -100,6 +100,7 @@ export class InsightsPage implements BasePage { * Resize a widget from its bottom right corner to the specified grid cell coordinates * @param widget The locator of the widget * @param to The grid cell coordinates to resize the widget to + * @param options The resize options (e.g. force will skip dimension assertions) */ async resizeWidgetTo(widget: Locator, [cellsWidth, cellsHeight] = [8, 8], { force } = { force: false }) { const [gridX, gridY] = await this.getWidgetLocation(widget);