feat: enhance Playwright configuration and CI workflow for E2E testing
- Updated playwright.config.js to allow dynamic base URL configuration via environment variables, improving flexibility for different environments. - Modified .gitea/workflows/test.yml to include steps for starting a development stack, seeding test data, and stopping the stack after tests, enhancing the CI process for end-to-end testing. - Refactored login test in dev-smoke-test.spec.js to use a dedicated function for submitting the login form, improving code clarity and maintainability.
This commit is contained in:
parent
1f2c8ea0f1
commit
50b8ff12cd
|
|
@ -57,7 +57,6 @@ jobs:
|
||||||
playwright-tests:
|
playwright-tests:
|
||||||
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
|
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [lint-backend, build-frontend]
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
@ -67,19 +66,53 @@ jobs:
|
||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: '20'
|
||||||
|
|
||||||
- name: Install Playwright
|
- name: Start dev stack for E2E
|
||||||
|
env:
|
||||||
|
DEV_ALLOWED_ORIGINS: http://127.0.0.1:3098,http://localhost:3098,http://host.docker.internal:3098,https://dev.shinkan.jinkendo.de
|
||||||
run: |
|
run: |
|
||||||
npm install -D @playwright/test
|
docker compose -f docker-compose.dev-env.yml up -d --build
|
||||||
npx playwright install --with-deps chromium
|
echo "Warte auf Frontend + API (/health) …"
|
||||||
|
for i in $(seq 1 90); do
|
||||||
|
if curl -sf http://127.0.0.1:3098/health >/dev/null 2>&1; then
|
||||||
|
echo "Health OK (Versuch $i)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
echo "Timeout: /health nicht erreichbar"
|
||||||
|
curl -v http://127.0.0.1:3098/health || true
|
||||||
|
docker compose -f docker-compose.dev-env.yml logs --tail=120
|
||||||
|
exit 1
|
||||||
|
|
||||||
- name: Run Playwright tests
|
- name: Seed E2E test user (erste Registrierung in frischer DB)
|
||||||
env:
|
env:
|
||||||
TEST_EMAIL: lars@stommer.com
|
TEST_EMAIL: lars@stommer.com
|
||||||
TEST_PASSWORD: 12345678
|
TEST_PASSWORD: 12345678
|
||||||
run: |
|
run: |
|
||||||
|
curl -sf -X POST "http://127.0.0.1:3098/api/auth/register" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"email\":\"${TEST_EMAIL}\",\"password\":\"${TEST_PASSWORD}\",\"name\":\"Playwright CI\"}" \
|
||||||
|
|| echo "(Registrierung übersprungen — Nutzer existiert evtl. schon)"
|
||||||
|
|
||||||
|
- name: Install Playwright
|
||||||
|
run: |
|
||||||
|
npm ci || npm install
|
||||||
|
npx playwright install --with-deps chromium
|
||||||
|
|
||||||
|
- name: Run Playwright tests
|
||||||
|
env:
|
||||||
|
PLAYWRIGHT_BASE_URL: http://127.0.0.1:3098
|
||||||
|
TEST_EMAIL: lars@stommer.com
|
||||||
|
TEST_PASSWORD: 12345678
|
||||||
|
run: |
|
||||||
|
mkdir -p screenshots
|
||||||
npx playwright test
|
npx playwright test
|
||||||
echo "✓ Playwright tests passed"
|
echo "✓ Playwright tests passed"
|
||||||
|
|
||||||
|
- name: Stop dev stack
|
||||||
|
if: always()
|
||||||
|
run: docker compose -f docker-compose.dev-env.yml down
|
||||||
|
|
||||||
- name: Upload test screenshots
|
- name: Upload test screenshots
|
||||||
if: failure()
|
if: failure()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
|
|
|
||||||
76
package-lock.json
generated
Normal file
76
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
{
|
||||||
|
"name": "shinkan-jinkendo",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "shinkan-jinkendo",
|
||||||
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.49.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@playwright/test": {
|
||||||
|
"version": "1.59.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.1.tgz",
|
||||||
|
"integrity": "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"playwright": "1.59.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"playwright": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/playwright": {
|
||||||
|
"version": "1.59.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz",
|
||||||
|
"integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"playwright-core": "1.59.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"playwright": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/playwright-core": {
|
||||||
|
"version": "1.59.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz",
|
||||||
|
"integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bin": {
|
||||||
|
"playwright-core": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
package.json
Normal file
11
package.json
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"name": "shinkan-jinkendo",
|
||||||
|
"private": true,
|
||||||
|
"description": "Workspace-Metadaten für E2E (Playwright). Frontend: frontend/",
|
||||||
|
"scripts": {
|
||||||
|
"test:e2e": "playwright test"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.49.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,11 @@
|
||||||
|
// CI: PLAYWRIGHT_BASE_URL=http://127.0.0.1:3098 nach docker compose dev-env
|
||||||
|
// Lokal gegen LAN/Dev: export PLAYWRIGHT_BASE_URL=http://192.168.x.x:3098
|
||||||
|
|
||||||
|
const rawBase =
|
||||||
|
process.env.PLAYWRIGHT_BASE_URL ||
|
||||||
|
process.env.BASE_URL ||
|
||||||
|
'http://127.0.0.1:3098';
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
testDir: './tests',
|
testDir: './tests',
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
|
|
@ -6,7 +14,7 @@ module.exports = {
|
||||||
headless: true,
|
headless: true,
|
||||||
viewport: { width: 390, height: 844 },
|
viewport: { width: 390, height: 844 },
|
||||||
screenshot: 'only-on-failure',
|
screenshot: 'only-on-failure',
|
||||||
baseURL: 'http://192.168.2.49:3098',
|
baseURL: rawBase.replace(/\/$/, ''),
|
||||||
},
|
},
|
||||||
reporter: 'list',
|
reporter: 'list',
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,11 @@ const { test, expect } = require('@playwright/test');
|
||||||
const TEST_EMAIL = process.env.TEST_EMAIL || 'lars@stommer.com';
|
const TEST_EMAIL = process.env.TEST_EMAIL || 'lars@stommer.com';
|
||||||
const TEST_PASSWORD = process.env.TEST_PASSWORD || '12345678';
|
const TEST_PASSWORD = process.env.TEST_PASSWORD || '12345678';
|
||||||
|
|
||||||
|
/** Primärer Submit auf der Login-Seite (nicht den Tab "Login" vs. "Registrieren"). */
|
||||||
|
async function submitLoginForm(page) {
|
||||||
|
await page.getByRole('button', { name: 'Anmelden' }).click();
|
||||||
|
}
|
||||||
|
|
||||||
async function login(page) {
|
async function login(page) {
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
await page.waitForLoadState('networkidle');
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
@ -12,7 +17,7 @@ async function login(page) {
|
||||||
|
|
||||||
await page.fill('input[type="email"]', TEST_EMAIL);
|
await page.fill('input[type="email"]', TEST_EMAIL);
|
||||||
await page.fill('input[type="password"]', TEST_PASSWORD);
|
await page.fill('input[type="password"]', TEST_PASSWORD);
|
||||||
await page.click('button:has-text("Login")');
|
await submitLoginForm(page);
|
||||||
await page.waitForLoadState('networkidle');
|
await page.waitForLoadState('networkidle');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -21,10 +26,10 @@ test('1. Login funktioniert', async ({ page }) => {
|
||||||
await page.waitForSelector('input[type="email"]', { timeout: 10000 });
|
await page.waitForSelector('input[type="email"]', { timeout: 10000 });
|
||||||
await page.fill('input[type="email"]', TEST_EMAIL);
|
await page.fill('input[type="email"]', TEST_EMAIL);
|
||||||
await page.fill('input[type="password"]', TEST_PASSWORD);
|
await page.fill('input[type="password"]', TEST_PASSWORD);
|
||||||
await page.click('button:has-text("Login")');
|
await submitLoginForm(page);
|
||||||
await page.waitForLoadState('networkidle');
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
// Nach Login sollte Login-Button verschwinden
|
// Nach Login soll der Tab "Login" (Moduswahl) verschwinden — nicht der Submit "Anmelden"
|
||||||
const loginButton = page.locator('button:has-text("Login")');
|
const loginButton = page.locator('button:has-text("Login")');
|
||||||
await expect(loginButton).toHaveCount(0, { timeout: 10000 });
|
await expect(loginButton).toHaveCount(0, { timeout: 10000 });
|
||||||
|
|
||||||
|
|
@ -73,7 +78,7 @@ test('4. Navigation zu Vereine', async ({ page }) => {
|
||||||
console.log('✓ Vereine-Seite erreichbar');
|
console.log('✓ Vereine-Seite erreichbar');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('5. Desktop-Sidebar sichtbar (Desktop)', async ({ page, context }) => {
|
test('5. Desktop-Sidebar sichtbar (Desktop)', async ({ page }) => {
|
||||||
// Desktop-Viewport
|
// Desktop-Viewport
|
||||||
await page.setViewportSize({ width: 1280, height: 800 });
|
await page.setViewportSize({ width: 1280, height: 800 });
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user