feat: add Playwright configuration and initial e2e test for authentication

- Created Playwright configuration file to set up testing environment.
- Added a new e2e test for user authentication in login.spec.ts.
- Updated tsconfig.node.json to include playwright.config.ts.
- Enhanced vite.config.ts to include API proxying for backend integration.
- Added a placeholder for last run test results in .last-run.json.
This commit is contained in:
2025-10-11 17:25:38 +02:00
parent 0c405ee6ca
commit 1099a738a3
17 changed files with 558 additions and 14 deletions

20
frontend/nginx.conf Normal file
View File

@@ -0,0 +1,20 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://backend:8000/api/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

View File

@@ -14,6 +14,7 @@
"react-leaflet": "^4.2.1"
},
"devDependencies": {
"@playwright/test": "^1.48.0",
"@types/leaflet": "^1.9.13",
"@types/node": "^20.16.5",
"@types/react": "^18.3.3",
@@ -972,6 +973,22 @@
"node": ">= 8"
}
},
"node_modules/@playwright/test": {
"version": "1.56.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.0.tgz",
"integrity": "sha512-Tzh95Twig7hUwwNe381/K3PggZBZblKUe2wv25oIpzWLr6Z0m4KgV1ZVIjnR6GM9ANEqjZD7XsZEa6JL/7YEgg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.56.0"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@react-leaflet/core": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz",
@@ -4654,6 +4671,53 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/playwright": {
"version": "1.56.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.0.tgz",
"integrity": "sha512-X5Q1b8lOdWIE4KAoHpW3SE8HvUB+ZZsUoN64ZhjnN8dOb1UpujxBtENGiZFE+9F/yhzJwYa+ca3u43FeLbboHA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.56.0"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
"version": "1.56.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.0.tgz",
"integrity": "sha512-1SXl7pMfemAMSDn5rkPeZljxOCYAmQnYLBTExuh6E8USHXGSX3dx6lYZN/xPpTz1vimXmPA9CDnILvmJaB8aSQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/playwright/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/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",

View File

@@ -8,7 +8,8 @@
"build": "tsc --noEmit && tsc --project tsconfig.node.json --noEmit && vite build",
"preview": "vite preview",
"lint": "eslint \"src/**/*.{ts,tsx}\"",
"format": "prettier --write \"src/**/*.{ts,tsx,css}\""
"format": "prettier --write \"src/**/*.{ts,tsx,css}\"",
"test:e2e": "playwright test"
},
"dependencies": {
"leaflet": "^1.9.4",
@@ -24,6 +25,7 @@
"@typescript-eslint/eslint-plugin": "^8.6.0",
"@typescript-eslint/parser": "^8.6.0",
"@vitejs/plugin-react": "^4.3.1",
"@playwright/test": "^1.48.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.31.0",

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,22 @@
import { defineConfig, devices } from '@playwright/test';
const baseURL = process.env.PLAYWRIGHT_BASE_URL ?? 'http://localhost:8080';
export default defineConfig({
testDir: './tests/e2e',
fullyParallel: true,
retries: process.env.CI ? 2 : 0,
reporter: [['list'], ['html', { outputFolder: 'playwright-report', open: 'never' }]],
use: {
baseURL,
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});

View File

@@ -0,0 +1,4 @@
{
"status": "passed",
"failedTests": []
}

View File

@@ -0,0 +1,26 @@
import { expect, test, type Page } from '@playwright/test';
const demoCredentials = {
username: process.env.DEMO_USERNAME ?? 'demo',
password: process.env.DEMO_PASSWORD ?? 'railgame123',
};
test.describe('Authentication', () => {
test('allows the demo user to sign in and view the network snapshot', async ({
page,
}: {
page: Page;
}) => {
await page.goto('/');
await expect(page.getByRole('heading', { name: 'Sign in' })).toBeVisible();
await page.getByLabel('Username').fill(demoCredentials.username);
await page.getByLabel('Password').fill(demoCredentials.password);
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page.getByRole('heading', { name: 'Network Snapshot' })).toBeVisible();
await expect(page.getByRole('heading', { name: 'Stations' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Sign out' })).toBeVisible();
});
});

View File

@@ -14,5 +14,5 @@
"isolatedModules": true,
"types": ["node"]
},
"include": ["vite.config.ts"]
"include": ["vite.config.ts", "playwright.config.ts"]
}

View File

@@ -1,10 +1,26 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
const backendUrl = process.env.VITE_BACKEND_URL ?? 'http://localhost:8000';
export default defineConfig({
plugins: [react()],
server: {
port: 5173,
open: true
}
open: true,
proxy: {
'/api': {
target: backendUrl,
changeOrigin: true,
},
},
},
preview: {
proxy: {
'/api': {
target: backendUrl,
changeOrigin: true,
},
},
},
});