From 6df31455a9437497f712000d57a07b9c11a2c725 Mon Sep 17 00:00:00 2001 From: ISA Date: Fri, 29 Aug 2025 11:57:25 +0200 Subject: [PATCH] test: systemTest.ts --- .env.development | 2 +- .env.production | 2 +- .woodpecker.yml | 8 +-- CHANGELOG.md | 15 ++++ package-lock.json | 4 +- package.json | 2 +- playwright.config.ts | 36 ++-------- playwright/tests/all.test.ts | 1 + playwright/tests/pages/systemTest.ts | 100 +++++++++++++++++++++++++++ 9 files changed, 131 insertions(+), 39 deletions(-) create mode 100644 playwright/tests/pages/systemTest.ts diff --git a/.env.development b/.env.development index b241e88..aa0e3f1 100644 --- a/.env.development +++ b/.env.development @@ -6,6 +6,6 @@ NEXT_PUBLIC_USE_MOCK_BACKEND_LOOP_START=false NEXT_PUBLIC_EXPORT_STATIC=false NEXT_PUBLIC_USE_CGI=false # App-Versionsnummer -NEXT_PUBLIC_APP_VERSION=1.6.779 +NEXT_PUBLIC_APP_VERSION=1.6.780 NEXT_PUBLIC_CPL_MODE=json # json (Entwicklungsumgebung) oder jsSimulatedProd (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter) diff --git a/.env.production b/.env.production index c218eff..d535e57 100644 --- a/.env.production +++ b/.env.production @@ -5,5 +5,5 @@ NEXT_PUBLIC_CPL_API_PATH=/CPL NEXT_PUBLIC_EXPORT_STATIC=true NEXT_PUBLIC_USE_CGI=true # App-Versionsnummer -NEXT_PUBLIC_APP_VERSION=1.6.779 +NEXT_PUBLIC_APP_VERSION=1.6.780 NEXT_PUBLIC_CPL_MODE=production \ No newline at end of file diff --git a/.woodpecker.yml b/.woodpecker.yml index 7ab1163..df6602d 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -3,12 +3,12 @@ steps: - name: install-dependencies-and-browsers image: node:22 environment: - PLAYWRIGHT_BROWSERS_PATH: "0" # Browser in ./node_modules/playwright/.local-browsers + PLAYWRIGHT_BROWSERS_PATH: "0" CI: "true" E2E_BASE_URL: "http://localhost:3000" LANG: "C.UTF-8" TZ: "Europe/Berlin" - PW_HEADLESS: "1" # erzwingt headless in der Config + PW_HEADLESS: "1" # erzwingt headless über die Config commands: - echo "📦 Installing deps..." - npm ci @@ -18,7 +18,7 @@ steps: - name: run-tests image: node:22 environment: - PLAYWRIGHT_BROWSERS_PATH: "0" # gleicher Pfad wie oben + PLAYWRIGHT_BROWSERS_PATH: "0" CI: "true" E2E_BASE_URL: "http://localhost:3000" LANG: "C.UTF-8" @@ -28,4 +28,4 @@ steps: - echo "🔧 Installing system dependencies for Playwright..." - npx playwright install-deps - echo "🧪 Running Playwright tests (Chromium only)..." - - npx playwright test --project=chromium --headless + - npx playwright test --project=chromium # <-- kein --headless diff --git a/CHANGELOG.md b/CHANGELOG.md index 22e03b9..e68b122 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +## [1.6.780] – 2025-08-29 + +- Headless wird sicher erzwungen (auch wenn lokal anders). + +Der Next.js-Server wird gebaut und via npm start im selben Container gestartet (statt npm run dev). + +Robustere Browser-Flags für Container. + +Artefakte (Trace/Screenshot/Video) nur bei Fehlern, damit der CI schnell bleibt. + +baseURL kommt aus ENV (E2E_BASE_URL) – lokal bleibt’s http://localhost:3000. + +PLAYWRIGHT_BROWSERS_PATH=0 bleibt (Option B). + +--- ## [1.6.779] – 2025-08-29 - fix: start chromium headless diff --git a/package-lock.json b/package-lock.json index a28ce92..f32ca46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cpl-v4", - "version": "1.6.779", + "version": "1.6.780", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cpl-v4", - "version": "1.6.779", + "version": "1.6.780", "dependencies": { "@fontsource/roboto": "^5.1.0", "@headlessui/react": "^2.2.4", diff --git a/package.json b/package.json index 7194a5d..00f16f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cpl-v4", - "version": "1.6.779", + "version": "1.6.780", "private": true, "scripts": { "dev": "next dev", diff --git a/playwright.config.ts b/playwright.config.ts index a26c027..0d06d7b 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -4,62 +4,38 @@ const CI = !!process.env.CI; export default defineConfig({ testDir: "./playwright/tests", - - // Globale Zeitlimits timeout: 90_000, - expect: { timeout: 15_000 }, // etwas großzügiger im CI + expect: { timeout: 15_000 }, - // Setup/Parallelisierung globalSetup: "./playwright/global-setup", fullyParallel: true, forbidOnly: CI, retries: CI ? 2 : 0, workers: CI ? 1 : undefined, - // Reporter & Ausgabepfade reporter: [ ["list"], ["html", { outputFolder: "playwright/report", open: "never" }], ], outputDir: "playwright/test-results", - // Standard-Defaults für alle Tests/Projekte use: { - // Base-URL: im CI per ENV steuerbar baseURL: process.env.E2E_BASE_URL || "http://localhost:3000", - - // Headless im CI (und wenn PW_HEADLESS=1); lokal darfst du headed verwenden - headless: process.env.PW_HEADLESS === "1" || CI, - - // Container-robuste Flags - launchOptions: { - args: ["--no-sandbox", "--disable-dev-shm-usage"], - }, - + headless: process.env.PW_HEADLESS === "1" || CI, // <- Headless-Steuerung hier + launchOptions: { args: ["--no-sandbox", "--disable-dev-shm-usage"] }, viewport: { width: 1920, height: 1080 }, - - // Artefakte – sparsam, aber genug fürs Debugging video: CI ? "retain-on-failure" : "on-first-retry", - screenshot: CI ? "only-on-failure" : "only-on-failure", + screenshot: "only-on-failure", trace: "retain-on-failure", - - // Optional: falls du Test-IDs nutzt testIdAttribute: "data-testid", }, - // Projekte (nur Chromium) - projects: [ - { - name: "chromium", - use: { ...devices["Desktop Chrome"] }, - }, - ], + projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }], - // Webserver: baue & starte Next.js (statt "dev") webServer: { command: "npm run build && npm run start -p 3000", url: process.env.E2E_BASE_URL || "http://localhost:3000", reuseExistingServer: !CI, - timeout: 120_000, // Zeit für Build+Start + timeout: 120_000, }, }); diff --git a/playwright/tests/all.test.ts b/playwright/tests/all.test.ts index 6e40d70..741a149 100644 --- a/playwright/tests/all.test.ts +++ b/playwright/tests/all.test.ts @@ -5,6 +5,7 @@ import { runDigitalInputsTest } from "./pages/digitalInputsTest"; import { runDigitalOutputsTest } from "./pages/digitalOutputsTest"; import { runAnalogInputsTest } from "./pages/analogInputsTest"; import { runMeldungenTest } from "./pages/meldungenTest"; + import { runSettingsPageTest } from "./pages/settingsPageTest"; test("Dashboard, AnalogInputs und SettingsPage", async ({ page }) => { diff --git a/playwright/tests/pages/systemTest.ts b/playwright/tests/pages/systemTest.ts new file mode 100644 index 0000000..4735d2f --- /dev/null +++ b/playwright/tests/pages/systemTest.ts @@ -0,0 +1,100 @@ +// gigityOutputsTest.ts +import type { Locator, Page } from "@playwright/test"; +import { expect } from "@playwright/test"; + +export async function runSystemTest(page: Page) { + await page.goto("/system"); + + // Logo + const logo = page.getByRole("img", { name: "Logo", exact: true }); + await highlightAndExpectVisible(page, logo); + await logo.click(); + await page.waitForTimeout(100); + + // TALAS Logo + const talasLogo = page.getByRole("img", { name: "TALAS Logo" }); + await highlightAndExpectVisible(page, talasLogo); + await talasLogo.click(); + await page.waitForTimeout(100); + + // Meldestation Heading + const meldestation = page.getByRole("heading", { name: "Meldestation" }); + await highlightAndExpectVisible(page, meldestation); + await meldestation.click(); + await page.waitForTimeout(100); + + // CPLV4 Ismail Rastede + const cplv4Text = page.getByText("CPLV4 Ismail Rastede"); + await highlightAndExpectVisible(page, cplv4Text); + await cplv4Text.click(); + await page.waitForTimeout(100); + + // Dark Mode Button sichtbar + const darkModeBtn = page.getByRole("button", { name: "Dark Mode" }); + await highlightAndExpectVisible(page, darkModeBtn); + await expect(darkModeBtn).toBeVisible(); + await page.waitForTimeout(100); + + // Sidebar Links sichtbar + const sidebarLinks = [ + { role: "link", name: "Übersicht" }, + { role: "link", name: "Kabelüberwachung" }, + { role: "link", name: "Meldungseingänge" }, + { role: "link", name: "Schaltausgänge" }, + { role: "link", name: "Messwerteingänge" }, + { role: "link", name: "Berichte" }, + { role: "link", name: "System" }, + { role: "link", name: "Einstellungen" }, + ]; + for (const link of sidebarLinks) { + const locator = page.getByRole(link.role as any, { name: link.name }); + await highlightAndExpectVisible(page, locator); + await expect(locator).toBeVisible(); + await page.waitForTimeout(50); + } + + // Berichte Heading + const berichteHeading = page.getByRole("heading", { name: "Berichte" }); + await highlightAndExpectVisible(page, berichteHeading); + await berichteHeading.click(); + await page.waitForTimeout(100); +} + +//--------------------------------------------------------------------- + +export async function highlightAndExpectVisible( + page: Page, + locator: Locator, + durationMs = 800 +) { + // CSS nur einmal pro Page injizieren + const alreadyInjected = await page.evaluate( + () => (window as any).__pwForceCssInjected === true + ); + + if (!alreadyInjected) { + await page.addStyleTag({ + content: ` + .pw-force-outline { + outline: 3px solid #ff1744 !important; + outline-offset: 2px !important; + box-shadow: 0 0 0 3px rgba(224,0,43,.35) !important; + } + `, + }); + await page.evaluate(() => { + (window as any).__pwForceCssInjected = true; + }); + } + + const els = await locator.elementHandles(); + for (const el of els) { + await el.evaluate((node: unknown, ms: number) => { + const n = node as HTMLElement; + n.classList.add("pw-force-outline"); + window.setTimeout(() => n.classList.remove("pw-force-outline"), ms); + }, durationMs); + } + + await expect(locator).toBeVisible(); +}