feat: migrate from Cypress to Playwright for E2E testing
- Remove Cypress dependencies and configuration files - Install @playwright/test with browser support - Add playwright.config.ts with optimized settings for Next.js - Migrate existing Cypress tests to Playwright format - Add new E2E test scripts to package.json - Configure GitHub Actions workflow for automated testing - Update .gitignore for Playwright artifacts BREAKING CHANGE: E2E testing framework changed from Cypress to Playwright
This commit is contained in:
@@ -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.680
|
||||
NEXT_PUBLIC_APP_VERSION=1.6.682
|
||||
NEXT_PUBLIC_CPL_MODE=json # json (Entwicklungsumgebung) oder jsSimulatedProd (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter)
|
||||
|
||||
|
||||
@@ -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.680
|
||||
NEXT_PUBLIC_APP_VERSION=1.6.682
|
||||
NEXT_PUBLIC_CPL_MODE=production
|
||||
27
.github/workflows/playwright.yml
vendored
Normal file
27
.github/workflows/playwright.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
pull_request:
|
||||
branches: [main, master]
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install --with-deps
|
||||
- name: Run Playwright tests
|
||||
run: npm run test:e2e
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -9,6 +9,12 @@
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# playwright
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
28
CHANGELOG.md
28
CHANGELOG.md
@@ -1,3 +1,31 @@
|
||||
## [1.6.682] – 2025-08-01
|
||||
|
||||
- git commit -m "feat: Enhance DetailModal with auto-loading and improved UX
|
||||
|
||||
- Add automatic data loading every 2 seconds when no chart data available
|
||||
- Implement intelligent cursor-wait display for entire modal during loading
|
||||
- Auto-reset to 'Alle Messwerte' (DIA0) and clear date fields on modal open
|
||||
- Add Tailwind-based color system for chart lines (gray for min/max, littwin-blue for current/average)
|
||||
- Improve chart line layering with background/foreground organization
|
||||
- Add periodic UI updates to ensure responsive loading feedback
|
||||
- Maintain manual 'Daten laden' button control alongside auto-loading
|
||||
- Fix TypeScript dependencies and optimize useEffect performance"
|
||||
|
||||
---
|
||||
## [1.6.681] – 2025-08-01
|
||||
|
||||
- git commit -m "feat: Enhance DetailModal with auto-loading and improved UX
|
||||
|
||||
- Add automatic data loading every 2 seconds when no chart data available
|
||||
- Implement intelligent cursor-wait display for entire modal during loading
|
||||
- Auto-reset to 'Alle Messwerte' (DIA0) and clear date fields on modal open
|
||||
- Add Tailwind-based color system for chart lines (gray for min/max, littwin-blue for current/average)
|
||||
- Improve chart line layering with background/foreground organization
|
||||
- Add periodic UI updates to ensure responsive loading feedback
|
||||
- Maintain manual 'Daten laden' button control alongside auto-loading
|
||||
- Fix TypeScript dependencies and optimize useEffect performance"
|
||||
|
||||
---
|
||||
## [1.6.680] – 2025-08-01
|
||||
|
||||
- fix: System ->Detailansicht -> Modal
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { defineConfig } from "cypress";
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
setupNodeEvents(on, config) {
|
||||
// implement node event listeners here
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,46 +0,0 @@
|
||||
describe('Kue705FO Integration Tests', () => {
|
||||
beforeEach(() => {
|
||||
// Besuche die Seite, auf der die Komponente gerendert wird
|
||||
//cy.visit('/path-to-your-component'); // Passe den Pfad an deine App an
|
||||
cy.visit('http://localhost:3000/kabelueberwachung');
|
||||
});
|
||||
|
||||
it('should render the component with default props', () => {
|
||||
// Überprüfe, ob der Modulname und die Slotnummer angezeigt werden
|
||||
cy.contains('KÜ705-FO').should('be.visible');
|
||||
cy.contains('Modul 1').should('be.visible'); // Beispiel für den Modulnamen
|
||||
});
|
||||
|
||||
it('should update display when TDR button is clicked', () => {
|
||||
// Klicke auf den TDR-Button
|
||||
cy.contains('TDR').click();
|
||||
|
||||
// Überprüfe, ob der Text aktualisiert wurde
|
||||
cy.contains('Entfernung [Km]').should('be.visible');
|
||||
});
|
||||
|
||||
it('should switch back to Schleife display', () => {
|
||||
// Klicke auf TDR, dann zurück zu Schleife
|
||||
cy.contains('TDR').click();
|
||||
cy.contains('Schleife').click();
|
||||
|
||||
// Überprüfe, ob der Text aktualisiert wurde
|
||||
cy.contains('Schleifenwiderstand [kOhm]').should('be.visible');
|
||||
});
|
||||
|
||||
it('should disable TDR button when tdrActive is 0', () => {
|
||||
// Dies erfordert eine benutzerdefinierte Backend-Konfiguration oder Redux-Manipulation
|
||||
cy.contains('TDR').should('be.disabled');
|
||||
});
|
||||
|
||||
it('should open and close the settings modal', () => {
|
||||
// Öffne das Modal
|
||||
cy.contains('⚙').click();
|
||||
cy.contains('KUE Einstellung - Slot 1').should('be.visible');
|
||||
|
||||
// Schließe das Modal
|
||||
cy.contains('×').click();
|
||||
cy.contains('KUE Einstellung - Slot 1').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 123 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 109 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 122 KiB |
@@ -1,37 +0,0 @@
|
||||
/// <reference types="cypress" />
|
||||
// ***********************************************
|
||||
// This example commands.ts shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
//
|
||||
// declare global {
|
||||
// namespace Cypress {
|
||||
// interface Chainable {
|
||||
// login(email: string, password: string): Chainable<void>
|
||||
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -1,17 +0,0 @@
|
||||
// ***********************************************************
|
||||
// This example support/e2e.ts is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
1305
package-lock.json
generated
1305
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cpl-v4",
|
||||
"version": "1.6.680",
|
||||
"version": "1.6.682",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
@@ -12,6 +12,10 @@
|
||||
"check": "npm run lint && npm run typecheck",
|
||||
"lint": "next lint",
|
||||
"test": "jest",
|
||||
"test:e2e": "playwright test",
|
||||
"test:e2e:ui": "playwright test --ui",
|
||||
"test:e2e:debug": "playwright test --debug",
|
||||
"test:e2e:report": "playwright show-report",
|
||||
"prepare": "husky install",
|
||||
"bump-version": "node ./scripts/bumpVersion.js"
|
||||
},
|
||||
@@ -55,11 +59,11 @@
|
||||
"redux": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.54.2",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.2.0",
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/cypress": "^1.1.6",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/lodash": "^4.17.16",
|
||||
"@types/node": "^22.10.10",
|
||||
@@ -69,7 +73,6 @@
|
||||
"@types/redux-mock-store": "^1.5.0",
|
||||
"@types/testing-library__react": "^10.2.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"cypress": "^14.0.0",
|
||||
"eslint": "8.57.1",
|
||||
"eslint-config-next": "15.3.4",
|
||||
"husky": "^8.0.0",
|
||||
|
||||
71
playwright.config.ts
Normal file
71
playwright.config.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { defineConfig, devices } from "@playwright/test";
|
||||
|
||||
/**
|
||||
* @see https://playwright.dev/docs/test-configuration
|
||||
*/
|
||||
export default defineConfig({
|
||||
testDir: "./tests",
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: "html",
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
baseURL: "http://localhost:3000",
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: "on-first-retry",
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
use: { ...devices["Desktop Chrome"] },
|
||||
},
|
||||
|
||||
{
|
||||
name: "firefox",
|
||||
use: { ...devices["Desktop Firefox"] },
|
||||
},
|
||||
|
||||
{
|
||||
name: "webkit",
|
||||
use: { ...devices["Desktop Safari"] },
|
||||
},
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: { ...devices['Pixel 5'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] },
|
||||
// },
|
||||
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
// name: 'Microsoft Edge',
|
||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
// },
|
||||
// {
|
||||
// name: 'Google Chrome',
|
||||
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||
// },
|
||||
],
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
webServer: {
|
||||
command: "npm run dev",
|
||||
url: "http://localhost:3000",
|
||||
reuseExistingServer: !process.env.CI,
|
||||
},
|
||||
});
|
||||
48
tests/kue705fo.spec.ts
Normal file
48
tests/kue705fo.spec.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
test.describe("Kue705FO Integration Tests", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Besuche die Seite, auf der die Komponente gerendert wird
|
||||
await page.goto("/kabelueberwachung");
|
||||
});
|
||||
|
||||
test("should render the component with default props", async ({ page }) => {
|
||||
// Überprüfe, ob der Modulname und die Slotnummer angezeigt werden
|
||||
await expect(page.locator("text=KÜ705-FO")).toBeVisible();
|
||||
await expect(page.locator("text=Modul 1")).toBeVisible(); // Beispiel für den Modulnamen
|
||||
});
|
||||
|
||||
test("should update display when TDR button is clicked", async ({ page }) => {
|
||||
// Klicke auf den TDR-Button
|
||||
await page.locator("text=TDR").click();
|
||||
|
||||
// Überprüfe, ob der Text aktualisiert wurde
|
||||
await expect(page.locator("text=Entfernung [Km]")).toBeVisible();
|
||||
});
|
||||
|
||||
test("should switch back to Schleife display", async ({ page }) => {
|
||||
// Klicke auf TDR, dann zurück zu Schleife
|
||||
await page.locator("text=TDR").click();
|
||||
await page.locator("text=Schleife").click();
|
||||
|
||||
// Überprüfe, ob der Text aktualisiert wurde
|
||||
await expect(page.locator("text=Schleifenwiderstand [kOhm]")).toBeVisible();
|
||||
});
|
||||
|
||||
test("should disable TDR button when tdrActive is 0", async ({ page }) => {
|
||||
// Dies erfordert eine benutzerdefinierte Backend-Konfiguration oder Redux-Manipulation
|
||||
await expect(page.locator("text=TDR")).toBeDisabled();
|
||||
});
|
||||
|
||||
test("should open and close the settings modal", async ({ page }) => {
|
||||
// Öffne das Modal
|
||||
await page.locator("text=⚙").click();
|
||||
await expect(page.locator("text=KUE Einstellung - Slot 1")).toBeVisible();
|
||||
|
||||
// Schließe das Modal
|
||||
await page.locator("text=×").click();
|
||||
await expect(
|
||||
page.locator("text=KUE Einstellung - Slot 1")
|
||||
).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
72
tests/system-view.spec.ts
Normal file
72
tests/system-view.spec.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
test.describe("System View Tests", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Besuche die System-Seite
|
||||
await page.goto("/system");
|
||||
});
|
||||
|
||||
test("should display system title", async ({ page }) => {
|
||||
// Überprüfe, ob der Titel angezeigt wird
|
||||
await expect(page.locator("h1")).toContainText(
|
||||
"System Spannungen & Temperaturen"
|
||||
);
|
||||
});
|
||||
|
||||
test("should show loading state initially", async ({ page }) => {
|
||||
// Überprüfe, ob der Ladeindikator angezeigt wird
|
||||
await expect(
|
||||
page.locator("text=Lade Systemdaten … bitte warten")
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("should display system data after loading", async ({ page }) => {
|
||||
// Warte auf das Verschwinden des Ladeindikators
|
||||
await page.waitForSelector("text=Lade Systemdaten … bitte warten", {
|
||||
state: "hidden",
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
// Überprüfe, ob Systemdaten angezeigt werden
|
||||
// Diese Tests müssen an die tatsächliche Implementierung angepasst werden
|
||||
await expect(
|
||||
page.locator('[data-testid="system-overview-grid"]')
|
||||
).toBeVisible({ timeout: 15000 });
|
||||
});
|
||||
|
||||
test("should open detail modal when clicking on voltage card", async ({
|
||||
page,
|
||||
}) => {
|
||||
// Warte auf das Laden der Daten
|
||||
await page.waitForSelector("text=Lade Systemdaten … bitte warten", {
|
||||
state: "hidden",
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
// Klicke auf eine Spannungskarte (dies muss an die tatsächliche Implementierung angepasst werden)
|
||||
await page.locator('[data-testid="voltage-card"]:first-child').click();
|
||||
|
||||
// Überprüfe, ob das Detail-Modal geöffnet wird
|
||||
await expect(page.locator('[data-testid="detail-modal"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test("should close detail modal when clicking close button", async ({
|
||||
page,
|
||||
}) => {
|
||||
// Warte auf das Laden der Daten
|
||||
await page.waitForSelector("text=Lade Systemdaten … bitte warten", {
|
||||
state: "hidden",
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
// Öffne das Modal
|
||||
await page.locator('[data-testid="voltage-card"]:first-child').click();
|
||||
await expect(page.locator('[data-testid="detail-modal"]')).toBeVisible();
|
||||
|
||||
// Schließe das Modal
|
||||
await page.locator('[data-testid="modal-close-button"]').click();
|
||||
await expect(
|
||||
page.locator('[data-testid="detail-modal"]')
|
||||
).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -30,7 +30,7 @@
|
||||
"allowJs": true,
|
||||
|
||||
// 🌐 IDE-Typen
|
||||
"types": ["cypress", "node"],
|
||||
"types": ["node"],
|
||||
|
||||
// 📚 Unterstützte Bibliotheken
|
||||
"lib": ["dom", "dom.iterable", "es2020"],
|
||||
|
||||
Reference in New Issue
Block a user