From efc4c6ab5f60b2b40e89723b8932ec096bae01e4 Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Wed, 18 Mar 2026 14:45:58 +0100 Subject: [PATCH 1/3] perf(e2e): add Chrome launch flags to reduce CI overhead --- automation/run-e2e/playwright.config.cjs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/automation/run-e2e/playwright.config.cjs b/automation/run-e2e/playwright.config.cjs index cbafb7f825..4f5920c70f 100644 --- a/automation/run-e2e/playwright.config.cjs +++ b/automation/run-e2e/playwright.config.cjs @@ -41,7 +41,23 @@ module.exports = defineConfig({ baseURL: process.env.URL ? process.env.URL : "http://127.0.0.1:8080", /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: "on-first-retry" + trace: "on-first-retry", + + launchOptions: { + args: [ + "--disable-dev-shm-usage", + "--disable-extensions", + "--disable-background-networking", + "--disable-background-timer-throttling", + "--disable-renderer-backgrounding", + "--disable-sync", + "--disable-translate", + "--disable-default-apps", + "--disable-hang-monitor", + "--metrics-recording-only", + "--no-first-run" + ] + } }, /* Configure projects for major browsers */ From adb33dffde412aff5ad7c8ab19c75426c4caa36a Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Thu, 19 Mar 2026 15:48:17 +0100 Subject: [PATCH 2/3] chore: wip playwright tests --- automation/run-e2e/docker/docker-compose.yml | 1 + automation/run-e2e/playwright.config.cjs | 7 +- .../e2e/AccessibilityHelper.spec.js | 16 +- .../accordion-web/e2e/Accordion.spec.js | 4 +- .../badge-button-web/e2e/dataTypes.spec.js | 4 +- .../e2e/differentViews.spec.js | 10 +- .../badge-button-web/e2e/onClick.spec.js | 4 +- .../badge-button-web/e2e/render.spec.js | 4 +- ...badgeButtonPageContent-chromium-darwin.png | Bin 0 -> 1856 bytes .../e2e/BarcodeGenerator.spec.js | 4 +- .../e2e/SelectionControls.spec.js | 4 +- .../color-picker-web/e2e/ColorPicker.spec.js | 14 +- .../column-chart-web/e2e/ColumnChart.spec.js | 6 +- .../combobox-web/e2e/Combobox.spec.js | 4 +- .../e2e/DataGridDateFilter.spec.js | 6 +- .../e2e/DataGridDropDownFilter.spec.js | 6 +- .../DataGridDropDownFilterAssociation.spec.js | 4 +- .../e2e/DataGridNumberFilter.spec.js | 8 +- .../e2e/DataGridTextFilter.spec.js | 8 +- .../datagrid-web/e2e/DataGrid.spec.js | 29 ++- .../e2e/DataGridSelection.spec.js | 8 - .../DataGridFilteringIntegration.spec.js | 4 +- .../filtering/DataGridFilteringMulti.spec.js | 8 +- .../filtering/DataGridFilteringSingle.spec.js | 2 +- .../e2e/DropDownSort.spec.js | 6 +- .../fieldset-web/e2e/Fieldset.spec.js | 4 +- .../gallery-web/e2e/Gallery.spec.js | 6 +- .../gallery-web/e2e/GallerySelection.spec.js | 8 +- .../e2e/HeatMapChart.spec.js | 4 +- .../image-web/e2e/dataTypes.spec.js | 12 +- .../image-web/e2e/onClick.spec.js | 10 +- .../e2e/LanguageSelector.spec.js | 6 +- .../line-chart-web/e2e/LineChart.spec.js | 4 +- .../maps-web/e2e/google.spec.js | 4 +- .../maps-web/e2e/here.spec.js | 12 +- .../maps-web/e2e/mapbox.spec.js | 12 +- .../maps-web/e2e/openstreet.spec.js | 12 +- .../markdown-web/e2e/Markdown.spec.js | 4 +- .../e2e/PieChart.spec.js | 6 +- .../popup-menu-web/e2e/PopupMenu.spec.js | 8 +- .../progress-bar-web/e2e/onClick.spec.js | 4 +- .../e2e/ProgressCircle.spec.js | 6 +- .../range-slider-web/e2e/dataTypes.spec.js | 4 +- .../rating-web/e2e/Rating.spec.js | 4 +- .../rich-text-web/e2e/RichText.spec.js | 26 +-- .../skiplink-web/e2e/SkipLink.spec.js | 28 +-- .../slider-web/e2e/Slider.spec.js | 34 +-- .../switch-web/e2e/Switch.spec.js | 4 +- .../e2e/TimeSeriesChart.spec.js | 6 +- .../timeline-web/e2e/timeline.spec.js | 4 +- .../tooltip-web/e2e/Tooltip.spec.js | 18 +- .../tree-node-web/e2e/TreeNode.spec.js | 8 +- playwright-performance-notes.md | 195 ++++++++++++++++++ 53 files changed, 408 insertions(+), 216 deletions(-) create mode 100644 packages/pluggableWidgets/badge-button-web/e2e/render.spec.js-snapshots/badgeButtonPageContent-chromium-darwin.png create mode 100644 playwright-performance-notes.md diff --git a/automation/run-e2e/docker/docker-compose.yml b/automation/run-e2e/docker/docker-compose.yml index e3fb6aa4fb..32336ca6d6 100644 --- a/automation/run-e2e/docker/docker-compose.yml +++ b/automation/run-e2e/docker/docker-compose.yml @@ -29,6 +29,7 @@ services: # Starts after mxbuild completes; "docker compose up --wait" blocks until healthy. mxruntime: image: mxruntime:${MENDIX_VERSION:?MENDIX_VERSION is required} + shm_size: "2gb" depends_on: mxbuild: condition: service_completed_successfully diff --git a/automation/run-e2e/playwright.config.cjs b/automation/run-e2e/playwright.config.cjs index 4f5920c70f..0c80130f21 100644 --- a/automation/run-e2e/playwright.config.cjs +++ b/automation/run-e2e/playwright.config.cjs @@ -55,8 +55,13 @@ module.exports = defineConfig({ "--disable-default-apps", "--disable-hang-monitor", "--metrics-recording-only", - "--no-first-run" + "--no-first-run", + "--font-render-hinting=none" ] + }, + + contextOptions: { + reducedMotion: "reduce" } }, diff --git a/packages/pluggableWidgets/accessibility-helper-web/e2e/AccessibilityHelper.spec.js b/packages/pluggableWidgets/accessibility-helper-web/e2e/AccessibilityHelper.spec.js index ee408a512c..185b41b6d5 100644 --- a/packages/pluggableWidgets/accessibility-helper-web/e2e/AccessibilityHelper.spec.js +++ b/packages/pluggableWidgets/accessibility-helper-web/e2e/AccessibilityHelper.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("with single target", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("sets attributes when condition is true", async ({ page }) => { @@ -63,7 +63,7 @@ test.describe("with single target", () => { test("sets attributes when condition is true", async ({ page }) => { await page.click(".mx-name-actionButton2"); await page.click(".mx-name-actionButton2"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-radioButtons2 input:first-child"); await page.click(".mx-name-radioButtons2 input:first-child"); await expect(page.locator(".mx-name-text3")).toHaveAttribute("trueCondition", "true"); @@ -72,7 +72,7 @@ test.describe("with single target", () => { test("hides attributes when condition is false", async ({ page }) => { await page.click(".mx-name-actionButton2"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-radioButtons2 input:first-child"); await page.click(".mx-name-radioButtons2 input:first-child"); await expect(page.locator(".mx-name-text3")).not.toHaveAttribute("a11yhelper", "a11yhelper"); @@ -81,7 +81,7 @@ test.describe("with single target", () => { test("updates target attributes when attributes are expression", async ({ page }) => { await page.click(".mx-name-actionButton2"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-radioButtons2 input:first-child"); await page.click(".mx-name-radioButtons2 input:first-child"); await page.locator(".mx-name-textBox1 input").fill("test", { force: true }); @@ -94,7 +94,7 @@ test.describe("with single target", () => { test("updates target attributes using a NF", async ({ page }) => { await page.click(".mx-name-actionButton2"); await page.click(".mx-name-actionButton2"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-radioButtons2 input:first-child"); await page.click(".mx-name-radioButtons2 input:first-child"); await page.click(".mx-name-radioButtons1 input:first-child"); @@ -107,7 +107,7 @@ test.describe("with single target", () => { test("sets target attributes even though target's props changed eg: textinput", async ({ page }) => { await page.click(".mx-name-actionButton2"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-radioButtons2 input:first-child"); await page.click(".mx-name-radioButtons1 input:first-child"); await page.locator(".mx-name-textBox1 input").fill("test", { force: true }); @@ -123,7 +123,7 @@ test.describe("with single target", () => { }) => { await page.click(".mx-name-actionButton2"); await page.click(".mx-name-actionButton2"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-radioButtons2 input:first-child"); await page.click(".mx-name-radioButtons2 input:first-child"); await page.click(".mx-name-radioButtons1 input:first-child"); diff --git a/packages/pluggableWidgets/accordion-web/e2e/Accordion.spec.js b/packages/pluggableWidgets/accordion-web/e2e/Accordion.spec.js index 655458645d..f1ccee31d4 100644 --- a/packages/pluggableWidgets/accordion-web/e2e/Accordion.spec.js +++ b/packages/pluggableWidgets/accordion-web/e2e/Accordion.spec.js @@ -1,9 +1,9 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.describe("Accordion", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("compares with a screenshot baseline and checks if all accordion elements are rendered as expected", async ({ diff --git a/packages/pluggableWidgets/badge-button-web/e2e/dataTypes.spec.js b/packages/pluggableWidgets/badge-button-web/e2e/dataTypes.spec.js index 31530b91bf..fb0fd922e4 100644 --- a/packages/pluggableWidgets/badge-button-web/e2e/dataTypes.spec.js +++ b/packages/pluggableWidgets/badge-button-web/e2e/dataTypes.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("BadgeButton different data types", () => { test.beforeEach(async ({ page }) => { await page.goto("p/dataTypes"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("displays correctly string data", async ({ page }) => { diff --git a/packages/pluggableWidgets/badge-button-web/e2e/differentViews.spec.js b/packages/pluggableWidgets/badge-button-web/e2e/differentViews.spec.js index 07ebd7553a..de7829f0c2 100644 --- a/packages/pluggableWidgets/badge-button-web/e2e/differentViews.spec.js +++ b/packages/pluggableWidgets/badge-button-web/e2e/differentViews.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -11,7 +11,7 @@ test.skip(process.env.MODERN_CLIENT === true, () => { test.describe("listen to grid", () => { test.beforeEach(async ({ page }) => { await page.goto("p/listenToGrid"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("displays correctly when listening a data grid", async ({ page }) => { @@ -26,7 +26,7 @@ test.skip(process.env.MODERN_CLIENT === true, () => { test.describe("listview", () => { test.beforeEach(async ({ page }) => { await page.goto("p/listView"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("displays correctly in a list view", async ({ page }) => { @@ -46,7 +46,7 @@ test.skip(process.env.MODERN_CLIENT === true, () => { test.describe("template grid", () => { test.beforeEach(async ({ page }) => { await page.goto("p/templateGrid"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("displays correctly in a template grid", async ({ page }) => { @@ -67,7 +67,7 @@ test.skip(process.env.MODERN_CLIENT === true, () => { test.describe("tab container", () => { test.beforeEach(async ({ page }) => { await page.goto("p/tabContainer"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("displays correctly in default tab", async ({ page }) => { diff --git a/packages/pluggableWidgets/badge-button-web/e2e/onClick.spec.js b/packages/pluggableWidgets/badge-button-web/e2e/onClick.spec.js index 32e411e6ce..b721651110 100644 --- a/packages/pluggableWidgets/badge-button-web/e2e/onClick.spec.js +++ b/packages/pluggableWidgets/badge-button-web/e2e/onClick.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -9,7 +9,7 @@ test.describe("BadgeButton on click", () => { test.describe("call microflow", () => { test.beforeEach(async ({ page }) => { await page.goto("p/events"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("displays a dialog", async ({ page }) => { diff --git a/packages/pluggableWidgets/badge-button-web/e2e/render.spec.js b/packages/pluggableWidgets/badge-button-web/e2e/render.spec.js index ac3f0f67bf..515b3a9737 100644 --- a/packages/pluggableWidgets/badge-button-web/e2e/render.spec.js +++ b/packages/pluggableWidgets/badge-button-web/e2e/render.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("BadgeButton", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("displays correctly dynamic data", async ({ page }) => { diff --git a/packages/pluggableWidgets/badge-button-web/e2e/render.spec.js-snapshots/badgeButtonPageContent-chromium-darwin.png b/packages/pluggableWidgets/badge-button-web/e2e/render.spec.js-snapshots/badgeButtonPageContent-chromium-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..a6e50f62fd71025d232538fa38d31889c2de5a3f GIT binary patch literal 1856 zcmV-G2fz4>hS`&ui0PJy6T@M1!i(2v8Xs0V+cyKxHH*0pg(9y8EW` zX?d)^Kj{SoUG@Hklin-4J=GgX&%oSTJAfn*V0!(iw|dF$9RVg>l`9m}V4PKzP#$0? z_%Lbci=+<$rj27i7_K zv0@q;Qos{zsSUbskpBS?_leqo4hoV%%mkzqtz(ljBBJDTwj5vP`Df$Z&q^Bdg74{GPC&)k#Rw_rJorjP zkb6ikpleM!KzR~I@bUb;UN_)LdRLYwLBDlQmAi6<``nlEfYh0PdTV#OPp`5({R;+w z14I4?z8i;yjBz-cHivqH{nz=v`u$?=EdA&utUgonyD`8~K3~3qwe%Dw6pk`ts^qnM z>vlPhywS-sq~&#~t-tY za3kAKRAJq~X~x1;0ee;R&S?-W(+@^Rg6?b54$6`+!*C*_GwZU7h5nP^)UZD7rJa_x zK{_)lS|x9@tAa)wgejQMefA4)-A;(kBa0#W8!F%##=_4TKFL+N(o?fpmo+7&=!ftX z1Y^?hg+Wh~>%?+AInA`gUh3o-?q2mXypZuIz2o86VekJQlVDBn)qT|ZVp_1J&T;5f z-?amrbrgv4)|X=hv_+eWb-So|X)D@z)Q;BgT9eM8gaG7WOm=JOY18EIh$K1oFSyHK zJ;nTg%wr!K$ z=e}y*JqvL|$Q(yvh2+P~#RVmw!*%kb=pzB!U*HuD^AlU(uR_0xXt!4VC}x+?!$BYX z##gtSgr)*chd0PH2>m9II6(;km?`$Xa~$RKT$P`~z~-lRAVd(Q;LO8^KnVe;e09fT8=G^x|d6Cu%=x6aOR<$WjLQ+fF6Wa{PoqB zLpLrZ7l9FC>&5SB5QE0CC)+!rr*Fbs%Kh{sTvSM$DM#*SL@Opvc#wP)&wpE{1NdYR ziAKOx&zZ6#7nI|GFBGP_2`tET8GIQoNk8TtRLpHIC0n`T6EqC@?+cmZL)Y?20s1{1 zT~3LoW)ngX9hNzc&nzUNOdfjV!A#q;wAX~h2qhkXfQZbA42;;S&wHEhFV}1)^us1( zO+f_bEDxBcZizD9>f*kvADumr}IWGHn+u8*M}|#HWt1K6?S2(Kj;ZWz;js zdfanr-Vut4}BjmBNb3{r^F?Z&juHSu4B8dNTG;174{B9Hs?e8R*FaZPhYB}Gc zjcG+o*xTStgM#jQIS0gw)EP&6xCD*L0*=^|Y69`6sqB%MPQh|?{1@Yb&f1RFCp2|C z=u*V(YA5Kr7Hxe(7YVABSs%cnJn0$W);+PlVjU7>H54z*trxx}>H&9Gwk?x5`vLND zyef;*u)ek-LjfzGQoM(@BuV0J%EK0P{qEk`luyiWMaVRedjZ<_f>ee^fXdJaP#GEl zDnlbcW#CPiAsW;HwLHs(_8&C#J!H$X;^<|X6Q}_uWO>4}mXZ46GA{jLjfTDg18d9w uqYB|)00030|D2q{djJ3c21!IgR09C4YXx { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("BarcodeGenerator", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("renders barcode generator widget", async ({ page }) => { diff --git a/packages/pluggableWidgets/checkbox-radio-selection-web/e2e/SelectionControls.spec.js b/packages/pluggableWidgets/checkbox-radio-selection-web/e2e/SelectionControls.spec.js index 310453dd54..0887610685 100644 --- a/packages/pluggableWidgets/checkbox-radio-selection-web/e2e/SelectionControls.spec.js +++ b/packages/pluggableWidgets/checkbox-radio-selection-web/e2e/SelectionControls.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("checkbox-radio-selection-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/p/checkboxradioselection"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-actionButton1"); }); diff --git a/packages/pluggableWidgets/color-picker-web/e2e/ColorPicker.spec.js b/packages/pluggableWidgets/color-picker-web/e2e/ColorPicker.spec.js index 7471a92b45..4c24407840 100644 --- a/packages/pluggableWidgets/color-picker-web/e2e/ColorPicker.spec.js +++ b/packages/pluggableWidgets/color-picker-web/e2e/ColorPicker.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -11,7 +11,7 @@ test.describe("color-picker-web", () => { const isFirefox = browserName === "firefox"; await page.goto("/p/modePage"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); if (!isFirefox) { const colorPicker = await page.locator(".mx-name-colorPicker3 .widget-color-picker-inner"); @@ -28,7 +28,7 @@ test.describe("color-picker-web", () => { test("input box", async ({ page }) => { await page.goto("/p/modePage"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-tabPage2"); const inputBox = await page.locator(".mx-name-colorPicker17 input"); await expect(inputBox).toHaveValue("#4caf50"); @@ -36,7 +36,7 @@ test.describe("color-picker-web", () => { test("inline", async ({ page }) => { await page.goto("/p/modePage"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-tabPage3"); const inlinePicker = await page.locator(".mx-name-colorPicker27 .sketch-picker"); await expect(inlinePicker).toBeVisible(); @@ -46,7 +46,7 @@ test.describe("color-picker-web", () => { test.describe("renders a picker of type", () => { test.beforeEach(async ({ page }) => { await page.goto("/p/modePage"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-tabPage3"); }); @@ -109,14 +109,14 @@ test.describe("color-picker-web", () => { test.describe("renders with color format as", () => { test.beforeEach(async ({ page }) => { await page.goto("/p/colorFormat"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.fixme("hex", async ({ page }) => { const hexInput = await page.locator(".mx-name-colorPicker24 input"); await expect(hexInput).toBeVisible(); await page.reload(); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(hexInput).toBeVisible({ timeout: 10000 }); await expect(hexInput).toBeEnabled({ timeout: 10000 }); await expect(hexInput).toBeEditable({ timeout: 10000 }); diff --git a/packages/pluggableWidgets/column-chart-web/e2e/ColumnChart.spec.js b/packages/pluggableWidgets/column-chart-web/e2e/ColumnChart.spec.js index 519940893c..f3a096b0cf 100644 --- a/packages/pluggableWidgets/column-chart-web/e2e/ColumnChart.spec.js +++ b/packages/pluggableWidgets/column-chart-web/e2e/ColumnChart.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,9 +8,9 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("column-chart-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-actionButton1").click(); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.describe("column color", () => { diff --git a/packages/pluggableWidgets/combobox-web/e2e/Combobox.spec.js b/packages/pluggableWidgets/combobox-web/e2e/Combobox.spec.js index 5a3fefae3e..e9b68e0fcd 100644 --- a/packages/pluggableWidgets/combobox-web/e2e/Combobox.spec.js +++ b/packages/pluggableWidgets/combobox-web/e2e/Combobox.spec.js @@ -8,9 +8,9 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("combobox-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/p/combobox"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-actionButton1"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.describe("data source types", () => { diff --git a/packages/pluggableWidgets/datagrid-date-filter-web/e2e/DataGridDateFilter.spec.js b/packages/pluggableWidgets/datagrid-date-filter-web/e2e/DataGridDateFilter.spec.js index c1cf7196d4..846421807a 100644 --- a/packages/pluggableWidgets/datagrid-date-filter-web/e2e/DataGridDateFilter.spec.js +++ b/packages/pluggableWidgets/datagrid-date-filter-web/e2e/DataGridDateFilter.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; import AxeBuilder from "@axe-core/playwright"; test.afterEach("Cleanup session", async ({ page }) => { @@ -9,7 +9,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("datagrid-date-filter-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.describe("visual testing:", () => { @@ -90,7 +90,7 @@ test.describe("datagrid-date-filter-web", () => { test.describe("a11y testing:", () => { test("checks accessibility violations", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const accessibilityScanResults = await new AxeBuilder({ page }) .withTags(["wcag21aa"]) diff --git a/packages/pluggableWidgets/datagrid-dropdown-filter-web/e2e/DataGridDropDownFilter.spec.js b/packages/pluggableWidgets/datagrid-dropdown-filter-web/e2e/DataGridDropDownFilter.spec.js index 563023ae42..e36eb2618a 100644 --- a/packages/pluggableWidgets/datagrid-dropdown-filter-web/e2e/DataGridDropDownFilter.spec.js +++ b/packages/pluggableWidgets/datagrid-dropdown-filter-web/e2e/DataGridDropDownFilter.spec.js @@ -9,7 +9,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("datagrid-dropdown-filter-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.describe("visual testing:", () => { @@ -77,7 +77,7 @@ test.describe("datagrid-dropdown-filter-web", () => { test.describe("with Default value", () => { test.beforeEach(async ({ page }) => { await page.goto("/p/filter_init_condition"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("in single mode, set init condition for boolean", async ({ page }) => { @@ -194,7 +194,7 @@ test.describe("with Default value", () => { test.describe("a11y testing:", () => { test("checks accessibility violations", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const accessibilityScanResults = await new AxeBuilder({ page }) .withTags(["wcag21aa"]) diff --git a/packages/pluggableWidgets/datagrid-dropdown-filter-web/e2e/DataGridDropDownFilterAssociation.spec.js b/packages/pluggableWidgets/datagrid-dropdown-filter-web/e2e/DataGridDropDownFilterAssociation.spec.js index 4ffcbe7119..1b79a0c393 100644 --- a/packages/pluggableWidgets/datagrid-dropdown-filter-web/e2e/DataGridDropDownFilterAssociation.spec.js +++ b/packages/pluggableWidgets/datagrid-dropdown-filter-web/e2e/DataGridDropDownFilterAssociation.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("datagrid-dropdown-filter-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/p/associations-filter"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.describe("single select", () => { diff --git a/packages/pluggableWidgets/datagrid-number-filter-web/e2e/DataGridNumberFilter.spec.js b/packages/pluggableWidgets/datagrid-number-filter-web/e2e/DataGridNumberFilter.spec.js index a44b536a93..0e1fef68a6 100644 --- a/packages/pluggableWidgets/datagrid-number-filter-web/e2e/DataGridNumberFilter.spec.js +++ b/packages/pluggableWidgets/datagrid-number-filter-web/e2e/DataGridNumberFilter.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; import AxeBuilder from "@axe-core/playwright"; test.afterEach("Cleanup session", async ({ page }) => { @@ -9,7 +9,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("datagrid-number-filter-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.describe("visual testing:", () => { @@ -42,7 +42,7 @@ test.describe("datagrid-number-filter-web", () => { const expected = [`First nameYear${NBSP}`, "Delia1987", "Lizzie1987"]; await page.goto("/p/filter_init_condition"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const rows = await page.locator(".mx-name-dataGrid21 [role=row]"); for (let i = 0; i < rows.length; i++) { @@ -57,7 +57,7 @@ test.describe("datagrid-number-filter-web", () => { test.describe("a11y testing:", () => { test("checks accessibility violations", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const accessibilityScanResults = await new AxeBuilder({ page }) .withTags(["wcag21aa"]) diff --git a/packages/pluggableWidgets/datagrid-text-filter-web/e2e/DataGridTextFilter.spec.js b/packages/pluggableWidgets/datagrid-text-filter-web/e2e/DataGridTextFilter.spec.js index 8be396ba9a..ca0a89df80 100644 --- a/packages/pluggableWidgets/datagrid-text-filter-web/e2e/DataGridTextFilter.spec.js +++ b/packages/pluggableWidgets/datagrid-text-filter-web/e2e/DataGridTextFilter.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; import AxeBuilder from "@axe-core/playwright"; test.afterEach("Cleanup session", async ({ page }) => { @@ -9,7 +9,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("datagrid-text-filter-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.describe("visual testing:", () => { @@ -51,7 +51,7 @@ test.describe("datagrid-text-filter-web", () => { const expected = [`First name${NBSP}`, "Betty"]; await page.goto("/p/filter_init_condition"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const rows = await page.locator(".mx-name-dataGrid21 [role=row]"); for (let i = 0; i < rows.length; i++) { @@ -66,7 +66,7 @@ test.describe("datagrid-text-filter-web", () => { test.describe("a11y testing:", () => { test("checks accessibility violations", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const accessibilityScanResults = await new AxeBuilder({ page }) .withTags(["wcag21aa"]) diff --git a/packages/pluggableWidgets/datagrid-web/e2e/DataGrid.spec.js b/packages/pluggableWidgets/datagrid-web/e2e/DataGrid.spec.js index 8fb49539d6..a2cc493030 100644 --- a/packages/pluggableWidgets/datagrid-web/e2e/DataGrid.spec.js +++ b/packages/pluggableWidgets/datagrid-web/e2e/DataGrid.spec.js @@ -1,6 +1,6 @@ -import AxeBuilder from "@axe-core/playwright"; -import { expect, test } from "@playwright/test"; import path from "path"; +import { AxeBuilder } from "@axe-core/playwright"; +import { expect, test } from "@playwright/test"; import * as XLSX from "xlsx"; test.afterEach("Cleanup session", async ({ page }) => { @@ -13,7 +13,6 @@ test.describe("datagrid-web export to Excel", () => { const downloadedFilename = path.join("./e2e/downloads/", "testFilename.xlsx"); await page.goto("/p/export-excel"); - await page.waitForLoadState("networkidle"); await page.locator(".mx-name-dataGridExportExcel").waitFor({ state: "visible", timeout: 15000 }); // Start waiting for download before clicking. const downloadPromise = page.waitForEvent("download"); @@ -47,7 +46,7 @@ test.describe("datagrid-web export to Excel", () => { test.describe("capabilities: sorting", () => { test("applies the default sort order from the data source option", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-datagrid1").waitFor(); await expect(page.locator(".mx-name-datagrid1 .column-header").nth(1)).toHaveText("First Name"); await expect(page.locator(".mx-name-datagrid1 .column-header").nth(1).locator("svg")).toHaveAttribute( "data-icon", @@ -58,7 +57,7 @@ test.describe("capabilities: sorting", () => { test("changes order of data to ASC when clicking sort option", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-datagrid1").waitFor(); await expect(page.locator(".mx-name-datagrid1 .column-header").nth(1)).toHaveText("First Name"); await expect(page.locator(".mx-name-datagrid1 .column-header").nth(1).locator("svg")).toHaveAttribute( "data-icon", @@ -74,7 +73,7 @@ test.describe("capabilities: sorting", () => { test("changes order of data to DESC when clicking sort option", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-datagrid1").waitFor(); await expect(page.locator(".mx-name-datagrid1 .column-header").nth(1)).toHaveText("First Name"); await page.locator(".mx-name-datagrid1 .column-header").nth(1).click(); await page.locator(".mx-name-datagrid1 .column-header").nth(1).click(); @@ -89,7 +88,7 @@ test.describe("capabilities: sorting", () => { test.describe("capabilities: hiding", () => { test("hides a selected column", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-datagrid1").waitFor(); await expect(page.locator(".mx-name-datagrid1 .column-header").first()).toHaveText("Age"); await page.locator(".mx-name-datagrid1 .column-selector-button").click(); await page.locator(".column-selectors > li").first().click(); @@ -98,7 +97,7 @@ test.describe("capabilities: hiding", () => { test("hide column saved on configuration attribute capability", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-datagrid1").waitFor(); // hide first column await page.locator(".mx-name-datagrid5 .column-selector-button").click(); @@ -127,7 +126,7 @@ test.describe("capabilities: hiding", () => { }); test("hide column by default enabled", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-datagrid1").waitFor(); await expect(page.locator(".mx-name-datagrid6 .column-header").first()).toHaveText("First Name"); await page.locator(".mx-name-datagrid6 .column-selector-button").click(); await page.locator(".column-selectors > li").first().click(); @@ -136,7 +135,7 @@ test.describe("capabilities: hiding", () => { test("do not allow to hide last visible column", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-datagrid1").waitFor(); await expect(page.locator(".mx-name-datagrid1 .column-header").first()).toBeVisible(); await page.locator(".mx-name-datagrid1 .column-selector-button").click(); await expect(page.locator(".column-selectors input:checked")).toHaveCount(4); @@ -158,7 +157,7 @@ test.describe("capabilities: hiding", () => { test.describe("capabilities: onClick action", () => { test("check the context", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-datagrid1").waitFor(); await expect(page.locator(".mx-name-datagrid1 .td").first()).toHaveText("12"); await page.locator(".mx-name-datagrid1 .td").first().click(); await expect(page.locator(".mx-name-AgeTextBox input")).toHaveValue("12"); @@ -168,7 +167,7 @@ test.describe("capabilities: onClick action", () => { test.describe("manual column width", () => { test("compares with a screenshot baseline and checks the column width is with correct size", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-datagrid1").waitFor(); await page.locator(".mx-name-datagrid7").scrollIntoViewIfNeeded(); await expect(page.locator(".mx-name-datagrid7")).toHaveScreenshot(`dataGridColumnContent.png`); }); @@ -179,7 +178,7 @@ test.describe("visual testing:", () => { page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-datagrid1").waitFor(); await expect(page.locator(".mx-name-datagrid1")).toBeVisible(); await expect(page.locator(".mx-name-datagrid1")).toHaveScreenshot(`datagrid.png`); }); @@ -188,7 +187,7 @@ test.describe("visual testing:", () => { page }) => { await page.goto("/p/virtual-scrolling"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-dataGrid21").waitFor(); await expect(page.locator(".mx-name-dataGrid21")).toBeVisible(); await page.locator(".mx-name-dataGrid21 .mx-name-textFilter1 .filter-selector-content .btn").click(); await expect(page.locator(".mx-page")).toHaveScreenshot(`datagrid-virtual-scrolling.png`); @@ -198,7 +197,7 @@ test.describe("visual testing:", () => { test.describe("a11y testing:", () => { test("checks accessibility violations", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-datagrid1").waitFor(); const accessibilityScanResults = await new AxeBuilder({ page }) .withTags(["wcag21aa"]) .exclude(".mx-name-navigationTree3") diff --git a/packages/pluggableWidgets/datagrid-web/e2e/DataGridSelection.spec.js b/packages/pluggableWidgets/datagrid-web/e2e/DataGridSelection.spec.js index b5ee1fd855..07b1129053 100644 --- a/packages/pluggableWidgets/datagrid-web/e2e/DataGridSelection.spec.js +++ b/packages/pluggableWidgets/datagrid-web/e2e/DataGridSelection.spec.js @@ -11,7 +11,6 @@ test.describe("datagrid-web selection", async () => { const singleSelectionCheckbox = page.locator(".mx-name-dgSingleSelectionCheckbox"); await page.goto("/p/single-selection"); - await page.waitForLoadState("networkidle"); await expect(singleSelectionCheckbox).toBeVisible(); await singleSelectionCheckbox.locator("input").first().click(); await expect(page).toHaveScreenshot(`datagridSingleSelectionCheckbox.png`); @@ -21,7 +20,6 @@ test.describe("datagrid-web selection", async () => { const singleSelectionRowClick = page.locator(".mx-name-dgSingleSelectionRowClick"); await page.goto("/p/single-selection"); - await page.waitForLoadState("networkidle"); await expect(singleSelectionRowClick).toBeVisible(); await singleSelectionRowClick .locator(".td") @@ -34,7 +32,6 @@ test.describe("datagrid-web selection", async () => { const multiSelectionCheckbox = page.locator(".mx-name-dgMultiSelectionCheckbox"); await page.goto("/p/multi-selection"); - await page.waitForLoadState("networkidle"); await expect(multiSelectionCheckbox).toBeVisible(); await multiSelectionCheckbox.locator("input").first().click(); await multiSelectionCheckbox.locator("input").nth(1).click(); @@ -45,7 +42,6 @@ test.describe("datagrid-web selection", async () => { const multiSelectionRowClick = page.locator(".mx-name-dgMultiSelectionRowClick"); await page.goto("/p/multi-selection"); - await page.waitForLoadState("networkidle"); await expect(multiSelectionRowClick).toBeVisible(); await multiSelectionRowClick.locator(".td").first().click({ force: true }); await multiSelectionRowClick @@ -57,8 +53,6 @@ test.describe("datagrid-web selection", async () => { test("checks single selection accessibility with sr-only text", async ({ page }) => { await page.goto("/p/single-selection"); - await page.waitForLoadState("networkidle"); - const singleSelectionCheckbox = page.locator(".mx-name-dgSingleSelectionCheckbox"); await singleSelectionCheckbox.waitFor(); @@ -88,8 +82,6 @@ test.describe("datagrid-web selection", async () => { test("checks accessibility violations", async ({ page }) => { await page.goto("/p/multi-selection"); - await page.waitForLoadState("networkidle"); - await page.locator(".mx-name-dgMultiSelectionCheckbox").waitFor(); const accessibilityScanResults = await new AxeBuilder({ page }) .withTags(["wcag21aa"]) diff --git a/packages/pluggableWidgets/datagrid-web/e2e/filtering/DataGridFilteringIntegration.spec.js b/packages/pluggableWidgets/datagrid-web/e2e/filtering/DataGridFilteringIntegration.spec.js index 9834a8ae48..f8a789e270 100644 --- a/packages/pluggableWidgets/datagrid-web/e2e/filtering/DataGridFilteringIntegration.spec.js +++ b/packages/pluggableWidgets/datagrid-web/e2e/filtering/DataGridFilteringIntegration.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -13,7 +13,7 @@ test("datagrid-web filtering integration", async ({ page }) => { const rowCount = await rows(); await page.goto("/p/filtering-integration"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-dataGrid21").waitFor(); await expect(rowCount).toHaveCount(51); diff --git a/packages/pluggableWidgets/datagrid-web/e2e/filtering/DataGridFilteringMulti.spec.js b/packages/pluggableWidgets/datagrid-web/e2e/filtering/DataGridFilteringMulti.spec.js index a622b7e272..40d184d554 100644 --- a/packages/pluggableWidgets/datagrid-web/e2e/filtering/DataGridFilteringMulti.spec.js +++ b/packages/pluggableWidgets/datagrid-web/e2e/filtering/DataGridFilteringMulti.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -15,7 +15,7 @@ test.describe("datagrid-web filtering multi select", () => { const enumSelect = () => page.locator(".mx-name-drop_downFilter1[role=combobox]"); const rowCount = await rows(); await page.goto("/p/filtering-multi"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-dataGrid21").waitFor(); await expect(rowCount).toHaveCount(11); await expect(await column(2).first()).toHaveText("Black"); await expect(await column(2).last()).toHaveText("Blue"); @@ -50,7 +50,7 @@ test.describe("datagrid-web filtering multi select", () => { "Environmental scientistPublic librarianMaterials specialist" ]; await page.goto("/p/filtering-multi"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-dataGrid21").waitFor(); await expect(await column(3).first()).toHaveText(expectedColumnText[0]); await roleSelect().click(); await option("Economist").click({ delay: 20 }); @@ -75,7 +75,7 @@ test.describe("datagrid-web filtering multi select", () => { const rowCount = await rows(); await page.goto("/p/filtering-multi"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-dataGrid21").waitFor(); await expect(rowCount).toHaveCount(11); await expect(await column(4).first()).toHaveText("W.R. Berkley Corporation"); await expect(await column(4).last()).toHaveText("PETsMART Inc"); diff --git a/packages/pluggableWidgets/datagrid-web/e2e/filtering/DataGridFilteringSingle.spec.js b/packages/pluggableWidgets/datagrid-web/e2e/filtering/DataGridFilteringSingle.spec.js index b420086f22..46278e1197 100644 --- a/packages/pluggableWidgets/datagrid-web/e2e/filtering/DataGridFilteringSingle.spec.js +++ b/packages/pluggableWidgets/datagrid-web/e2e/filtering/DataGridFilteringSingle.spec.js @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("datagrid-web filtering single select", () => { test.beforeEach(async ({ page }) => { await page.goto("/p/filtering-single"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-name-dataGrid21").waitFor(); }); test("compares with a screenshot baseline and checks if all datagrid and filter elements are rendered as expected", async ({ diff --git a/packages/pluggableWidgets/dropdown-sort-web/e2e/DropDownSort.spec.js b/packages/pluggableWidgets/dropdown-sort-web/e2e/DropDownSort.spec.js index 1028fd1c03..72e53da424 100644 --- a/packages/pluggableWidgets/dropdown-sort-web/e2e/DropDownSort.spec.js +++ b/packages/pluggableWidgets/dropdown-sort-web/e2e/DropDownSort.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; import AxeBuilder from "@axe-core/playwright"; test.afterEach("Cleanup session", async ({ page }) => { @@ -9,7 +9,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("dropdown-sort-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("shows the descending order", async ({ page }) => { @@ -31,7 +31,7 @@ test.describe("dropdown-sort-web", () => { test.describe("a11y testing:", () => { test("checks accessibility violations", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const accessibilityScanResults = await new AxeBuilder({ page }) .withTags(["wcag21aa"]) diff --git a/packages/pluggableWidgets/fieldset-web/e2e/Fieldset.spec.js b/packages/pluggableWidgets/fieldset-web/e2e/Fieldset.spec.js index 1faaeff61e..6d341c169a 100644 --- a/packages/pluggableWidgets/fieldset-web/e2e/Fieldset.spec.js +++ b/packages/pluggableWidgets/fieldset-web/e2e/Fieldset.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("Fieldset", () => { test.beforeEach(async ({ page }) => { await page.goto("/p/configuration-combinations"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("renders content and legend", async ({ page }) => { diff --git a/packages/pluggableWidgets/gallery-web/e2e/Gallery.spec.js b/packages/pluggableWidgets/gallery-web/e2e/Gallery.spec.js index 4298bbdee9..519d228875 100644 --- a/packages/pluggableWidgets/gallery-web/e2e/Gallery.spec.js +++ b/packages/pluggableWidgets/gallery-web/e2e/Gallery.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; import AxeBuilder from "@axe-core/playwright"; test.afterEach("Cleanup session", async ({ page }) => { @@ -9,7 +9,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("gallery-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.describe("capabilities: sorting", () => { @@ -90,7 +90,7 @@ test.describe("gallery-web", () => { test.describe("a11y testing:", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("checks accessibility violations", async ({ page }) => { diff --git a/packages/pluggableWidgets/gallery-web/e2e/GallerySelection.spec.js b/packages/pluggableWidgets/gallery-web/e2e/GallerySelection.spec.js index 3e5f97f97e..074c9d0a90 100644 --- a/packages/pluggableWidgets/gallery-web/e2e/GallerySelection.spec.js +++ b/packages/pluggableWidgets/gallery-web/e2e/GallerySelection.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; import AxeBuilder from "@axe-core/playwright"; test.afterEach("Cleanup session", async ({ page }) => { @@ -10,7 +10,7 @@ test.describe("gallery-web", () => { test.describe("capabilities: selection", () => { test("applies single select", async ({ page }) => { await page.goto("/p/single-selection"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-gallery1")).toBeVisible(); await page.locator(".mx-name-image1").first().click(); await page.locator(".mx-name-feedback1").isHidden(); @@ -19,7 +19,7 @@ test.describe("gallery-web", () => { test("applies multi select", async ({ page }) => { await page.goto("/p/multi-selection"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-gallery1")).toBeVisible(); await page.keyboard.down("Shift"); await page.locator(".mx-name-image1").nth(0).click(); @@ -33,7 +33,7 @@ test.describe("gallery-web", () => { test.describe("a11y testing:", () => { test("checks accessibility violations", async ({ page }) => { await page.goto("/p/multi-selection"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-gallery1").waitFor(); const accessibilityScanResults = await new AxeBuilder({ page }) diff --git a/packages/pluggableWidgets/heatmap-chart-web/e2e/HeatMapChart.spec.js b/packages/pluggableWidgets/heatmap-chart-web/e2e/HeatMapChart.spec.js index 0e47cc6b38..594e6f7bba 100644 --- a/packages/pluggableWidgets/heatmap-chart-web/e2e/HeatMapChart.spec.js +++ b/packages/pluggableWidgets/heatmap-chart-web/e2e/HeatMapChart.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("heatmap-chart-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.describe("heatmap color", { viewport: { height: 720, width: 1280 } }, async () => { diff --git a/packages/pluggableWidgets/image-web/e2e/dataTypes.spec.js b/packages/pluggableWidgets/image-web/e2e/dataTypes.spec.js index 0674fbe55c..674855793b 100644 --- a/packages/pluggableWidgets/image-web/e2e/dataTypes.spec.js +++ b/packages/pluggableWidgets/image-web/e2e/dataTypes.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -13,7 +13,7 @@ test.describe("Image viewer", () => { test("loads an image from a dynamic url", async ({ page }) => { await page.goto("/p/dynamicUrl"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const imageElement = await page.locator(".mx-name-imageRender1 img"); await expect(imageElement).toHaveAttribute("src", dynamicImage); }); @@ -21,7 +21,7 @@ test.describe("Image viewer", () => { // todo: unskip once we figure out why this spec is failing. test.skip("loads an image from a dynamic url association", async ({ page }) => { await page.goto("/p/dynamicUrlAssociation"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const imageElement = await page.locator(".mx-name-image1 img"); await expect(imageElement).toHaveAttribute("src", dynamicImage); }); @@ -29,21 +29,21 @@ test.describe("Image viewer", () => { // todo: unskip once we figure out why this spec is failing. test.skip("loads no image when no image url is specified", async ({ page }) => { await page.goto("/p/emptyUrl"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const imageElement = await page.locator(".mx-name-image1.hidden img"); await expect(imageElement).toHaveAttribute("src", dynamicImageNoUrl); }); test("loads an image from a static image", async ({ page }) => { await page.goto("/p/staticImage"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const imageElement = await page.locator(".mx-name-image1 img"); await expect(imageElement).toHaveAttribute("src", /ImageViewer\$Images\$landscape_2\.png/); }); test("loads an image from a static URL", async ({ page }) => { await page.goto("/p/staticUrl"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const imageElement = await page.locator(".mx-name-image1 img"); await expect(imageElement).toHaveAttribute("src", staticUrl); }); diff --git a/packages/pluggableWidgets/image-web/e2e/onClick.spec.js b/packages/pluggableWidgets/image-web/e2e/onClick.spec.js index 21b467af34..9ada913702 100644 --- a/packages/pluggableWidgets/image-web/e2e/onClick.spec.js +++ b/packages/pluggableWidgets/image-web/e2e/onClick.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -11,7 +11,7 @@ test.describe("Image viewer", () => { test("triggers a Microflow on click", async ({ page }) => { await page.goto("/p/onClickMicroflow"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-image1"); const modalDialog = await page.locator(".modal-dialog"); await expect(modalDialog).toContainText("You clicked this image"); @@ -19,7 +19,7 @@ test.describe("Image viewer", () => { test("triggers a Nanoflow on click", async ({ page }) => { await page.goto("/p/onClickNanoflow"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-image1"); const modalDialog = await page.locator(".modal-dialog"); await expect(modalDialog).toContainText(dynamicImage); @@ -27,7 +27,7 @@ test.describe("Image viewer", () => { test("opens a Page on click", async ({ page }) => { await page.goto("/p/onClickShowPage"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-image1"); const modalDialog = await page.locator(".modal-dialog"); const caption = await modalDialog.locator("#mxui_widget_Window_0_caption"); @@ -36,7 +36,7 @@ test.describe("Image viewer", () => { test("shows full screen image on click", async ({ page }) => { await page.goto("/p/onClickOpenFullScreen"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-name-imageRender1"); const lightboxImage = await page.locator(".mx-image-viewer-lightbox img"); await expect(lightboxImage).toHaveAttribute("src", /ImageViewer\$Images\$landscape_2\.png/); diff --git a/packages/pluggableWidgets/language-selector-web/e2e/LanguageSelector.spec.js b/packages/pluggableWidgets/language-selector-web/e2e/LanguageSelector.spec.js index bd8cc58cde..6aea05211b 100644 --- a/packages/pluggableWidgets/language-selector-web/e2e/LanguageSelector.spec.js +++ b/packages/pluggableWidgets/language-selector-web/e2e/LanguageSelector.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; import AxeBuilder from "@axe-core/playwright"; test.afterEach("Cleanup session", async ({ page }) => { @@ -9,7 +9,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("language-selector-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("checks if all elements are rendered as expected", async ({ page }) => { @@ -33,7 +33,7 @@ test.describe("language-selector-web", () => { test("checks accessibility violations", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const accessibilityScanResults = await new AxeBuilder({ page }) .withTags(["wcag21aa"]) .disableRules([ diff --git a/packages/pluggableWidgets/line-chart-web/e2e/LineChart.spec.js b/packages/pluggableWidgets/line-chart-web/e2e/LineChart.spec.js index 9cda7070b5..1107f059ff 100644 --- a/packages/pluggableWidgets/line-chart-web/e2e/LineChart.spec.js +++ b/packages/pluggableWidgets/line-chart-web/e2e/LineChart.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("line-chart-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.describe("line style", () => { diff --git a/packages/pluggableWidgets/maps-web/e2e/google.spec.js b/packages/pluggableWidgets/maps-web/e2e/google.spec.js index 844b95a31c..96b088cfd9 100644 --- a/packages/pluggableWidgets/maps-web/e2e/google.spec.js +++ b/packages/pluggableWidgets/maps-web/e2e/google.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("Google Maps", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("compares with a screenshot baseline and checks if basemap is correct", async ({ page }) => { diff --git a/packages/pluggableWidgets/maps-web/e2e/here.spec.js b/packages/pluggableWidgets/maps-web/e2e/here.spec.js index 3e6017891d..42806f21c6 100644 --- a/packages/pluggableWidgets/maps-web/e2e/here.spec.js +++ b/packages/pluggableWidgets/maps-web/e2e/here.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -9,7 +9,7 @@ test.describe("Here Maps", () => { test.describe("rendering", () => { test("compares with a screenshot baseline and checks if basemap is correct", async ({ page }) => { await page.goto("p/here-static"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const mapElement = await page.locator(".widget-maps"); await expect(mapElement).toBeVisible(); await expect(mapElement).toHaveScreenshot("hereMaps.png", { maxDiffPixels: 4000 }); @@ -19,7 +19,7 @@ test.describe("Here Maps", () => { test.describe("mixed rendering", () => { test("checks the rendering", async ({ page }) => { await page.goto("p/here"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const mapElement = await page.locator(".widget-leaflet-maps"); await expect(mapElement).toBeVisible(); }); @@ -36,7 +36,7 @@ test.describe("Here Maps", () => { test.describe("static locations", () => { test("checks the rendering", async ({ page }) => { await page.goto("p/here-static"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const mapElement = await page.locator(".widget-leaflet-maps"); await expect(mapElement).toBeVisible(); }); @@ -54,7 +54,7 @@ test.describe("Here Maps", () => { test.describe("datasource locations", () => { test.beforeEach(async ({ page }) => { await page.goto("p/here-datasource"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("checks the rendering", async ({ page }) => { @@ -74,7 +74,7 @@ test.describe("Here Maps", () => { test.describe("on click", () => { test.beforeEach(async ({ page }) => { await page.goto("p/here-onclick"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("should click on first marker", async ({ page }) => { diff --git a/packages/pluggableWidgets/maps-web/e2e/mapbox.spec.js b/packages/pluggableWidgets/maps-web/e2e/mapbox.spec.js index 6fe583b481..d4124f3c15 100644 --- a/packages/pluggableWidgets/maps-web/e2e/mapbox.spec.js +++ b/packages/pluggableWidgets/maps-web/e2e/mapbox.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -9,7 +9,7 @@ test.describe("Mapbox Maps", () => { test.describe("rendering", () => { test.beforeEach(async ({ page }) => { await page.goto("p/mapbox-static"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("compares with a screenshot baseline and checks if basemap is correct", async ({ page }) => { @@ -22,7 +22,7 @@ test.describe("Mapbox Maps", () => { test.describe("mixed rendering", () => { test.beforeEach(async ({ page }) => { await page.goto("p/mapbox"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("checks the rendering", async ({ page }) => { @@ -41,7 +41,7 @@ test.describe("Mapbox Maps", () => { test.describe("static locations", () => { test.beforeEach(async ({ page }) => { await page.goto("p/mapbox-static"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("checks the rendering", async ({ page }) => { @@ -61,7 +61,7 @@ test.describe("Mapbox Maps", () => { test.describe("datasource locations", () => { test.beforeEach(async ({ page }) => { await page.goto("p/mapbox-datasource"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("checks the rendering", async ({ page }) => { @@ -81,7 +81,7 @@ test.describe("Mapbox Maps", () => { test.describe("on click", () => { test.beforeEach(async ({ page }) => { await page.goto("/p/mapbox-onclick"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("should click on first marker", async ({ page }) => { diff --git a/packages/pluggableWidgets/maps-web/e2e/openstreet.spec.js b/packages/pluggableWidgets/maps-web/e2e/openstreet.spec.js index 731075a10b..3ab68bcb46 100644 --- a/packages/pluggableWidgets/maps-web/e2e/openstreet.spec.js +++ b/packages/pluggableWidgets/maps-web/e2e/openstreet.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -9,7 +9,7 @@ test.describe("OpenStreet Maps", () => { test.describe("rendering", () => { test.beforeEach(async ({ page }) => { await page.goto("p/osm-static"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("compares with a screenshot baseline and checks if basemap is correct", async ({ page }) => { @@ -22,7 +22,7 @@ test.describe("OpenStreet Maps", () => { test.describe("mixed rendering", () => { test.beforeEach(async ({ page }) => { await page.goto("p/osm"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("checks the rendering", async ({ page }) => { @@ -41,7 +41,7 @@ test.describe("OpenStreet Maps", () => { test.describe("static locations", () => { test.beforeEach(async ({ page }) => { await page.goto("p/osm-static"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("checks the rendering", async ({ page }) => { @@ -60,7 +60,7 @@ test.describe("OpenStreet Maps", () => { test.describe("datasource locations", () => { test.beforeEach(async ({ page }) => { await page.goto("p/osm-datasource"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("checks the rendering", async ({ page }) => { @@ -79,7 +79,7 @@ test.describe("OpenStreet Maps", () => { test.describe("on click", () => { test.beforeEach(async ({ page }) => { await page.goto("p/osm-onclick"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("should click on first marker", async ({ page }) => { diff --git a/packages/pluggableWidgets/markdown-web/e2e/Markdown.spec.js b/packages/pluggableWidgets/markdown-web/e2e/Markdown.spec.js index aea6cdeb13..e0b356f521 100644 --- a/packages/pluggableWidgets/markdown-web/e2e/Markdown.spec.js +++ b/packages/pluggableWidgets/markdown-web/e2e/Markdown.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("markdown-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.describe("contents", () => { diff --git a/packages/pluggableWidgets/pie-doughnut-chart-web/e2e/PieChart.spec.js b/packages/pluggableWidgets/pie-doughnut-chart-web/e2e/PieChart.spec.js index 903d598a4c..0da54b2542 100644 --- a/packages/pluggableWidgets/pie-doughnut-chart-web/e2e/PieChart.spec.js +++ b/packages/pluggableWidgets/pie-doughnut-chart-web/e2e/PieChart.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -9,7 +9,7 @@ test.describe("pie-doughnut-chart-web", () => { test.describe("pie color", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test( @@ -28,7 +28,7 @@ test.describe("pie-doughnut-chart-web", () => { test.describe("column format", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test( diff --git a/packages/pluggableWidgets/popup-menu-web/e2e/PopupMenu.spec.js b/packages/pluggableWidgets/popup-menu-web/e2e/PopupMenu.spec.js index a4b1778998..6c4aa11305 100644 --- a/packages/pluggableWidgets/popup-menu-web/e2e/PopupMenu.spec.js +++ b/packages/pluggableWidgets/popup-menu-web/e2e/PopupMenu.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -9,7 +9,7 @@ test.describe("Popup-menu-web", () => { test.describe("using basic option", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("compares with a screenshot baseline and checks if popupmenu is rendered in the top left position", async ({ @@ -78,7 +78,7 @@ test.describe("Popup-menu-web", () => { test("shows a new menu list when on hover is triggered", async ({ page }) => { await page.click(".mx-name-actionButton1"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const button25 = page.getByRole("button", { name: "Trigger On Hover" }); await expect(button25).toBeVisible(); await button25.hover(); @@ -102,7 +102,7 @@ test.describe("Popup-menu-web", () => { test.describe("using custom option", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("compares with a screenshot baseline and checks if custom popupmenu is rendered in the top left position", async ({ diff --git a/packages/pluggableWidgets/progress-bar-web/e2e/onClick.spec.js b/packages/pluggableWidgets/progress-bar-web/e2e/onClick.spec.js index be553dbae6..0ab7683fc3 100644 --- a/packages/pluggableWidgets/progress-bar-web/e2e/onClick.spec.js +++ b/packages/pluggableWidgets/progress-bar-web/e2e/onClick.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("Progress Bar on click", () => { test.beforeEach(async ({ page }) => { await page.goto("/p/eventOnClick"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("should call Microflow", async ({ page }) => { diff --git a/packages/pluggableWidgets/progress-circle-web/e2e/ProgressCircle.spec.js b/packages/pluggableWidgets/progress-circle-web/e2e/ProgressCircle.spec.js index 28dd567a5b..4b06f83c3d 100644 --- a/packages/pluggableWidgets/progress-circle-web/e2e/ProgressCircle.spec.js +++ b/packages/pluggableWidgets/progress-circle-web/e2e/ProgressCircle.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,14 +8,14 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("Progress Circle", () => { test("renders with a value", async ({ page }) => { await page.goto("p/Home"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-progressCircleNegative")).toBeVisible(); await expect(page.locator(".mx-name-progressCircleNegative .progressbar-text")).toHaveText("20%"); }); test("updates the progress percentage when the value is changed", async ({ page }) => { await page.goto("p/Playground"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-progressCirclePercentage")).toBeVisible(); await page.locator(".mx-name-textBoxProgress input").fill("67", { force: true }); await page.locator(".mx-name-textBoxMaximumValue").click(); diff --git a/packages/pluggableWidgets/range-slider-web/e2e/dataTypes.spec.js b/packages/pluggableWidgets/range-slider-web/e2e/dataTypes.spec.js index c45f5985e9..9f7266dff7 100644 --- a/packages/pluggableWidgets/range-slider-web/e2e/dataTypes.spec.js +++ b/packages/pluggableWidgets/range-slider-web/e2e/dataTypes.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("Range Slider", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("renders slider with interval context", async ({ page }) => { diff --git a/packages/pluggableWidgets/rating-web/e2e/Rating.spec.js b/packages/pluggableWidgets/rating-web/e2e/Rating.spec.js index a6c75b2506..620303be44 100644 --- a/packages/pluggableWidgets/rating-web/e2e/Rating.spec.js +++ b/packages/pluggableWidgets/rating-web/e2e/Rating.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("Rating", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("compares with a screenshot baseline and checks if all rating elements are rendered as expected", async ({ diff --git a/packages/pluggableWidgets/rich-text-web/e2e/RichText.spec.js b/packages/pluggableWidgets/rich-text-web/e2e/RichText.spec.js index 96ed1c1335..acac1b5f76 100644 --- a/packages/pluggableWidgets/rich-text-web/e2e/RichText.spec.js +++ b/packages/pluggableWidgets/rich-text-web/e2e/RichText.spec.js @@ -10,10 +10,10 @@ test.describe("RichText", () => { page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click("text=Generate Data"); await page.goto("/p/basic"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-richText1").scrollIntoViewIfNeeded(); await expect(page.locator(".mx-name-richText1")).toBeVisible(); await expect(page.locator(".mx-name-richText1")).toHaveScreenshot(`inlineBasicMode.png`, { threshold: 0.4 }); @@ -23,7 +23,7 @@ test.describe("RichText", () => { page }) => { await page.goto("/p/basic"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-richText4")).toBeVisible(); await expect(page.locator(".mx-name-richText4")).toHaveScreenshot(`toolbarBasicMode.png`, { threshold: 0.4 }); }); @@ -32,7 +32,7 @@ test.describe("RichText", () => { page }) => { await page.goto("/p/advanced"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-richText1")).toBeVisible(); await expect(page.locator(".mx-name-richText1")).toHaveScreenshot(`bottomToolbarAdvancedMode.png`, { threshold: 0.4 @@ -48,7 +48,7 @@ test.describe("RichText", () => { page }) => { await page.goto("/p/advanced"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-richText4").scrollIntoViewIfNeeded(); await expect(page.locator(".mx-name-richText4")).toBeVisible(); await expect(page.locator(".mx-name-richText4")).toHaveScreenshot(`toolbarAdvancedMode.png`, { @@ -65,7 +65,7 @@ test.describe("RichText", () => { page }) => { await page.goto("/p/custom"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-richText1")).toBeVisible(); await expect(page.locator(".mx-name-richText1")).toHaveScreenshot(`inlineCustomMode.png`, { threshold: 0.4 }); }); @@ -74,7 +74,7 @@ test.describe("RichText", () => { page }) => { await page.goto("/p/custom"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-richText2")).toBeVisible(); await expect(page.locator(".mx-name-richText2")).toHaveScreenshot(`toolbarCustomMode.png`, { threshold: 0.4 }); }); @@ -83,7 +83,7 @@ test.describe("RichText", () => { page }) => { await page.goto("/p/custom"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-richText3").scrollIntoViewIfNeeded(); await expect(page.locator(".mx-name-richText3")).toBeVisible(); await expect(page.locator(".mx-name-richText3")).toHaveScreenshot(`customModeAllOptions.png`, { @@ -95,7 +95,7 @@ test.describe("RichText", () => { page }) => { await page.goto("/p/custom"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-richText4").scrollIntoViewIfNeeded(); await expect(page.locator(".mx-name-richText4")).toBeVisible(); await expect(page.locator(".mx-name-richText4")).toHaveScreenshot(`customModeNoneOptions.png`, { @@ -105,7 +105,7 @@ test.describe("RichText", () => { test("compares with a screenshot baseline and checks for readonly mode basic styling", async ({ page }) => { await page.goto("/p/read-only"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-richText3").scrollIntoViewIfNeeded(); await expect(page.locator(".mx-name-richText3")).toBeVisible(); await expect(page.locator(".mx-name-richText3")).toHaveScreenshot(`readOnlyModeBasic.png`, { @@ -115,7 +115,7 @@ test.describe("RichText", () => { test("compares with a screenshot baseline and checks for readonly mode bordered styling", async ({ page }) => { await page.goto("/p/read-only"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-richText2").scrollIntoViewIfNeeded(); await expect(page.locator(".mx-name-richText2")).toBeVisible(); await expect(page.locator(".mx-name-richText2")).toHaveScreenshot(`readOnlyModeBordered.png`, { @@ -125,7 +125,7 @@ test.describe("RichText", () => { test("compares with a screenshot baseline and checks for readonly mode read panel styling", async ({ page }) => { await page.goto("/p/read-only"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-richText6").scrollIntoViewIfNeeded(); await expect(page.locator(".mx-name-richText6")).toBeVisible(); await expect(page.locator(".mx-name-richText6")).toHaveScreenshot(`readOnlyModeReadPanel.png`, { @@ -135,7 +135,7 @@ test.describe("RichText", () => { test("compares with a screenshot for rich text inside modal popup layout", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.click(".mx-navbar-item [title='Demo']"); await expect(page.locator(".mx-name-customWidget1").first()).toHaveScreenshot(`richTextModal.png`); diff --git a/packages/pluggableWidgets/skiplink-web/e2e/SkipLink.spec.js b/packages/pluggableWidgets/skiplink-web/e2e/SkipLink.spec.js index e36eee53ad..4b689924e1 100644 --- a/packages/pluggableWidgets/skiplink-web/e2e/SkipLink.spec.js +++ b/packages/pluggableWidgets/skiplink-web/e2e/SkipLink.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -7,7 +7,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.describe("SkipLink:", function () { @@ -15,7 +15,7 @@ test.describe("SkipLink:", function () { // Skip link should be in the DOM but not visible const skipLink = page.locator(".widget-skip-link").first(); await expect(skipLink).toBeAttached(); - + // Check initial styling (hidden) const transform = await skipLink.evaluate(el => getComputedStyle(el).transform); expect(transform).toContain("matrix(1, 0, 0, 1, 0, -48)"); @@ -25,24 +25,24 @@ test.describe("SkipLink:", function () { // Tab to focus the skip link (should be first focusable element) const skipLink = page.locator(".widget-skip-link").first(); await page.keyboard.press("Tab"); - + await expect(skipLink).toBeFocused(); await page.waitForTimeout(1000); // Check that it becomes visible when focused const transform = await skipLink.evaluate(el => getComputedStyle(el).transform); - expect(transform).toContain("matrix(1, 0, 0, 1, 0, 0)") + expect(transform).toContain("matrix(1, 0, 0, 1, 0, 0)"); }); test("skip link navigates to main content when activated", async ({ page }) => { // Tab to focus the skip link await page.keyboard.press("Tab"); - + const skipLink = page.locator(".widget-skip-link").first(); await expect(skipLink).toBeFocused(); - + // Activate the skip link await page.keyboard.press("Enter"); - + // Check that main content is now focused const mainContent = page.locator("main"); await expect(mainContent).toBeFocused(); @@ -50,13 +50,13 @@ test.describe("SkipLink:", function () { test("skip link has correct attributes and text", async ({ page }) => { const skipLink = page.locator(".widget-skip-link").first(); - + // Check default text await expect(skipLink).toHaveText("Skip to main content"); - + // Check href attribute await expect(skipLink).toHaveAttribute("href", "#"); - + // Check CSS class await expect(skipLink).toHaveClass("widget-skip-link mx-name-skipLink1"); }); @@ -64,11 +64,11 @@ test.describe("SkipLink:", function () { test("visual comparison", async ({ page }) => { // Tab to make skip link visible for screenshot await page.keyboard.press("Tab"); - + const skipLink = page.locator(".widget-skip-link").first(); await expect(skipLink).toBeFocused(); - + // Visual comparison of focused skip link await expect(skipLink).toHaveScreenshot("skiplink-focused.png"); }); -}); \ No newline at end of file +}); diff --git a/packages/pluggableWidgets/slider-web/e2e/Slider.spec.js b/packages/pluggableWidgets/slider-web/e2e/Slider.spec.js index ba943545fc..991cdffe61 100644 --- a/packages/pluggableWidgets/slider-web/e2e/Slider.spec.js +++ b/packages/pluggableWidgets/slider-web/e2e/Slider.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("Slider", () => { test("renders with context", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const minimumValue = await page.inputValue(".mx-name-textBoxMinimumValue input"); const minimumValueText = await page @@ -33,7 +33,7 @@ test.describe("Slider", () => { test("renders without context", async ({ page }) => { await page.goto("/p/no-context"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); const sliderClass = await page.locator(".mx-name-sliderNoContext .rc-slider").getAttribute("class"); await expect(sliderClass).toContain("rc-slider-disabled"); @@ -62,7 +62,7 @@ test.describe("Slider", () => { test.skip(process.env.MODERN_CLIENT === true, () => { test("listens to a grid", async ({ page }) => { await page.goto("/p/listen-to-grid"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-slider .rc-slider-handle")).toHaveCSS("cursor", /not-allowed/); @@ -76,7 +76,7 @@ test.describe("Slider", () => { test("triggers a microflow after slide", async ({ page }) => { await page.goto("/p/after-slide"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page .locator(".mx-name-sliderMicroflow .rc-slider-handle") @@ -86,7 +86,7 @@ test.describe("Slider", () => { test("triggers a nanoflow after slide", async ({ page }) => { await page.goto("/p/after-slide"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page .locator(".mx-name-sliderNanoflow .rc-slider-handle") @@ -98,7 +98,7 @@ test.describe("Slider", () => { test("renders with a range that goes from negative to positive", async ({ page }) => { await page.goto("/p/negative-and-positive-range"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-slider")).toBeVisible(); await expect(page.locator(".mx-name-textValue")).toHaveText(/5/); @@ -112,7 +112,7 @@ test.describe("Slider", () => { test("renders multiple markers", async ({ page }) => { await page.goto("/p/multiple-markers"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-slider")).toBeVisible(); const mark0 = await page.locator(".mx-name-slider .rc-slider-mark > span").nth(0); @@ -132,7 +132,7 @@ test.describe("Slider", () => { test("updates decimal values", async ({ page }) => { await page.goto("/p/decimal-values"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-slider")).toBeVisible(); await expect(page.locator(".mx-name-textValue")).toHaveText(/5.5/); @@ -146,7 +146,7 @@ test.describe("Slider", () => { test("updates long values", async ({ page }) => { await page.goto("/p/long-values"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-slider")).toBeVisible(); await expect(page.locator(".mx-name-textValue")).toHaveText(/60000/); @@ -160,7 +160,7 @@ test.describe("Slider", () => { test("slides with step size", async ({ page }) => { await page.goto("/p/long-values"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-slider")).toBeVisible(); await page.locator(".mx-name-slider .rc-slider-handle").click({ position: { x: 58, y: 0 }, force: true }); @@ -174,7 +174,7 @@ test.describe("Slider", () => { test("snaps to intermediate markers", async ({ page }) => { await page.goto("/p/long-values"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-slider")).toBeVisible(); await expect(page.locator(".mx-name-slider .rc-slider-mark > span").nth(1)).toHaveText("140000"); @@ -186,7 +186,7 @@ test.describe("Slider", () => { test("slides without using intermediate marker as base", async ({ page }) => { await page.goto("/p/long-values"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-slider")).toBeVisible(); await page.locator(".mx-name-slider .rc-slider-dot:nth-child(2)").click({ force: true }); @@ -201,7 +201,7 @@ test.describe("Slider", () => { test.describe("Style", () => { test.beforeEach(async ({ page }) => { await page.goto("/p/different-slider-styles"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("compares with a screenshot baseline and checks if all slider elements are rendered as expected", async ({ @@ -217,7 +217,7 @@ test.describe("Slider", () => { test.describe("Tooltip", () => { test("doesn't render when there's no title", async ({ page }) => { await page.goto("/p/no-tooltip-title"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-slider")).toBeVisible(); await expect(page.locator(".mx-name-slider .rc-slider-handle .rc-slider-tooltip")).toHaveCount(0); @@ -225,7 +225,7 @@ test.describe("Slider", () => { test("renders a static title", async ({ page }) => { await page.goto("/p/tooltip-with-static-title"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".mx-name-slider")).toBeVisible(); await expect(page.locator(".rc-slider-tooltip-container")).toHaveText("Slider"); @@ -239,7 +239,7 @@ test.describe("Slider", () => { test("renders the slider's value", async ({ page }) => { await page.goto("/p/tooltip-with-slider-value"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await expect(page.locator(".rc-slider-tooltip-container")).toHaveText("10.00"); diff --git a/packages/pluggableWidgets/switch-web/e2e/Switch.spec.js b/packages/pluggableWidgets/switch-web/e2e/Switch.spec.js index 5213788fa9..de1dafbe3c 100644 --- a/packages/pluggableWidgets/switch-web/e2e/Switch.spec.js +++ b/packages/pluggableWidgets/switch-web/e2e/Switch.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("Switch", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("changes color when checked", async ({ page }) => { diff --git a/packages/pluggableWidgets/time-series-chart-web/e2e/TimeSeriesChart.spec.js b/packages/pluggableWidgets/time-series-chart-web/e2e/TimeSeriesChart.spec.js index da828f1251..9e7bdf1e61 100644 --- a/packages/pluggableWidgets/time-series-chart-web/e2e/TimeSeriesChart.spec.js +++ b/packages/pluggableWidgets/time-series-chart-web/e2e/TimeSeriesChart.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("time-series-chart-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("renders time series chart with multiple series and compares with a screenshot baseline", async ({ page }) => { @@ -55,7 +55,7 @@ test.describe("time-series-chart-web", () => { test.describe("y axis range", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("renders time series chart with non negative values and compares with a screenshot baseline", async ({ diff --git a/packages/pluggableWidgets/timeline-web/e2e/timeline.spec.js b/packages/pluggableWidgets/timeline-web/e2e/timeline.spec.js index 6626f7a1f5..90fa318077 100644 --- a/packages/pluggableWidgets/timeline-web/e2e/timeline.spec.js +++ b/packages/pluggableWidgets/timeline-web/e2e/timeline.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("timeline-web", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test.describe("option: basic", () => { diff --git a/packages/pluggableWidgets/tooltip-web/e2e/Tooltip.spec.js b/packages/pluggableWidgets/tooltip-web/e2e/Tooltip.spec.js index eff1b19038..9fb7bb4671 100644 --- a/packages/pluggableWidgets/tooltip-web/e2e/Tooltip.spec.js +++ b/packages/pluggableWidgets/tooltip-web/e2e/Tooltip.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; test.afterEach("Cleanup session", async ({ page }) => { // Because the test isolation that will open a new session for every test executed, and that exceeds Mendix's license limit of 5 sessions, so we need to force logout after each test. @@ -8,7 +8,7 @@ test.afterEach("Cleanup session", async ({ page }) => { test.describe("render method: text", () => { test.beforeEach(async ({ page }) => { await page.goto("/p/arrow"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("compares with a screenshot baseline and checks if tooltip arrow start is rendered as expected", async ({ @@ -34,14 +34,14 @@ test.describe("render method: text", () => { test("compares with a screenshot baseline and checks if tooltip position is rendered on top", async ({ page }) => { await page.goto("/p/position"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-actionButtonTop").focus(); await expect(page.locator(".mx-scrollcontainer-center")).toHaveScreenshot(`tooltipPositionTop.png`, 0.1); }); test("compares with a screenshot baseline and checks if tooltip position is rendered on left", async ({ page }) => { await page.goto("/p/position"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-actionButtonLeft").focus(); await expect(page.locator(".mx-scrollcontainer-center")).toHaveScreenshot(`tooltipPositionLeft.png`, 0.1); }); @@ -50,7 +50,7 @@ test.describe("render method: text", () => { page }) => { await page.goto("/p/position"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-actionButtonRight").focus(); await expect(page.locator(".mx-scrollcontainer-center")).toHaveScreenshot(`tooltipPositionRight.png`, 0.1); }); @@ -59,7 +59,7 @@ test.describe("render method: text", () => { page }) => { await page.goto("/p/position"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-actionButtonBottom").focus(); await expect(page.locator(".mx-scrollcontainer-center")).toHaveScreenshot(`tooltipPositionBottom.png`, 0.1); }); @@ -68,7 +68,7 @@ test.describe("render method: text", () => { page }) => { await page.goto("/p/position"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-actionButtonFlip").focus(); await expect(page.locator(".mx-scrollcontainer-center")).toHaveScreenshot(`tooltipPositionFlipped.png`, 0.1); }); @@ -76,7 +76,7 @@ test.describe("render method: text", () => { test.describe("render method: custom", () => { test.beforeEach(async ({ page }) => { await page.goto("/p/arrow"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("verifies tooltip shown custom content and compares with a screenshot baseline", async ({ page }) => { @@ -87,7 +87,7 @@ test.describe("render method: text", () => { test("verifies if tooltip is opened on click", async ({ page }) => { await page.goto("/p/click"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-actionButtonClick").click(); await expect(page.locator(".mx-scrollcontainer-center")).toHaveScreenshot(`tooltipClick.png`, 0.1); }); diff --git a/packages/pluggableWidgets/tree-node-web/e2e/TreeNode.spec.js b/packages/pluggableWidgets/tree-node-web/e2e/TreeNode.spec.js index 78601e0128..04a216ff61 100644 --- a/packages/pluggableWidgets/tree-node-web/e2e/TreeNode.spec.js +++ b/packages/pluggableWidgets/tree-node-web/e2e/TreeNode.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test"; +import { expect, test } from "@playwright/test"; import AxeBuilder from "@axe-core/playwright"; test.afterEach("Cleanup session", async ({ page }) => { @@ -13,7 +13,7 @@ function getTreeNodeHeaders(page) { test.describe("capabilities: expand", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("expands a node", async ({ page }) => { @@ -33,7 +33,7 @@ test.describe("capabilities: expand", () => { test.describe("capabilities: collapse", () => { test.beforeEach(async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); }); test("collapses a node", async ({ page }) => { @@ -59,7 +59,7 @@ test.describe("capabilities: collapse", () => { test.describe("a11y testing:", () => { test("checks accessibility violations", async ({ page }) => { await page.goto("/"); - await page.waitForLoadState("networkidle"); + await page.locator(".mx-page").waitFor(); await page.locator(".mx-name-treeNode1").waitFor(); const accessibilityScanResults = await new AxeBuilder({ page }) diff --git a/playwright-performance-notes.md b/playwright-performance-notes.md new file mode 100644 index 0000000000..23ebd3e0ee --- /dev/null +++ b/playwright-performance-notes.md @@ -0,0 +1,195 @@ +# Playwright Performance & Memory Improvement Ideas + +## Setup Overview + +- **Config:** `automation/run-e2e/playwright.config.cjs` — shared by all 40 widget packages +- **Browser:** Chromium only, `channel: "chromium"`, `devices["Desktop Chrome"]` +- **Parallelism:** `fullyParallel: true`, 4 workers in CI +- **Scale:** 59 `.spec.js` files, ~4,900 lines of E2E code +- **Trace:** `on-first-retry` (already good) +- **Pattern:** Every test navigates + `waitForLoadState("networkidle")`, then logs out via `window.mx.session.logout()` + +--- + +## Ideas + +### 1. Add Chrome Launch Flags + +The config uses no custom `launchOptions`. These flags can significantly reduce overhead: + +```js +// playwright.config.cjs +use: { + launchOptions: { + args: [ + "--disable-dev-shm-usage", // CRITICAL in Docker — prevents OOM crashes + "--disable-extensions", + "--disable-background-networking", + "--disable-background-timer-throttling", + "--disable-renderer-backgrounding", + "--disable-sync", + "--disable-translate", + "--disable-default-apps", + "--disable-hang-monitor", + "--metrics-recording-only", + "--no-first-run", + ] + } +} +``` + +`--disable-dev-shm-usage` is especially impactful in the Docker CI runtime since `/dev/shm` is typically limited to 64MB, causing Chrome to crash under load. + +--- + +### 2. Replace `waitForLoadState("networkidle")` with Targeted Waits + +**Every single test file** uses this pattern: + +```js +await page.waitForLoadState("networkidle"); +``` + +`networkidle` waits until there are no network requests for 500ms — it's the slowest load state and is fragile when apps have long-polling or periodic requests. Replace with element-based waits: + +```js +// Instead of: +await page.waitForLoadState("networkidle"); + +// Prefer waiting for the widget's root element to appear: +await page.locator(".mx-datagrid").waitFor({ state: "visible" }); +// or +await page.locator(".widget-badge").waitFor(); +``` + +This could cut seconds off each test's setup time. + +--- + +### 3. Disable Animations for Visual Tests + +Visual snapshot tests are sensitive to CSS animations causing flakiness and slower execution: + +```js +use: { + contextOptions: { + reducedMotion: "reduce", + } +} +``` + +Or via launch args: + +```js +args: ["--animation-duration-scale=0"] +``` + +--- + +### 4. Block Unnecessary Network Requests + +In tests that don't need analytics or external resources, intercept and abort them: + +```js +// In a shared beforeEach or fixture +await page.route("**/*.{png,jpg,woff2}", route => route.abort()); +await page.route(/google-analytics|analytics\.js/, route => route.abort()); +``` + +--- + +### 5. Share Browser Context for Read-Only Tests + +Currently every test gets a fresh Mendix session, limited to 5 by license. For tests that only read data (no mutations), a shared `browserContext` in `beforeAll/afterAll` avoids the per-test session creation cost: + +```js +test.describe("read-only group", () => { + let sharedPage; + test.beforeAll(async ({ browser }) => { + sharedPage = await browser.newPage(); + await sharedPage.goto("/p/datagrid"); + await sharedPage.waitForLoadState("networkidle"); + }); + test.afterAll(async () => { + await sharedPage.evaluate(() => window.mx.session.logout()); + await sharedPage.close(); + }); + // tests use sharedPage instead of page fixture +}); +``` + +--- + +### 6. Introduce a Shared Playwright Fixture for Mendix Navigation + +Currently each test manually navigates and waits. A custom fixture would centralize this and allow easy optimization in one place: + +```js +// automation/run-e2e/fixtures.js +const { test: base } = require("@playwright/test"); + +exports.test = base.extend({ + mendixPage: async ({ page }, use) => { + // centralized wait strategy — easy to tune globally + await page.goto("/"); + await page.waitForSelector(".mx-app", { state: "visible" }); + await use(page); + await page.evaluate(() => window.mx.session.logout()); + } +}); +``` + +This would let you swap out the wait strategy across all 59 test files from one location. + +--- + +### 7. Increase CI Workers (Within Session Limit) + +Currently `workers: CI ? 4 : undefined`. The Mendix 5-session license limit means you're spending more time on session management than needed. With the `afterEach` logout pattern, sessions are released immediately — so increasing to 5 workers is safe: + +```js +workers: process.env.CI ? 5 : undefined, +``` + +--- + +### 8. Docker: Mount Adequate `/dev/shm` + +In `docker-utils.mjs`, if Chrome is run inside Docker, ensure the container has enough shared memory: + +```yaml +# docker-compose +shm_size: '2gb' +``` + +Or pass `--shm-size=2g` to the Docker run command. Without this, Chrome silently OOMs on heavy pages. + +--- + +### 9. Use `--font-render-hinting=none` for Consistent Screenshots + +Visual tests produce different snapshots across machines/OS due to font rendering differences. This flag makes rendering more deterministic: + +```js +args: ["--font-render-hinting=none"] +``` + +This reduces the number of `chromium-linux.png` vs `chromium-darwin.png` divergences and can reduce snapshot file sizes. + +--- + +## Summary Table + +| Idea | Impact | Effort | Priority | +|---|---|---|---| +| `--disable-dev-shm-usage` in Docker | High (prevents crashes) | Low | Critical | +| Replace `networkidle` with element waits | High (speed) | Medium | High | +| Add Chrome launch flags | Medium (memory/speed) | Low | High | +| Increase CI workers to 5 | Low-Medium (throughput) | Low | Medium | +| Disable animations | Medium (stability) | Low | Medium | +| Block unnecessary network requests | Low-Medium | Medium | Medium | +| Shared context for read-only tests | Medium (speed) | Medium | Medium | +| Shared Mendix fixture | Low (maintainability) | Medium | Low | +| `--font-render-hinting=none` | Low (consistency) | Low | Low | + +The highest-leverage changes are (1) adding `--disable-dev-shm-usage` for the Docker CI environment and (2) replacing `waitForLoadState("networkidle")` with targeted element waits, since those two patterns are in every test run. From ffb932cae03014ac4872472a7d66a33472a7c40f Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Fri, 3 Apr 2026 15:13:23 +0200 Subject: [PATCH 3/3] chore: remove outdated Playwright performance notes --- playwright-performance-notes.md | 195 -------------------------------- 1 file changed, 195 deletions(-) delete mode 100644 playwright-performance-notes.md diff --git a/playwright-performance-notes.md b/playwright-performance-notes.md deleted file mode 100644 index 23ebd3e0ee..0000000000 --- a/playwright-performance-notes.md +++ /dev/null @@ -1,195 +0,0 @@ -# Playwright Performance & Memory Improvement Ideas - -## Setup Overview - -- **Config:** `automation/run-e2e/playwright.config.cjs` — shared by all 40 widget packages -- **Browser:** Chromium only, `channel: "chromium"`, `devices["Desktop Chrome"]` -- **Parallelism:** `fullyParallel: true`, 4 workers in CI -- **Scale:** 59 `.spec.js` files, ~4,900 lines of E2E code -- **Trace:** `on-first-retry` (already good) -- **Pattern:** Every test navigates + `waitForLoadState("networkidle")`, then logs out via `window.mx.session.logout()` - ---- - -## Ideas - -### 1. Add Chrome Launch Flags - -The config uses no custom `launchOptions`. These flags can significantly reduce overhead: - -```js -// playwright.config.cjs -use: { - launchOptions: { - args: [ - "--disable-dev-shm-usage", // CRITICAL in Docker — prevents OOM crashes - "--disable-extensions", - "--disable-background-networking", - "--disable-background-timer-throttling", - "--disable-renderer-backgrounding", - "--disable-sync", - "--disable-translate", - "--disable-default-apps", - "--disable-hang-monitor", - "--metrics-recording-only", - "--no-first-run", - ] - } -} -``` - -`--disable-dev-shm-usage` is especially impactful in the Docker CI runtime since `/dev/shm` is typically limited to 64MB, causing Chrome to crash under load. - ---- - -### 2. Replace `waitForLoadState("networkidle")` with Targeted Waits - -**Every single test file** uses this pattern: - -```js -await page.waitForLoadState("networkidle"); -``` - -`networkidle` waits until there are no network requests for 500ms — it's the slowest load state and is fragile when apps have long-polling or periodic requests. Replace with element-based waits: - -```js -// Instead of: -await page.waitForLoadState("networkidle"); - -// Prefer waiting for the widget's root element to appear: -await page.locator(".mx-datagrid").waitFor({ state: "visible" }); -// or -await page.locator(".widget-badge").waitFor(); -``` - -This could cut seconds off each test's setup time. - ---- - -### 3. Disable Animations for Visual Tests - -Visual snapshot tests are sensitive to CSS animations causing flakiness and slower execution: - -```js -use: { - contextOptions: { - reducedMotion: "reduce", - } -} -``` - -Or via launch args: - -```js -args: ["--animation-duration-scale=0"] -``` - ---- - -### 4. Block Unnecessary Network Requests - -In tests that don't need analytics or external resources, intercept and abort them: - -```js -// In a shared beforeEach or fixture -await page.route("**/*.{png,jpg,woff2}", route => route.abort()); -await page.route(/google-analytics|analytics\.js/, route => route.abort()); -``` - ---- - -### 5. Share Browser Context for Read-Only Tests - -Currently every test gets a fresh Mendix session, limited to 5 by license. For tests that only read data (no mutations), a shared `browserContext` in `beforeAll/afterAll` avoids the per-test session creation cost: - -```js -test.describe("read-only group", () => { - let sharedPage; - test.beforeAll(async ({ browser }) => { - sharedPage = await browser.newPage(); - await sharedPage.goto("/p/datagrid"); - await sharedPage.waitForLoadState("networkidle"); - }); - test.afterAll(async () => { - await sharedPage.evaluate(() => window.mx.session.logout()); - await sharedPage.close(); - }); - // tests use sharedPage instead of page fixture -}); -``` - ---- - -### 6. Introduce a Shared Playwright Fixture for Mendix Navigation - -Currently each test manually navigates and waits. A custom fixture would centralize this and allow easy optimization in one place: - -```js -// automation/run-e2e/fixtures.js -const { test: base } = require("@playwright/test"); - -exports.test = base.extend({ - mendixPage: async ({ page }, use) => { - // centralized wait strategy — easy to tune globally - await page.goto("/"); - await page.waitForSelector(".mx-app", { state: "visible" }); - await use(page); - await page.evaluate(() => window.mx.session.logout()); - } -}); -``` - -This would let you swap out the wait strategy across all 59 test files from one location. - ---- - -### 7. Increase CI Workers (Within Session Limit) - -Currently `workers: CI ? 4 : undefined`. The Mendix 5-session license limit means you're spending more time on session management than needed. With the `afterEach` logout pattern, sessions are released immediately — so increasing to 5 workers is safe: - -```js -workers: process.env.CI ? 5 : undefined, -``` - ---- - -### 8. Docker: Mount Adequate `/dev/shm` - -In `docker-utils.mjs`, if Chrome is run inside Docker, ensure the container has enough shared memory: - -```yaml -# docker-compose -shm_size: '2gb' -``` - -Or pass `--shm-size=2g` to the Docker run command. Without this, Chrome silently OOMs on heavy pages. - ---- - -### 9. Use `--font-render-hinting=none` for Consistent Screenshots - -Visual tests produce different snapshots across machines/OS due to font rendering differences. This flag makes rendering more deterministic: - -```js -args: ["--font-render-hinting=none"] -``` - -This reduces the number of `chromium-linux.png` vs `chromium-darwin.png` divergences and can reduce snapshot file sizes. - ---- - -## Summary Table - -| Idea | Impact | Effort | Priority | -|---|---|---|---| -| `--disable-dev-shm-usage` in Docker | High (prevents crashes) | Low | Critical | -| Replace `networkidle` with element waits | High (speed) | Medium | High | -| Add Chrome launch flags | Medium (memory/speed) | Low | High | -| Increase CI workers to 5 | Low-Medium (throughput) | Low | Medium | -| Disable animations | Medium (stability) | Low | Medium | -| Block unnecessary network requests | Low-Medium | Medium | Medium | -| Shared context for read-only tests | Medium (speed) | Medium | Medium | -| Shared Mendix fixture | Low (maintainability) | Medium | Low | -| `--font-render-hinting=none` | Low (consistency) | Low | Low | - -The highest-leverage changes are (1) adding `--disable-dev-shm-usage` for the Docker CI environment and (2) replacing `waitForLoadState("networkidle")` with targeted element waits, since those two patterns are in every test run.