Skip to content

Commit 7b3719e

Browse files
authored
chore: e2e stability (#22307)
1 parent f64efb8 commit 7b3719e

15 files changed

+147
-44
lines changed

.github/workflows/default.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ jobs:
1818
- uses: actions/setup-go@v5
1919
with:
2020
go-version: "1.24.0"
21+
cache: false # avoid cache thrashing
2122
id: go
2223

2324
- uses: actions/cache@v4
@@ -222,6 +223,7 @@ jobs:
222223

223224
- name: Run tests
224225
run: npx playwright test
226+
timeout-minutes: 20
225227
env:
226228
TZ: Europe/Berlin
227229

tests/auth.spec.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { test, expect } from "@playwright/test";
22
import { start, stop, baseUrl } from "./evcc";
3-
import { expectModalHidden, expectModalVisible } from "./utils";
3+
import {
4+
expectModalHidden,
5+
expectModalVisible,
6+
openTopNavigation,
7+
expectTopNavigationClosed,
8+
} from "./utils";
49
test.use({ baseURL: baseUrl() });
510

611
const BASIC = "basics.evcc.yaml";
@@ -38,8 +43,9 @@ test("login", async ({ page }) => {
3843
await page.goto("/");
3944

4045
// go to config
41-
await page.getByTestId("topnavigation-button").click();
46+
await openTopNavigation(page);
4247
await page.getByRole("link", { name: "Configuration" }).click();
48+
await expectTopNavigationClosed(page);
4349

4450
// login modal
4551
const login = page.getByTestId("login-modal");
@@ -65,8 +71,9 @@ test("http iframe hint", async ({ page }) => {
6571
await page.goto("/");
6672

6773
// go to config
68-
await page.getByTestId("topnavigation-button").click();
74+
await openTopNavigation(page);
6975
await page.getByRole("link", { name: "Configuration" }).click();
76+
await expectTopNavigationClosed(page);
7077

7178
// login modal
7279
const login = page.getByTestId("login-modal");
@@ -116,13 +123,15 @@ test("update password", async ({ page }) => {
116123
).not.toBeVisible();
117124

118125
// logout
119-
await page.getByTestId("topnavigation-button").click();
126+
await openTopNavigation(page);
120127
await page.getByRole("button", { name: "Logout" }).click();
128+
await expectTopNavigationClosed(page);
121129

122130
// login modal
123-
await page.getByTestId("topnavigation-button").click();
131+
await openTopNavigation(page);
124132
await expect(page.getByRole("button", { name: "Logout" })).not.toBeVisible();
125133
await page.getByRole("link", { name: "Configuration" }).click();
134+
await expectTopNavigationClosed(page);
126135
const loginNew = page.getByTestId("login-modal");
127136
await expectModalVisible(loginNew);
128137
await loginNew.getByLabel("Password").fill(newPassword);
@@ -153,8 +162,9 @@ test("disable auth", async ({ page }) => {
153162
await expectModalHidden(modal);
154163

155164
// configuration page without login
156-
await page.getByTestId("topnavigation-button").click();
165+
await openTopNavigation(page);
157166
await page.getByRole("link", { name: "Configuration" }).click();
167+
await expectTopNavigationClosed(page);
158168
await expect(page.getByRole("heading", { name: "Configuration" })).toBeVisible();
159169

160170
await stop();

tests/battery-settings.spec.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { test, expect } from "@playwright/test";
22
import { start, stop, baseUrl } from "./evcc";
3-
import { expectModalVisible, expectModalHidden } from "./utils";
3+
import { expectModalVisible, expectModalHidden, openTopNavigation } from "./utils";
44
test.use({ baseURL: baseUrl() });
55

66
test.beforeAll(async () => {
@@ -13,10 +13,11 @@ test.afterAll(async () => {
1313
test.describe("battery settings", async () => {
1414
test("open modal", async ({ page }) => {
1515
await page.goto("/");
16-
await page.getByTestId("topnavigation-button").click();
16+
await openTopNavigation(page);
1717
await page.getByTestId("topnavigation-battery").click();
1818

1919
const modal = page.getByTestId("battery-settings-modal");
20+
await expectModalVisible(modal);
2021
await expect(modal.getByRole("heading", { name: "Home Battery" })).toBeVisible();
2122
await expect(modal.getByRole("link", { name: "Grid charging 🧪" })).not.toBeVisible();
2223
await expect(modal).toContainText("Battery level: 50%");
@@ -25,20 +26,22 @@ test.describe("battery settings", async () => {
2526

2627
test("battery usage", async ({ page }) => {
2728
await page.goto("/");
28-
await page.getByTestId("topnavigation-button").click();
29+
await openTopNavigation(page);
2930
await page.getByTestId("topnavigation-battery").click();
3031

31-
await page.locator("#batterySettingsPriority").selectOption({ label: "50%" });
32-
await expect(page.locator("label[for=batterySettingsPriorityMiddle] span")).toHaveText("50%");
33-
await expect(page.locator("label[for=batterySettingsPriorityBottom] span")).toHaveText("50%");
34-
await page.locator("#batterySettingsBufferTop").selectOption({ label: "80%" });
35-
await page.locator("#batterySettingsBufferStart").selectOption({ label: "when above 90%." });
36-
await expect(page.locator("label[for=batterySettingsBuffer] span")).toHaveText("80%");
32+
const modal = page.getByTestId("battery-settings-modal");
33+
await expectModalVisible(modal);
34+
await modal.locator("#batterySettingsPriority").selectOption({ label: "50%" });
35+
await expect(modal.locator("label[for=batterySettingsPriorityMiddle] span")).toHaveText("50%");
36+
await expect(modal.locator("label[for=batterySettingsPriorityBottom] span")).toHaveText("50%");
37+
await modal.locator("#batterySettingsBufferTop").selectOption({ label: "80%" });
38+
await modal.locator("#batterySettingsBufferStart").selectOption({ label: "when above 90%." });
39+
await expect(modal.locator("label[for=batterySettingsBuffer] span")).toHaveText("80%");
3740
});
3841

3942
test("grid charging", async ({ page }) => {
4043
await page.goto("/");
41-
await page.getByTestId("topnavigation-button").click();
44+
await openTopNavigation(page);
4245
await page.getByTestId("topnavigation-battery").click();
4346
const modal = page.getByTestId("battery-settings-modal");
4447
await expectModalVisible(modal);

tests/config-grid.spec.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { test, expect } from "@playwright/test";
22
import { start, stop, restart, baseUrl } from "./evcc";
3-
import { startSimulator, stopSimulator, simulatorUrl, simulatorHost } from "./simulator";
3+
import {
4+
startSimulator,
5+
stopSimulator,
6+
simulatorUrl,
7+
simulatorHost,
8+
simulatorApply,
9+
} from "./simulator";
410
import { enableExperimental, expectModalHidden, expectModalVisible } from "./utils";
511

612
const CONFIG_ONE_LP = "config-one-lp.evcc.yaml";
@@ -29,7 +35,7 @@ test.describe("grid meter", async () => {
2935
// setup test data for mock openems api
3036
await page.goto(simulatorUrl());
3137
await page.getByLabel("Grid Power").fill("5000");
32-
await page.getByRole("button", { name: "Apply changes" }).click();
38+
await simulatorApply(page);
3339

3440
await page.goto("/#/config");
3541
await enableExperimental(page, false);

tests/config-loadpoint.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,8 @@ test.describe("charging loadpoint", async () => {
279279
await addDemoCharger(page);
280280
await lpModal.getByLabel("Default vehicle").selectOption(VEHICLE_2);
281281
await lpModal.getByRole("button", { name: "Save" }).click();
282+
await expectModalHidden(lpModal);
283+
await expect(page.getByTestId("loadpoint")).toHaveCount(2);
282284

283285
// restart
284286
await restart();
@@ -320,6 +322,9 @@ test.describe("charging loadpoint", async () => {
320322
await page.goto("/");
321323
await expect(page.getByRole("button", { name: "Off" })).toHaveClass(/active/);
322324
await page.getByRole("button", { name: "Solar", exact: true }).click();
325+
await page.waitForLoadState("networkidle");
326+
await expect(page.getByRole("button", { name: "Solar", exact: true })).toHaveClass(/active/);
327+
323328
await restart();
324329
await page.reload();
325330
await expect(page.getByRole("button", { name: "Solar", exact: true })).toHaveClass(/active/);

tests/config.spec.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { test, expect } from "@playwright/test";
22
import { start, stop, baseUrl } from "./evcc";
3-
import { enableExperimental, expectModalHidden, expectModalVisible } from "./utils";
3+
import {
4+
enableExperimental,
5+
expectModalHidden,
6+
expectModalVisible,
7+
openTopNavigation,
8+
expectTopNavigationClosed,
9+
} from "./utils";
410

511
const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml";
612

@@ -16,8 +22,9 @@ test.afterAll(async () => {
1622
test.describe("basics", async () => {
1723
test("navigation to config", async ({ page }) => {
1824
await page.goto("/");
19-
await page.getByTestId("topnavigation-button").click();
25+
await openTopNavigation(page);
2026
await page.getByRole("link", { name: "Configuration" }).click();
27+
await expectTopNavigationClosed(page);
2128
await expect(page.getByRole("heading", { name: "Configuration" })).toBeVisible();
2229
});
2330
});

tests/demo.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { test, expect } from "@playwright/test";
22
import { start, stop, baseUrl } from "./evcc";
3-
import { expectModalHidden } from "./utils";
3+
import { expectModalHidden, openTopNavigation, expectTopNavigationClosed } from "./utils";
44
import { ChildProcess } from "child_process";
55

66
test.use({ baseURL: baseUrl() });
@@ -35,8 +35,9 @@ test.describe("demo mode", async () => {
3535
});
3636

3737
test("auth is locked", async ({ page }) => {
38-
await page.getByTestId("topnavigation-button").click();
38+
await openTopNavigation(page);
3939
await page.getByRole("link", { name: "Configuration" }).click();
40+
await expectTopNavigationClosed(page);
4041
const loginModal = page.getByTestId("login-modal");
4142
await expect(loginModal).toBeVisible();
4243
await expect(loginModal).toContainText("Login is not supported in demo mode.");

tests/limits.spec.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { test, expect } from "@playwright/test";
22
import { start, stop, baseUrl } from "./evcc";
3-
import { startSimulator, stopSimulator, simulatorUrl, simulatorConfig } from "./simulator";
3+
import {
4+
startSimulator,
5+
stopSimulator,
6+
simulatorUrl,
7+
simulatorConfig,
8+
simulatorApply,
9+
} from "./simulator";
410

511
test.use({ baseURL: baseUrl() });
612

@@ -18,7 +24,7 @@ test.beforeEach(async ({ page }) => {
1824
await page.getByLabel("Grid Power").fill("500");
1925
await page.getByTestId("vehicle0").getByLabel("SoC").fill("20");
2026
await page.getByTestId("loadpoint0").getByText("B (connected)").click();
21-
await page.getByRole("button", { name: "Apply changes" }).click();
27+
await simulatorApply(page);
2228
});
2329

2430
test.afterEach(async () => {
@@ -41,7 +47,7 @@ test.describe("limitSoc", async () => {
4147
test("can be set even if vehicle isn't connected yet", async ({ page }) => {
4248
await page.goto(simulatorUrl());
4349
await page.getByTestId("loadpoint0").getByText("A (disconnected)").click();
44-
await page.getByRole("button", { name: "Apply changes" }).click();
50+
await simulatorApply(page);
4551

4652
await page.goto("/");
4753
await expect(page.getByTestId("vehicle-title")).toContainText("blauer e-Golf");
@@ -52,7 +58,7 @@ test.describe("limitSoc", async () => {
5258

5359
await page.goto(simulatorUrl());
5460
await page.getByTestId("loadpoint0").getByText("B (connected)").click();
55-
await page.getByRole("button", { name: "Apply changes" }).click();
61+
await simulatorApply(page);
5662

5763
await page.goto("/");
5864
await expect(page.getByTestId("limit-soc-value")).toHaveText("50%");
@@ -67,7 +73,7 @@ test.describe("limitSoc", async () => {
6773
// disconnect
6874
await page.goto(simulatorUrl());
6975
await page.getByTestId("loadpoint0").getByText("A (disconnected)").click();
70-
await page.getByRole("button", { name: "Apply changes" }).click();
76+
await simulatorApply(page);
7177

7278
await page.goto("/");
7379
await expect(page.getByTestId("vehicle-status")).toHaveText("Disconnected.");
@@ -76,7 +82,7 @@ test.describe("limitSoc", async () => {
7682
// connect
7783
await page.goto(simulatorUrl());
7884
await page.getByTestId("loadpoint0").getByText("B (connected)").click();
79-
await page.getByRole("button", { name: "Apply changes" }).click();
85+
await simulatorApply(page);
8086

8187
await page.goto("/");
8288
await expect(page.getByTestId("vehicle-status")).toHaveText("Connected.");

tests/logs.spec.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { test, expect } from "@playwright/test";
22
import { start, stop, baseUrl } from "./evcc";
3+
import { openTopNavigation, expectTopNavigationClosed } from "./utils";
34

45
test.use({ baseURL: baseUrl() });
56

@@ -13,11 +14,19 @@ test.afterAll(async () => {
1314
test.describe("opening logs", async () => {
1415
test("via config", async ({ page }) => {
1516
await page.goto("/");
16-
await page.getByTestId("topnavigation-button").click();
17+
await openTopNavigation(page);
1718
await page.getByRole("link", { name: "Configuration" }).click();
19+
await expectTopNavigationClosed(page);
1820
await page.getByRole("link", { name: "Logs" }).click();
1921
await expect(page.getByRole("heading", { name: "Logs", exact: false })).toBeVisible();
2022
});
23+
test("via top navigation", async ({ page }) => {
24+
await page.goto("/");
25+
await openTopNavigation(page);
26+
await page.getByRole("link", { name: "Logs" }).click();
27+
await expectTopNavigationClosed(page);
28+
await expect(page.getByRole("heading", { name: "Logs", exact: false })).toBeVisible();
29+
});
2130
test("via notifications", async ({ page }) => {
2231
await page.goto("/");
2332
await page.evaluate(() => window.app.raise({ message: "Fake Error" }));
@@ -27,8 +36,9 @@ test.describe("opening logs", async () => {
2736
});
2837
test("via need help", async ({ page }) => {
2938
await page.goto("/");
30-
await page.getByTestId("topnavigation-button").click();
39+
await openTopNavigation(page);
3140
await page.getByRole("button", { name: "Need Help?" }).click();
41+
await expectTopNavigationClosed(page);
3242
await page.getByRole("link", { name: "View logs" }).click();
3343
await expect(page.getByRole("heading", { name: "Logs", exact: false })).toBeVisible();
3444
});

tests/modals.spec.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { test, expect } from "@playwright/test";
22
import { start, stop, baseUrl } from "./evcc";
33
import { startSimulator, stopSimulator, simulatorConfig } from "./simulator";
4+
import { openTopNavigation, expectTopNavigationClosed, closeTopNavigation } from "./utils";
45

56
const BASICS_CONFIG = "basics.evcc.yaml";
67

@@ -28,7 +29,7 @@ test.describe("Basics", async () => {
2829
await page.goto(route.path);
2930

3031
await expect(page.getByRole("heading", { name: route.title || title })).toBeVisible();
31-
await page.getByTestId("topnavigation-button").click();
32+
await openTopNavigation(page);
3233
await expect(page.getByRole("button", { name: "User Interface" })).toBeVisible();
3334
await expect(page.getByRole("button", { name: "Home Battery" })).not.toBeVisible();
3435
await expect(page.getByRole("button", { name: "Need help?" })).toBeVisible();
@@ -39,17 +40,19 @@ test.describe("Basics", async () => {
3940
await page.goto("/");
4041

4142
await expect(page.getByRole("heading", { name: "Hello World" })).toBeVisible();
42-
await page.getByTestId("topnavigation-button").click();
43+
await openTopNavigation(page);
4344
await page.getByRole("button", { name: "Need help?" }).click();
45+
await expectTopNavigationClosed(page);
4446

4547
await expect(page.getByRole("heading", { name: "Need help?" })).toBeVisible();
4648
});
4749

4850
test("User Interface", async ({ page }) => {
4951
await page.goto("/");
5052
await expect(page.getByRole("heading", { name: "Hello World" })).toBeVisible();
51-
await page.getByTestId("topnavigation-button").click();
53+
await openTopNavigation(page);
5254
await page.getByRole("button", { name: "User Interface" }).click();
55+
await expectTopNavigationClosed(page);
5356

5457
await expect(page.getByRole("heading", { name: "User Interface" })).toBeVisible();
5558
});
@@ -73,18 +76,20 @@ test.describe("Advanced", async () => {
7376
await page.goto(route.path);
7477

7578
await expect(page.getByRole("heading", { name: route.title || title })).toBeVisible();
76-
await page.getByTestId("topnavigation-button").click();
79+
await openTopNavigation(page);
7780
await expect(page.getByRole("button", { name: "User Interface" })).toBeVisible();
7881
await expect(page.getByRole("button", { name: "Home Battery" })).toBeVisible();
7982
await expect(page.getByRole("button", { name: "Need help?" })).toBeVisible();
83+
await closeTopNavigation(page);
8084
}
8185
});
8286

8387
test("Home Battery from top navigation", async ({ page }) => {
8488
await page.goto("/");
8589
await expect(page.getByRole("heading", { name: title })).toBeVisible();
86-
await page.getByTestId("topnavigation-button").click();
90+
await openTopNavigation(page);
8791
await page.getByRole("button", { name: "Home Battery" }).click();
92+
await expectTopNavigationClosed(page);
8893

8994
await expect(page.getByRole("heading", { name: "Home Battery" })).toBeVisible();
9095
});

0 commit comments

Comments
 (0)