From 4fd924317d5a7afe9411921857e49fbfab8fd4e5 Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Sat, 14 Jun 2025 20:26:20 +0200 Subject: [PATCH] chore: improve playwright monaco stability (#21845) --- playwright.config.js | 1 + tests/config-aux.spec.js | 92 ++++++++++++++++++---------------- tests/config-circuit.spec.js | 33 ++++++------ tests/config-loadpoint.spec.js | 33 +++++++----- tests/config-tariffs.spec.js | 19 +++---- tests/config-vehicles.spec.js | 36 ++++++------- tests/utils.ts | 13 ++--- 7 files changed, 117 insertions(+), 110 deletions(-) diff --git a/playwright.config.js b/playwright.config.js index c3148e8f1..10f23637f 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -15,6 +15,7 @@ export default defineConfig({ trace: "on-first-retry", video: "on-first-retry", screenshot: "only-on-failure", + permissions: ["clipboard-write"], }, projects: [ { diff --git a/tests/config-aux.spec.js b/tests/config-aux.spec.js index 944cfe172..d8cf0b88e 100644 --- a/tests/config-aux.spec.js +++ b/tests/config-aux.spec.js @@ -2,7 +2,7 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; import { editorClear, - editorType, + editorPaste, enableExperimental, expectModalHidden, expectModalVisible, @@ -81,16 +81,16 @@ test.describe("aux meter", async () => { await expect(editor).toContainText("power: # current power"); await editorClear(editor); - await editorType(editor, [ - // prettier-ignore - "power:", - " source: const", - "value: 3000 # W", - "Shift+Tab", - "energy:", - " source: const", - "value: 42.0 # kWh", - ]); + await editorPaste( + editor, + page, + `power: + source: const + value: 3000 # W +energy: + source: const + value: 42.0 # kWh` + ); const restResult = modal.getByTestId("test-result"); await expect(restResult).toContainText("Status: unknown"); @@ -122,16 +122,16 @@ test.describe("aux meter", async () => { // update await modal.getByLabel("Title").fill("Small heater"); await editorClear(editor); - await editorType(editor, [ - // prettier-ignore - "power:", - " source: const", - "value: 300 # W", - "Shift+Tab", - "energy:", - " source: const", - "value: 4.2 # kWh", - ]); + await editorPaste( + editor, + page, + `power: + source: const + value: 300 # W +energy: + source: const + value: 4.2 # kWh` + ); await expect(restResult).toContainText("Status: unknown"); await restResult.getByRole("link", { name: "validate" }).click(); await expect(restResult).toContainText("Status: successful"); @@ -175,11 +175,12 @@ test.describe("aux meter", async () => { // yaml syntax error await editorClear(editor); - await editorType(editor, [ - // prettier-ignore - "hello: world", - " foo: bar", - ]); + await editorPaste( + editor, + page, + `hello: world + foo: bar` + ); // no errors await expect(editor.locator(".line-numbers.error")).toHaveCount(0); @@ -194,12 +195,13 @@ test.describe("aux meter", async () => { // invalid field error await editorClear(editor); - await editorType(editor, [ - // prettier-ignore - "apower:", - " source: const", - "value: 3000 # W", - ]); + await editorPaste( + editor, + page, + `apower: + source: const + value: 3000 # W` + ); await expect(restResult).toContainText("Status: unknown"); await restResult.getByRole("link", { name: "validate" }).click(); await expect(restResult).toContainText("Status: failed"); @@ -208,12 +210,13 @@ test.describe("aux meter", async () => { // unknown source error await editorClear(editor); - await editorType(editor, [ - // prettier-ignore - "power:", - " source: unknown", - "value: 3000 # W", - ]); + await editorPaste( + editor, + page, + `power: + source: unknown + value: 3000 # W` + ); await expect(restResult).toContainText("Status: unknown"); await restResult.getByRole("link", { name: "validate" }).click(); await expect(restResult).toContainText("Status: failed"); @@ -222,12 +225,13 @@ test.describe("aux meter", async () => { // missing required field error await editorClear(editor); - await editorType(editor, [ - // prettier-ignore - "energy:", - " source: const", - "value: 300 # kWh", - ]); + await editorPaste( + editor, + page, + `energy: + source: const + value: 300 # kWh` + ); await expect(restResult).toContainText("Status: unknown"); await restResult.getByRole("link", { name: "validate" }).click(); await expect(restResult).toContainText("Status: failed"); diff --git a/tests/config-circuit.spec.js b/tests/config-circuit.spec.js index 4d57588e7..022e5010d 100644 --- a/tests/config-circuit.spec.js +++ b/tests/config-circuit.spec.js @@ -5,7 +5,7 @@ import { expectModalVisible, expectModalHidden, editorClear, - editorType, + editorPaste, } from "./utils"; const CONFIG_YAML = "config-circuit.evcc.yaml"; @@ -86,22 +86,21 @@ test.describe("circuit", async () => { const editor = circuitsModal.getByTestId("yaml-editor"); await editorClear(editor); - await editorType(editor, [ - // prettier-ignore - "- name: main", - " meter: db:1", - "maxcurrent: 16", - "Shift+Tab", - "- name: house", - " title: House", - "maxcurrent: 10", - "parent: main", - "Shift+Tab", - "- name: garage", - " title: Garage", - "maxcurrent: 8", - "parent: main", - ]); + await editorPaste( + editor, + page, + `- name: main + meter: db:1 + maxcurrent: 16 +- name: house + title: House + maxcurrent: 10 + parent: main +- name: garage + title: Garage + maxcurrent: 8 + parent: main` + ); await circuitsModal.getByRole("button", { name: "Save" }).click(); await expectModalHidden(circuitsModal); diff --git a/tests/config-loadpoint.spec.js b/tests/config-loadpoint.spec.js index 3a9b572e8..5357643b3 100644 --- a/tests/config-loadpoint.spec.js +++ b/tests/config-loadpoint.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; -import { expectModalVisible, expectModalHidden, editorClear, editorType } from "./utils"; +import { expectModalVisible, expectModalHidden, editorClear, editorPaste } from "./utils"; const CONFIG_EMPTY = "config-empty.evcc.yaml"; const CONFIG_ONE_LP = "config-one-lp.evcc.yaml"; @@ -436,18 +436,25 @@ test.describe("loadpoint", async () => { await expect(editor).toContainText("status: # charger status [A..F]"); await editorClear(editor, 10); - await editorType(editor, [ - // prettier-ignore - "status:\n source: const\nvalue: 'C'", - "Shift+Tab", - "enabled:\n source: const\nvalue: true", - "Shift+Tab", - "enable:\n source: js\nscript: console.log(enable)", - "Shift+Tab", - "maxcurrent:\n source: js\nscript: console.log(maxcurrent)", - "Shift+Tab", - "power:\n source: const\nvalue: 11000", - ]); + await editorPaste( + editor, + page, + `status: + source: const + value: 'C' +enabled: + source: const + value: true +enable: + source: js + script: console.log(enable) +maxcurrent: + source: js + script: console.log(maxcurrent) +power: + source: const + value: 11000` + ); const restResult = chargerModal.getByTestId("test-result"); await expect(restResult).toContainText("Status: unknown"); diff --git a/tests/config-tariffs.spec.js b/tests/config-tariffs.spec.js index 0256be1be..aaf72b1e0 100644 --- a/tests/config-tariffs.spec.js +++ b/tests/config-tariffs.spec.js @@ -5,7 +5,7 @@ import { expectModalHidden, expectModalVisible, editorClear, - editorType, + editorPaste, } from "./utils"; const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml"; @@ -47,19 +47,20 @@ test.describe("tariffs", async () => { // clear and enter invalid yaml await editorClear(editor); - await editorType(editor, "foo: bar"); + await editorPaste(editor, page, "foo: bar"); await page.getByRole("button", { name: "Save" }).click(); await expect(modal.getByTestId("error")).toContainText("invalid keys: foo"); // clear and enter valid yaml await editorClear(editor); - await editorType(editor, [ - // prettier-ignore - "currency: CHF", - "grid:", - " type: fixed", - "price: 0.123", - ]); + await editorPaste( + editor, + page, + `currency: CHF +grid: + type: fixed + price: 0.123` + ); await page.getByRole("button", { name: "Save" }).click(); await expect(modal.getByTestId("error")).not.toBeVisible(); diff --git a/tests/config-vehicles.spec.js b/tests/config-vehicles.spec.js index bec6ef39d..dc622e77a 100644 --- a/tests/config-vehicles.spec.js +++ b/tests/config-vehicles.spec.js @@ -2,7 +2,7 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; import { editorClear, - editorType, + editorPaste, enableExperimental, expectModalHidden, expectModalVisible, @@ -213,14 +213,15 @@ test.describe("vehicles", async () => { await expect(editor).toContainText("title: green Honda"); await editorClear(editor); - await editorType(editor, [ - // prettier-ignore - "title: blue Honda", - "capacity: 12.3", - "soc:", - " source: const", - "value: 42", - ]); + await editorPaste( + editor, + page, + `title: blue Honda +capacity: 12.3 +soc: + source: const + value: 42` + ); const restResult = modal.getByTestId("test-result"); await expect(restResult).toContainText("Status: unknown"); @@ -247,14 +248,15 @@ test.describe("vehicles", async () => { // update await editorClear(editor); - await editorType(editor, [ - // prettier-ignore - "title: pink Honda", - "capacity: 23.4", - "soc:", - " source: const", - "value: 32", - ]); + await editorPaste( + editor, + page, + `title: pink Honda +capacity: 23.4 +soc: + source: const + value: 32` + ); await expect(restResult).toContainText("Status: unknown"); await restResult.getByRole("link", { name: "validate" }).click(); await expect(restResult).toContainText("Status: successful"); diff --git a/tests/utils.ts b/tests/utils.ts index 95f66e1a0..83d3521da 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -26,15 +26,8 @@ export async function editorClear(editor: Locator, iterations = 6): Promise { - const instructions = ["Shift+Tab"]; +export async function editorPaste(editor: Locator, page: Page, text: string): Promise { await editor.locator(".view-line").nth(0).click(); - const lines = Array.isArray(text) ? text : [text]; - for (const line of lines) { - if (instructions.includes(line)) { - await editor.page().keyboard.press(line); - } else { - await editor.page().keyboard.type(line + "\n"); - } - } + await page.evaluate((text) => navigator.clipboard.writeText(text), text); + await page.keyboard.press("ControlOrMeta+KeyV", { delay: 50 }); }