diff --git a/.env.development b/.env.development index 16fabf2..f363ee8 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.776 +NEXT_PUBLIC_APP_VERSION=1.6.777 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 c82fabc..68a83da 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.776 +NEXT_PUBLIC_APP_VERSION=1.6.777 NEXT_PUBLIC_CPL_MODE=production \ No newline at end of file diff --git a/.woodpecker.yml b/.woodpecker.yml index 50e7e15..e9cb3d5 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -1,22 +1,23 @@ +# .woodpecker.yml — Option B (Browser im Workspace) steps: - - name: install-dependencies + - name: install-dependencies-and-browsers image: node:22 environment: - NODE_PATH: /var/jenkins_home/.npm/node_modules - NPM_CONFIG_CACHE: /var/jenkins_home/.npm + PLAYWRIGHT_BROWSERS_PATH: "0" # Browser in ./node_modules/playwright/.local-browsers + CI: "true" commands: - - echo "📦 Installing dependencies..." - - npm install --prefer-offline --no-audit - - - name: install-playwright - image: node:22 - commands: - - echo "🧩 Installing Playwright and required browsers..." - - npx playwright install # vollständige Installation inkl. Chromium & headless_shell - - npx playwright install-deps + - echo "📦 Installing deps..." + - npm ci + - echo "🧩 Installing Playwright (Chromium) into workspace..." + - npx playwright install chromium - name: run-tests image: node:22 + environment: + PLAYWRIGHT_BROWSERS_PATH: "0" # gleicher Pfad wie oben + CI: "true" commands: + - echo "🔧 Installing system dependencies for Playwright..." + - npx playwright install-deps - echo "🧪 Running Playwright tests (Chromium only)..." - npx playwright test --project=chromium diff --git a/CHANGELOG.md b/CHANGELOG.md index 8301d68..162e70f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## [1.6.777] – 2025-08-29 + +- fix: playwright config + +--- ## [1.6.776] – 2025-08-29 - fix: woodpecker install chromium diff --git a/package-lock.json b/package-lock.json index 90d1aa6..3e6a2ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cpl-v4", - "version": "1.6.776", + "version": "1.6.777", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cpl-v4", - "version": "1.6.776", + "version": "1.6.777", "dependencies": { "@fontsource/roboto": "^5.1.0", "@headlessui/react": "^2.2.4", diff --git a/package.json b/package.json index 879f194..722889b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cpl-v4", - "version": "1.6.776", + "version": "1.6.777", "private": true, "scripts": { "dev": "next dev", diff --git a/playwright.config.ts b/playwright.config.ts index 25a2351..799ca03 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -15,7 +15,7 @@ export default defineConfig({ use: { baseURL: "http://localhost:3000", - headless: true, + headless: false, launchOptions: { slowMo: 300 }, viewport: { width: 1920, height: 1080 }, video: "on", diff --git a/playwright/tests/all.test.ts b/playwright/tests/all.test.ts index d7414d7..6e40d70 100644 --- a/playwright/tests/all.test.ts +++ b/playwright/tests/all.test.ts @@ -4,13 +4,15 @@ import { runCableMonitoringTest } from "./pages/kabelueberwachungTest"; 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 }) => { // await runDashboardTest(page); // await runCableMonitoringTest(page); //await runDigitalInputsTest(page); - await runDigitalOutputsTest(page); + //await runDigitalOutputsTest(page); //await runAnalogInputsTest(page); + await runMeldungenTest(page); //await runSettingsPageTest(page); }); diff --git a/playwright/tests/pages/meldungenTest.ts b/playwright/tests/pages/meldungenTest.ts new file mode 100644 index 0000000..aba7a14 --- /dev/null +++ b/playwright/tests/pages/meldungenTest.ts @@ -0,0 +1,209 @@ +// gigityOutputsTest.ts +import type { Locator, Page } from "@playwright/test"; +import { expect } from "@playwright/test"; + +export async function runMeldungenTest(page: Page) { + await page.goto("/meldungen"); + + // 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); + + // Von + const vonText = page.getByText("Von"); + await highlightAndExpectVisible(page, vonText); + await vonText.click(); + await page.waitForTimeout(50); + + const vonTextbox = page + .locator("div") + .filter({ hasText: /^Von$/ }) + .getByRole("textbox"); + await highlightAndExpectVisible(page, vonTextbox); + await vonTextbox.click(); + await page.waitForTimeout(50); + + const julyDate = page + .getByLabel("Choose Date") + .locator("div") + .filter({ hasText: "July" }) + .first(); + await highlightAndExpectVisible(page, julyDate); + await expect(julyDate).toBeVisible(); + await page.waitForTimeout(50); + + await vonTextbox.click(); + await page.waitForTimeout(50); + + const bisTextbox = page + .locator("div") + .filter({ hasText: /^Bis$/ }) + .getByRole("textbox"); + await highlightAndExpectVisible(page, bisTextbox); + await bisTextbox.click(); + await page.waitForTimeout(50); + + const augustDate = page + .getByLabel("Choose Date") + .locator("div") + .filter({ hasText: "August" }) + .first(); + await highlightAndExpectVisible(page, augustDate); + await expect(augustDate).toBeVisible(); + await page.waitForTimeout(50); + + await bisTextbox.click(); + await page.waitForTimeout(50); + + await highlightAndExpectVisible(page, berichteHeading); + await berichteHeading.click(); + await page.waitForTimeout(50); + + // Buttons sichtbar + const anzeigenBtn = page.getByRole("button", { name: "Anzeigen" }); + await highlightAndExpectVisible(page, anzeigenBtn); + await expect(anzeigenBtn).toBeVisible(); + await page.waitForTimeout(50); + + const alleQuellenBtn = page.getByRole("button", { name: "Alle Quellen" }); + await highlightAndExpectVisible(page, alleQuellenBtn); + await expect(alleQuellenBtn).toBeVisible(); + await alleQuellenBtn.click(); + await page.waitForTimeout(50); + await alleQuellenBtn.click(); + await page.waitForTimeout(50); + + // Tabellenzellen + const tableCells = [ + page.getByRole("cell", { name: "Prio" }), + page.getByRole("cell", { name: "Zeitstempel" }), + page.getByRole("cell", { name: "Quelle" }), + page.getByRole("cell", { name: "Meldung" }), + page.getByRole("cell", { name: "Status" }), + ]; + for (const cell of tableCells) { + await highlightAndExpectVisible(page, cell); + await cell.click(); + await page.waitForTimeout(30); + } + + // Dynamische Zeilen und Zellen (Beispiel für mehrere Zeitstempel) + const zeiten = [ + "11.08.2025, 11:52:44", + "11.08.2025, 11:51:14", + "11.08.2025, 11:44:19", + "11.08.2025, 11:43:44", + "11.08.2025, 11:36:42", + "11.08.2025, 11:35:45", + "11.08.2025, 11:21:16", + "11.08.2025, 11:21:05", + "11.08.2025, 11:14:01", + ]; + for (const zeit of zeiten) { + const row = page.getByRole("row", { name: zeit }); + await highlightAndExpectVisible(page, row.getByRole("cell").first()); + await row.getByRole("cell").first().click(); + await page.waitForTimeout(20); + + const timeCell = page.getByRole("cell", { name: zeit.split(", ")[1] }); + await highlightAndExpectVisible(page, timeCell); + await timeCell.click(); + await page.waitForTimeout(20); + + for (let i = 2; i <= 4; i++) { + const cell = row.getByRole("cell").nth(i); + await highlightAndExpectVisible(page, cell); + await cell.click(); + await page.waitForTimeout(20); + } + } +} + +//--------------------------------------------------------------------- + +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(); +}