From 143373e1c3eb7da42a21c250667deb8c4761610f Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Sun, 6 Apr 2025 14:57:22 +0200 Subject: [PATCH] chore: e2e stability, modal visibility (#20438) --- .../js/components/Config/LoadpointModal.vue | 2 - assets/js/components/Helper/GenericModal.vue | 8 +- assets/js/views/Config.vue | 1 + playwright.config.js | 2 +- tests/auth.spec.js | 22 ++--- tests/boot.spec.js | 4 +- tests/config-aux.spec.js | 4 +- tests/config-battery.spec.js | 8 +- tests/config-grid.spec.js | 6 +- tests/config-loadpoint.spec.js | 82 ++++++++++--------- tests/config-messaging.spec.js | 8 +- tests/config-mqtt.spec.js | 4 +- tests/config-onboarding.spec.js | 24 +++--- tests/config-pv.spec.js | 10 +-- tests/config-tariffs.spec.js | 6 +- tests/config.spec.js | 8 +- tests/utils.js | 10 +++ 17 files changed, 113 insertions(+), 96 deletions(-) diff --git a/assets/js/components/Config/LoadpointModal.vue b/assets/js/components/Config/LoadpointModal.vue index d5ef5be2a..50211dd75 100644 --- a/assets/js/components/Config/LoadpointModal.vue +++ b/assets/js/components/Config/LoadpointModal.vue @@ -726,7 +726,6 @@ export default { this.updatePhases(); }, async loadConfiguration() { - console.log("loadpoint modal loadConfiguration"); try { const res = await api.get(`config/loadpoints/${this.id}`); this.values = deepClone(res.data.result); @@ -766,7 +765,6 @@ export default { await api.post("config/loadpoints", this.values); this.$emit("updated"); this.$refs.modal.close(); - this.reset(); } catch (e) { console.error(e); const error = e.response?.data?.error; diff --git a/assets/js/components/Helper/GenericModal.vue b/assets/js/components/Helper/GenericModal.vue index fe57da932..73eb672de 100644 --- a/assets/js/components/Helper/GenericModal.vue +++ b/assets/js/components/Helper/GenericModal.vue @@ -6,7 +6,7 @@ :class="classes" tabindex="-1" role="dialog" - aria-hidden="true" + :aria-hidden="isModalVisible ? 'false' : 'true'" :data-bs-backdrop="uncloseable ? 'static' : 'true'" :data-bs-keyboard="uncloseable ? 'false' : 'true'" :data-testid="dataTestid" @@ -88,9 +88,11 @@ export default { }, methods: { handleShow() { + console.log(this.dataTestid, "> show"); this.$emit("open"); }, handleShown() { + console.log(this.dataTestid, "> shown"); this.$emit("opened"); // focus first input or select this.$nextTick(() => { @@ -102,16 +104,20 @@ export default { this.isModalVisible = true; }, handleHide() { + console.log(this.dataTestid, "> hide"); this.$emit("close"); }, handleHidden() { + console.log(this.dataTestid, "> hidden"); this.$emit("closed"); this.isModalVisible = false; }, open() { + console.log(this.dataTestid, "> open", this.$refs.modal._isShown); Modal.getOrCreateInstance(this.$refs.modal).show(); }, close() { + console.log(this.dataTestid, "> close", this.$refs.modal._isShown); Modal.getOrCreateInstance(this.$refs.modal).hide(); }, }, diff --git a/assets/js/views/Config.vue b/assets/js/views/Config.vue index e4ddf58ee..a88270400 100644 --- a/assets/js/views/Config.vue +++ b/assets/js/views/Config.vue @@ -762,6 +762,7 @@ export default { }, newLoadpoint() { this.selectedLoadpointId = undefined; + this.$refs.loadpointModal.reset(); this.$nextTick(() => this.loadpointModal().show()); }, async loadpointChanged() { diff --git a/playwright.config.js b/playwright.config.js index 229a8639c..c3148e8f1 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -7,7 +7,7 @@ export default defineConfig({ testDir: "./tests", forbidOnly: !!process.env.CI, retries: process.env.CI ? 4 : 0, - timeout: 20000, // default 30s + timeout: 30000, // default 30s workers: process.env.CI ? 3 : 4, reporter: "html", use: { diff --git a/tests/auth.spec.js b/tests/auth.spec.js index 561d43ea7..fbd9856d3 100644 --- a/tests/auth.spec.js +++ b/tests/auth.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, baseUrl } from "./evcc"; - +import { expectModalHidden, expectModalVisible } from "./utils"; test.use({ baseURL: baseUrl() }); const BASIC = "basics.evcc.yaml"; @@ -11,7 +11,7 @@ test("set initial password", async ({ page }) => { const modal = page.getByTestId("password-modal"); - await expect(modal).toBeVisible(); + await expectModalVisible(modal); await expect(modal.getByRole("heading", { name: "Set Administrator Password" })).toBeVisible(); // empty password @@ -28,7 +28,7 @@ test("set initial password", async ({ page }) => { await modal.getByLabel("New password").fill("secret"); await modal.getByLabel("Repeat password").fill("secret"); await modal.getByRole("button", { name: "Create Password" }).click(); - await expect(modal).not.toBeVisible(); + await expectModalHidden(modal); await stop(); }); @@ -43,7 +43,7 @@ test("login", async ({ page }) => { // login modal const login = page.getByTestId("login-modal"); - await expect(login).toBeVisible(); + await expectModalVisible(login); await expect(login.getByRole("heading", { name: "Authentication" })).toBeVisible(); // enter wrong password @@ -54,7 +54,7 @@ test("login", async ({ page }) => { // enter correct password await login.getByLabel("Password").fill("secret"); await login.getByRole("button", { name: "Login" }).click(); - await expect(login).not.toBeVisible(); + await expectModalHidden(login); await expect(page.getByRole("heading", { name: "Configuration" })).toBeVisible(); await stop(); @@ -70,7 +70,7 @@ test("http iframe hint", async ({ page }) => { // login modal const login = page.getByTestId("login-modal"); - await expect(login).toBeVisible(); + await expectModalVisible(login); await expect(login.getByRole("heading", { name: "Authentication" })).toBeVisible(); // rewrite api call to simulate lost auth cookie @@ -97,10 +97,10 @@ test("update password", async ({ page }) => { // login modal await page.goto("/#/config"); const loginModal = page.getByTestId("login-modal"); - await expect(loginModal).toBeVisible(); + await expectModalVisible(loginModal); await loginModal.getByLabel("Password").fill(oldPassword); await loginModal.getByRole("button", { name: "Login" }).click(); - await expect(loginModal).not.toBeVisible(); + await expectModalHidden(loginModal); // update password await page.getByTestId("generalconfig-password").getByRole("button", { name: "edit" }).click(); @@ -123,11 +123,11 @@ test("update password", async ({ page }) => { await expect(page.getByRole("button", { name: "Logout" })).not.toBeVisible(); await page.getByRole("link", { name: "Configuration" }).click(); const loginNew = page.getByTestId("login-modal"); - await expect(loginNew).toBeVisible(); + await expectModalVisible(loginNew); await loginNew.getByLabel("Password").fill(newPassword); await loginNew.getByRole("button", { name: "Login" }).click(); await expect(page.getByRole("heading", { name: "Configuration" })).toBeVisible(); - await expect(loginNew).not.toBeVisible(); + await expectModalHidden(loginNew); // revert to old password await page.getByTestId("generalconfig-password").getByRole("button", { name: "edit" }).click(); @@ -148,7 +148,7 @@ test("disable auth", async ({ page }) => { // no password modal const modal = page.getByTestId("password-modal"); - await expect(modal).not.toBeVisible(); + await expectModalHidden(modal); // configuration page without login await page.getByTestId("topnavigation-button").click(); diff --git a/tests/boot.spec.js b/tests/boot.spec.js index 4df26c124..a93dee63f 100644 --- a/tests/boot.spec.js +++ b/tests/boot.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, baseUrl } from "./evcc"; -import { enableExperimental } from "./utils"; +import { enableExperimental, expectModalHidden } from "./utils"; test.use({ baseURL: baseUrl() }); test.beforeAll(async () => { @@ -37,7 +37,7 @@ test.describe("boost", async () => { "Boost active for this charging session." ); await modal.getByLabel("Close").click(); - await expect(modal).not.toBeVisible(); + await expectModalHidden(modal); await expect(page.getByTestId("vehicle-status-batteryboost")).toBeVisible(); }); diff --git a/tests/config-aux.spec.js b/tests/config-aux.spec.js index a67008248..7cac218ce 100644 --- a/tests/config-aux.spec.js +++ b/tests/config-aux.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; -import { enableExperimental } from "./utils"; +import { enableExperimental, expectModalHidden } from "./utils"; const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml"; @@ -29,7 +29,7 @@ test.describe("aux meter", async () => { await meterModal.getByLabel("Manufacturer").selectOption("Demo meter"); await meterModal.getByLabel("Power (W)").fill("1200"); await meterModal.getByRole("button", { name: "Validate & save" }).click(); - await expect(meterModal).not.toBeVisible(); + await expectModalHidden(meterModal); // check await expect(page.getByTestId("aux")).toBeVisible(1); diff --git a/tests/config-battery.spec.js b/tests/config-battery.spec.js index 830425505..74f49fb07 100644 --- a/tests/config-battery.spec.js +++ b/tests/config-battery.spec.js @@ -1,7 +1,7 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; import { startSimulator, stopSimulator, simulatorUrl, simulatorHost } from "./simulator"; -import { enableExperimental } from "./utils"; +import { enableExperimental, expectModalHidden, expectModalVisible } from "./utils"; const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml"; @@ -42,16 +42,16 @@ test.describe("battery meter", async () => { await expect(meterModal.getByTestId("device-tag-soc")).toContainText("75.0%"); await expect(meterModal.getByTestId("device-tag-power")).toContainText("-2.5 kW"); await meterModal.getByRole("button", { name: "Save" }).click(); - await expect(meterModal).not.toBeVisible(); + await expectModalHidden(meterModal); await expect(page.getByTestId("battery")).toBeVisible(1); await expect(page.getByTestId("battery")).toContainText("Battery Basement"); // edit #1 await page.getByTestId("battery").getByRole("button", { name: "edit" }).click(); - await expect(meterModal).toBeVisible(); + await expectModalVisible(meterModal); await meterModal.getByLabel("Battery capacity in kWh").fill("20"); await meterModal.getByRole("button", { name: "Validate & save" }).click(); - await expect(meterModal).not.toBeVisible(); + await expectModalHidden(meterModal); const battery = page.getByTestId("battery"); await expect(battery).toBeVisible(1); diff --git a/tests/config-grid.spec.js b/tests/config-grid.spec.js index 6b420796b..4723a1641 100644 --- a/tests/config-grid.spec.js +++ b/tests/config-grid.spec.js @@ -1,7 +1,7 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; import { startSimulator, stopSimulator, simulatorUrl, simulatorHost } from "./simulator"; -import { enableExperimental } from "./utils"; +import { enableExperimental, expectModalHidden } from "./utils"; const CONFIG_ONE_LP = "config-one-lp.evcc.yaml"; @@ -47,7 +47,7 @@ test.describe("grid meter", async () => { await meterModal.getByRole("link", { name: "validate" }).click(); await expect(meterModal.getByTestId("device-tag-power")).toContainText("5.0 kW"); await meterModal.getByRole("button", { name: "Save" }).click(); - await expect(meterModal).not.toBeVisible(); + await expectModalHidden(meterModal); // restart await restart(CONFIG_ONE_LP); @@ -62,7 +62,7 @@ test.describe("grid meter", async () => { await page.goto("/#/config"); await page.getByTestId("grid").getByRole("button", { name: "edit" }).click(); await meterModal.getByRole("button", { name: "Delete" }).click(); - await expect(meterModal).not.toBeVisible(); + await expectModalHidden(meterModal); await expect(page.getByTestId("grid")).not.toBeVisible(); await expect(page.getByTestId("add-grid")).toBeVisible(); diff --git a/tests/config-loadpoint.spec.js b/tests/config-loadpoint.spec.js index 96e2f66df..fd58cf97c 100644 --- a/tests/config-loadpoint.spec.js +++ b/tests/config-loadpoint.spec.js @@ -1,5 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; +import { expectModalVisible, expectModalHidden } from "./utils"; const CONFIG_EMPTY = "config-empty.evcc.yaml"; const CONFIG_ONE_LP = "config-one-lp.evcc.yaml"; @@ -24,11 +25,11 @@ async function addDemoCharger(page) { await lpModal.getByRole("button", { name: "Add charger" }).click(); const modal = page.getByTestId("charger-modal"); - await expect(modal).toBeVisible(); + await expectModalVisible(modal); await modal.getByLabel("Manufacturer").selectOption("Demo charger"); await modal.getByRole("button", { name: "Save" }).click(); - await expect(modal).not.toBeVisible(); - await expect(lpModal).toBeVisible(); + await expectModalHidden(modal); + await expectModalVisible(lpModal); } async function addDemoMeter(page, power = "0") { @@ -36,28 +37,28 @@ async function addDemoMeter(page, power = "0") { await lpModal.getByRole("button", { name: "Add dedicated charger meter" }).click(); const modal = page.getByTestId("meter-modal"); - await expect(modal).toBeVisible(); + await expectModalVisible(modal); await modal.getByLabel("Manufacturer").selectOption("Demo meter"); await modal.getByLabel("Power").fill(power); await modal.getByRole("button", { name: "Save" }).click(); - await expect(modal).not.toBeVisible(); - await expect(lpModal).toBeVisible(); + await expectModalHidden(modal); + await expectModalVisible(lpModal); } async function addVehicle(page, title) { await page.getByRole("button", { name: "Add vehicle" }).click(); const modal = page.getByTestId("vehicle-modal"); - await expect(modal).toBeVisible(); + await expectModalVisible(modal); await modal.getByLabel("Manufacturer").selectOption("Generic vehicle"); await modal.getByLabel("Title").fill(title); await modal.getByRole("button", { name: "Validate & save" }).click(); - await expect(modal).not.toBeVisible(); + await expectModalHidden(modal); } async function newLoadpoint(page, title) { const lpModal = page.getByTestId("loadpoint-modal"); await page.getByRole("button", { name: "Add charge point" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await lpModal.getByLabel("Title").fill(title); } @@ -105,7 +106,7 @@ test.describe("loadpoint", async () => { // update loadpoint title await page.getByTestId("loadpoint").getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await lpModal.getByLabel("Title").fill("Solar Carport 2"); await lpModal.getByRole("button", { name: "Save" }).click(); await expect(page.getByTestId("loadpoint")).toContainText("Solar Carport 2"); @@ -118,7 +119,7 @@ test.describe("loadpoint", async () => { // update loadpoint power await page.getByTestId("loadpoint").getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await lpModal.getByTestId("chargerPower-22kw").click(); // update charger mode @@ -128,10 +129,10 @@ test.describe("loadpoint", async () => { await lpModal.getByRole("textbox", { name: "Charger" }).click(); await chargerModal.getByLabel("Charge status").selectOption("A"); await chargerModal.getByRole("button", { name: "Save" }).click(); - await expect(chargerModal).not.toBeVisible(); + await expectModalHidden(chargerModal); await lpModal.getByRole("button", { name: "Save" }).click(); - await expect(lpModal).not.toBeVisible(); + await expectModalHidden(lpModal); // restart await restart(CONFIG_EMPTY); @@ -140,14 +141,14 @@ test.describe("loadpoint", async () => { await expect(page.getByTestId("loadpoint")).toContainText("not connected"); await page.getByTestId("loadpoint").getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await expect(lpModal.getByTestId("chargerPower-22kw")).toHaveClass(/active/); await expect(lpModal.getByLabel("Title")).toHaveValue("Solar Carport 2"); await lpModal.getByRole("button", { name: "Close" }).click(); // delete loadpoint await page.getByTestId("loadpoint").getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await lpModal.getByRole("button", { name: "Delete" }).click(); await expect(page.getByTestId("loadpoint")).toHaveCount(0); @@ -172,7 +173,7 @@ test.describe("loadpoint", async () => { await newLoadpoint(page, "Garage"); await addDemoCharger(page); await lpModal.getByRole("button", { name: "Save" }).click(); - await expect(lpModal).not.toBeVisible(); + await expectModalHidden(lpModal); // two loadpoints await expect(page.getByTestId("loadpoint")).toHaveCount(2); @@ -181,11 +182,11 @@ test.describe("loadpoint", async () => { // second loadpoint: increase priority await page.getByTestId("loadpoint").nth(1).getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await expect(lpModal.getByLabel("Priority")).toHaveValue("0 (default)"); await lpModal.getByLabel("Priority").selectOption("1"); await lpModal.getByRole("button", { name: "Save" }).click(); - await expect(lpModal).not.toBeVisible(); + await expectModalHidden(lpModal); // restart await restart(CONFIG_ONE_LP); @@ -193,7 +194,7 @@ test.describe("loadpoint", async () => { // check priorities await page.getByTestId("loadpoint").nth(1).getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await expect(lpModal.getByLabel("Priority")).toHaveValue("1"); }); @@ -214,11 +215,11 @@ test.describe("loadpoint", async () => { await addDemoCharger(page); await expect(lpModal.getByLabel("Default vehicle")).not.toBeVisible(); await lpModal.getByRole("button", { name: "Save" }).click(); - await expect(lpModal).not.toBeVisible(); + await expectModalHidden(lpModal); // edit loadpoint await page.getByTestId("loadpoint").nth(0).getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await expect(lpModal).toContainText("No vehicles are configured."); await lpModal.getByRole("button", { name: "Close" }).click(); @@ -229,10 +230,10 @@ test.describe("loadpoint", async () => { // set vehicle as default for loadpoint 1 await page.getByTestId("loadpoint").nth(0).getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await lpModal.getByLabel("Default vehicle").selectOption(VEHICLE_1); await lpModal.getByRole("button", { name: "Save" }).click(); - await expect(lpModal).not.toBeVisible(); + await expectModalHidden(lpModal); // add second loadpoint await newLoadpoint(page, LP_2); @@ -247,10 +248,10 @@ test.describe("loadpoint", async () => { // check loadpoint default vehicles for (const [index, vehicle] of [VEHICLE_1, VEHICLE_2].entries()) { await page.getByTestId("loadpoint").nth(index).getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await expect(lpModal.locator("#loadpointParamVehicle option:checked")).toHaveText(vehicle); await lpModal.getByRole("button", { name: "Close" }).click(); - await expect(lpModal).not.toBeVisible(); + await expectModalHidden(lpModal); } }); @@ -265,7 +266,7 @@ test.describe("loadpoint", async () => { await meterModal.getByLabel("Manufacturer").selectOption("Demo meter"); await meterModal.getByLabel("Power").fill("-1000"); await meterModal.getByRole("button", { name: "Save" }).click(); - await expect(meterModal).not.toBeVisible(); + await expectModalHidden(meterModal); // add a loadpoint with dummy charger, const lpModal = page.getByTestId("loadpoint-modal"); @@ -273,7 +274,7 @@ test.describe("loadpoint", async () => { await addDemoCharger(page); await lpModal.getByLabel("Default mode").selectOption("---"); await lpModal.getByRole("button", { name: "Save" }).click(); - await expect(lpModal).not.toBeVisible(); + await expectModalHidden(lpModal); await restart(CONFIG_EMPTY); // change on main ui @@ -288,10 +289,10 @@ test.describe("loadpoint", async () => { await page.goto("/#/config"); // open first loadpoint await page.getByTestId("loadpoint").getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await lpModal.getByLabel("Default mode").selectOption("Fast"); await lpModal.getByRole("button", { name: "Save" }).click(); - await expect(lpModal).not.toBeVisible(); + await expectModalHidden(lpModal); await restart(CONFIG_EMPTY); // check loadpoint mode @@ -312,13 +313,13 @@ test.describe("loadpoint", async () => { const lpModal = page.getByTestId("loadpoint-modal"); await lpModal.getByLabel("Default vehicle").selectOption("Porsche"); await lpModal.getByRole("button", { name: "Save" }).click(); - await expect(lpModal).not.toBeVisible(); + await expectModalHidden(lpModal); // delete vehicle await page.getByTestId("vehicle").nth(0).getByRole("button", { name: "edit" }).click(); const vehicleModal = page.getByTestId("vehicle-modal"); await vehicleModal.getByRole("button", { name: "Delete" }).click(); - await expect(vehicleModal).not.toBeVisible(); + await expectModalHidden(vehicleModal); // restart await restart(CONFIG_EMPTY); @@ -326,7 +327,7 @@ test.describe("loadpoint", async () => { // check loadpoint default vehicle await page.getByTestId("loadpoint").getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await expect(lpModal.getByLabel("Default vehicle")).toHaveValue(""); }); @@ -340,15 +341,16 @@ test.describe("loadpoint", async () => { await addDemoCharger(page); const lpModal = page.getByTestId("loadpoint-modal"); await lpModal.getByRole("button", { name: "Save" }).click(); - await expect(lpModal).not.toBeVisible(); + await expectModalHidden(lpModal); // delete charger await page.getByTestId("loadpoint").getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await lpModal.getByRole("textbox", { name: "Charger" }).click(); const chargerModal = page.getByTestId("charger-modal"); + await expectModalVisible(chargerModal); await chargerModal.getByRole("button", { name: "Delete" }).click(); - await expect(chargerModal).not.toBeVisible(); + await expectModalHidden(chargerModal); // restart without saving loadpoint await restart(CONFIG_EMPTY); @@ -356,7 +358,7 @@ test.describe("loadpoint", async () => { // check loadpoint default vehicle await page.getByTestId("loadpoint").getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await expect(lpModal.getByRole("textbox", { name: "Title" })).toHaveValue("Garage"); await expect(lpModal).toContainText("Configuring a charger is required."); }); @@ -372,16 +374,16 @@ test.describe("loadpoint", async () => { await addDemoMeter(page, "11000"); const lpModal = page.getByTestId("loadpoint-modal"); await lpModal.getByRole("button", { name: "Save" }).click(); - await expect(lpModal).not.toBeVisible(); + await expectModalHidden(lpModal); await expect(page.getByTestId("loadpoint")).toContainText("11.0 kW"); // delete charger await page.getByTestId("loadpoint").getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await lpModal.getByRole("textbox", { name: "Meter" }).click(); const meterModal = page.getByTestId("meter-modal"); await meterModal.getByRole("button", { name: "Delete" }).click(); - await expect(meterModal).not.toBeVisible(); + await expectModalHidden(meterModal); // restart without saving loadpoint await restart(CONFIG_EMPTY); @@ -390,7 +392,7 @@ test.describe("loadpoint", async () => { // check loadpoint default vehicle await expect(page.getByTestId("loadpoint")).not.toContainText("11.0 kW"); await page.getByTestId("loadpoint").getByRole("button", { name: "edit" }).click(); - await expect(lpModal).toBeVisible(); + await expectModalVisible(lpModal); await expect(lpModal.getByRole("textbox", { name: "Title" })).toHaveValue("Garage"); await expect( lpModal.getByRole("button", { name: "Add dedicated charger meter" }) diff --git a/tests/config-messaging.spec.js b/tests/config-messaging.spec.js index c0b55f5b6..c110a83d5 100644 --- a/tests/config-messaging.spec.js +++ b/tests/config-messaging.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, baseUrl } from "./evcc"; -import { enableExperimental } from "./utils"; +import { enableExperimental, expectModalHidden, expectModalVisible } from "./utils"; const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml"; @@ -24,7 +24,7 @@ test.describe("messaging", async () => { await page.getByTestId("messaging").getByRole("button", { name: "edit" }).click(); const modal = await page.getByTestId("messaging-modal"); - await expect(modal).toBeVisible(); + await expectModalVisible(modal); await modal.locator(".monaco-editor .view-line").nth(0).click(); for (let i = 0; i < 4; i++) { @@ -33,12 +33,12 @@ test.describe("messaging", async () => { } await page.keyboard.type("# hello world"); await page.getByRole("button", { name: "Save" }).click(); - await expect(modal).not.toBeVisible(); + await expectModalHidden(modal); page.reload(); await page.getByTestId("messaging").getByRole("button", { name: "edit" }).click(); - await expect(modal).toBeVisible(); + await expectModalVisible(modal); await expect(modal).toContainText("# hello world"); }); }); diff --git a/tests/config-mqtt.spec.js b/tests/config-mqtt.spec.js index 47c107b57..886606a56 100644 --- a/tests/config-mqtt.spec.js +++ b/tests/config-mqtt.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; -import { enableExperimental } from "./utils"; +import { enableExperimental, expectModalHidden } from "./utils"; const CONFIG = "config-grid-only.evcc.yaml"; @@ -42,7 +42,7 @@ test.describe("mqtt", async () => { await modal.getByLabel("Password").fill(VALID_PASSWORD); await page.getByRole("button", { name: "Save" }).click(); await expect(modal.getByTestId("error")).not.toBeVisible(); - await expect(modal).not.toBeVisible(); + await expectModalHidden(modal); // restart button appears const restartButton = await page diff --git a/tests/config-onboarding.spec.js b/tests/config-onboarding.spec.js index b8cbf7b41..32a6525ab 100644 --- a/tests/config-onboarding.spec.js +++ b/tests/config-onboarding.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; -import { enableExperimental } from "./utils"; +import { enableExperimental, expectModalHidden, expectModalVisible } from "./utils"; const CONFIG = "config-empty.evcc.yaml"; @@ -21,11 +21,11 @@ test.describe("onboarding", async () => { // set admin password const admin = page.getByTestId("password-modal"); - await expect(admin).toBeVisible(); + await expectModalVisible(admin); await admin.getByLabel("New password").fill(PASSWORD); await admin.getByLabel("Repeat password").fill(PASSWORD); await admin.getByRole("button", { name: "Create Password" }).click(); - await expect(admin).not.toBeVisible(); + await expectModalHidden(admin); // onboarding await expect(page.locator("body")).toContainText("Hello aboard!"); @@ -33,10 +33,10 @@ test.describe("onboarding", async () => { // login const login = page.getByTestId("login-modal"); - await expect(login).toBeVisible(); + await expectModalVisible(login); await login.getByLabel("Password").fill(PASSWORD); await login.getByRole("button", { name: "Login" }).click(); - await expect(login).not.toBeVisible(); + await expectModalHidden(login); // config page await expect(page.getByRole("heading", { name: "Configuration" })).toBeVisible(); @@ -53,30 +53,30 @@ test.describe("onboarding", async () => { await chargerModal.getByLabel("Charge status").selectOption("C"); await chargerModal.getByLabel("Power").fill("3000"); await chargerModal.getByRole("button", { name: "Save" }).click(); - await expect(chargerModal).not.toBeVisible(); - await expect(lpModal).toBeVisible(); + await expectModalHidden(chargerModal); + await expectModalVisible(lpModal); await lpModal.getByRole("button", { name: "Save" }).click(); - await expect(lpModal).not.toBeVisible(); + await expectModalHidden(lpModal); // create grid meter await page.getByRole("button", { name: "Add grid meter" }).click(); const gridModal = page.getByTestId("meter-modal"); - await expect(gridModal).toBeVisible(); + await expectModalVisible(gridModal); await gridModal.getByLabel("Manufacturer").selectOption("Demo meter"); await gridModal.getByLabel("Power").fill("-2000"); await gridModal.getByRole("button", { name: "Save" }).click(); - await expect(gridModal).not.toBeVisible(); + await expectModalHidden(gridModal); // create pv meter await page.getByRole("button", { name: "Add solar or battery" }).click(); const pvModal = page.getByTestId("meter-modal"); - await expect(gridModal).toBeVisible(); + await expectModalVisible(pvModal); await pvModal.getByRole("button", { name: "Add solar meter" }).click(); await pvModal.getByLabel("Title").fill("PV South"); await pvModal.getByLabel("Manufacturer").selectOption("Demo meter"); await pvModal.getByLabel("Power").fill("5000"); await pvModal.getByRole("button", { name: "Save" }).click(); - await expect(pvModal).not.toBeVisible(); + await expectModalHidden(pvModal); // restart const restartButton = await page diff --git a/tests/config-pv.spec.js b/tests/config-pv.spec.js index 27cc1dc1a..3b98f88d7 100644 --- a/tests/config-pv.spec.js +++ b/tests/config-pv.spec.js @@ -1,7 +1,7 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; import { startSimulator, stopSimulator, simulatorHost } from "./simulator"; -import { enableExperimental } from "./utils"; +import { enableExperimental, expectModalHidden, expectModalVisible } from "./utils"; const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml"; @@ -33,16 +33,16 @@ test.describe("pv meter", async () => { await meterModal.getByRole("link", { name: "validate" }).click(); await expect(meterModal.getByTestId("device-tag-power")).toContainText("5.0 kW"); await meterModal.getByRole("button", { name: "Save" }).click(); - await expect(meterModal).not.toBeVisible(); + await expectModalHidden(meterModal); await expect(page.getByTestId("pv")).toBeVisible(1); await expect(page.getByTestId("pv")).toContainText("PV North"); // edit #1 await page.getByTestId("pv").getByRole("button", { name: "edit" }).click(); - await expect(meterModal).toBeVisible(); + await expectModalVisible(meterModal); await meterModal.getByLabel("Power (W)").fill("6000"); await meterModal.getByRole("button", { name: "Validate & save" }).click(); - await expect(meterModal).not.toBeVisible(); + await expectModalHidden(meterModal); const pv = page.getByTestId("pv"); await expect(pv).toBeVisible(1); @@ -83,7 +83,7 @@ test.describe("pv meter", async () => { await meterModal.getByLabel("Manufacturer").selectOption("shelly-1pm"); await meterModal.getByLabel("IP address or hostname").fill(simulatorHost()); await meterModal.getByRole("button", { name: "Validate & save" }).click(); - await expect(meterModal).not.toBeVisible(); + await expectModalHidden(meterModal); await expect(page.getByTestId("pv")).toBeVisible(1); await expect(page.getByTestId("pv")).toContainText("North Roof"); diff --git a/tests/config-tariffs.spec.js b/tests/config-tariffs.spec.js index 263319686..96bc66d7d 100644 --- a/tests/config-tariffs.spec.js +++ b/tests/config-tariffs.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; -import { enableExperimental } from "./utils"; +import { enableExperimental, expectModalHidden, expectModalVisible } from "./utils"; const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml"; const CONFIG_WITH_TARIFFS = "config-with-tariffs.evcc.yaml"; @@ -34,7 +34,7 @@ test.describe("tariffs", async () => { await page.getByTestId("add-tariffs").click(); const modal = await page.getByTestId("tariffs-modal"); - await expect(modal).toBeVisible(); + await expectModalVisible(modal); await page.waitForLoadState("networkidle"); // default content @@ -68,7 +68,7 @@ test.describe("tariffs", async () => { await expect(modal.getByTestId("error")).not.toBeVisible(); // modal closes - await expect(modal).not.toBeVisible(); + await expectModalHidden(modal); // restart button appears const restartButton = await page diff --git a/tests/config.spec.js b/tests/config.spec.js index 229c81ede..29ce22501 100644 --- a/tests/config.spec.js +++ b/tests/config.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, baseUrl } from "./evcc"; -import { enableExperimental } from "./utils"; +import { enableExperimental, expectModalHidden, expectModalVisible } from "./utils"; const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml"; @@ -40,19 +40,19 @@ test.describe("general", async () => { await expect(page.getByTestId("generalconfig-title")).toContainText("Hello World"); await page.getByTestId("generalconfig-title").getByRole("button", { name: "edit" }).click(); const modal = page.getByTestId("title-modal"); - await expect(modal).toBeVisible(); + await expectModalVisible(modal); await modal.getByLabel("Title").fill("Whoops World"); // close modal and ignore entry on cancel await modal.getByRole("button", { name: "Cancel" }).click(); - await expect(modal).not.toBeVisible(); + await expectModalHidden(modal); await expect(page.getByTestId("generalconfig-title")).toContainText("Hello World"); // change and save value await page.getByTestId("generalconfig-title").getByRole("button", { name: "edit" }).click(); await modal.getByLabel("Title").fill("Ahoy World"); await modal.getByRole("button", { name: "Save" }).click(); - await expect(modal).not.toBeVisible(); + await expectModalHidden(modal); await expect(page.getByTestId("generalconfig-title")).toContainText("Ahoy World"); // check changed value on main ui diff --git a/tests/utils.js b/tests/utils.js index da3f4d889..6d200f5b2 100644 --- a/tests/utils.js +++ b/tests/utils.js @@ -7,3 +7,13 @@ export async function enableExperimental(page) { await page.getByRole("button", { name: "Close" }).click(); await expect(page.locator(".modal-backdrop")).not.toBeVisible(); } + +export async function expectModalVisible(modal) { + await expect(modal).toBeVisible(); + await expect(modal).toHaveAttribute("aria-hidden", "false"); +} + +export async function expectModalHidden(modal) { + await expect(modal).not.toBeVisible(); + await expect(modal).toHaveAttribute("aria-hidden", "true"); +}