Entorno para test E2E

This commit is contained in:
David Arranz 2026-09-10 14:04:03 +02:00
parent 42b197c16d
commit 94b6515a03
10 changed files with 151 additions and 0 deletions

6
.gitignore vendored
View File

@ -10,3 +10,9 @@ dist-ssr
server/dist
public/dist
out
playwright-report/
test-results/
blob-report/
apps/server/.env.e2e
apps/web/.env.e2e

View File

@ -0,0 +1,29 @@
NODE_ENV=test
PORT=3002
API_BASE_PATH=/api/v1
FRONTEND_URL=http://127.0.0.1:5173
TRUST_PROXY=0
TIMEZONE=Europe/Madrid
DB_DIALECT=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=uecko_erp_e2e
DB_USER=replace-with-e2e-user
DB_PASS=replace-with-e2e-password
DB_LOGGING=false
DB_SSL=false
DB_SYNC_MODE=none
WARMUP_TIMEOUT_MS=30000
WARMUP_STRICT=false
JWT_SECRET=replace-with-a-dedicated-e2e-secret-of-at-least-32-characters
JWT_ACCESS_EXPIRATION=15m
JWT_REFRESH_EXPIRATION=7d
TEMPLATES_PATH=./storage/e2e/templates
DOCUMENTS_PATH=./storage/e2e/documents
SIGNED_DOCUMENTS_PATH=./storage/e2e/signed-documents
FASTREPORT_BIN=replace-with-fastreport-binary-path
SIGNING_SERVICE_URL=http://127.0.0.1:3003
SIGNING_SERVICE_METHOD=POST
SIGNING_SERVICE_TIMEOUT_MS=5000
SIGNING_SERVICE_MAX_RETRIES=0
COMPANY_CERTIFICATES_PATH=./storage/e2e/certificates

View File

@ -0,0 +1,2 @@
VITE_API_SERVER_URL=http://127.0.0.1:3002/api/v1
VITE_FORCE_INITIAL_ONBOARDING=false

View File

@ -21,11 +21,15 @@
"check": "biome check .",
"check:write": "biome check --write --unsafe .",
"test:frontend": "node --experimental-test-module-mocks --import tsx --test",
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui",
"test:e2e:headed": "playwright test --headed",
"test:unit": "node --import tsx --test",
"typecheck": "tsc -p tsconfig.json --noEmit"
},
"devDependencies": {
"@biomejs/biome": "2.4.11",
"@playwright/test": "^1.63.0",
"@repo/typescript-config": "workspace:*",
"@tailwindcss/postcss": "^4.2.2",
"@typescript-eslint/eslint-plugin": "^8.58.1",

40
playwright.config.ts Normal file
View File

@ -0,0 +1,40 @@
import { defineConfig, devices } from "@playwright/test";
const localBaseUrl = "http://127.0.0.1:5173";
const baseURL = process.env.E2E_BASE_URL ?? localBaseUrl;
const startLocalStack = !process.env.E2E_BASE_URL;
export default defineConfig({
testDir: "./tests/e2e",
timeout: 30_000,
expect: { timeout: 5_000 },
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
reporter: [["html", { open: "never" }]],
use: {
baseURL,
testIdAttribute: "data-testid",
trace: "on-first-retry",
screenshot: "only-on-failure",
video: "retain-on-failure",
},
projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }],
webServer: startLocalStack
? [
{
command:
"node tests/e2e/support/ensure-e2e-database.mjs && cd apps/server && node --env-file=.env.e2e --import=tsx src/index.ts",
url: "http://127.0.0.1:3002/api/v1/__ready",
timeout: 120_000,
reuseExistingServer: !process.env.CI,
},
{
command: "cd apps/web && pnpm dev -- --mode e2e --port 5173",
url: localBaseUrl,
timeout: 120_000,
reuseExistingServer: !process.env.CI,
},
]
: undefined,
});

View File

@ -11,6 +11,9 @@ importers:
'@biomejs/biome':
specifier: 2.4.11
version: 2.4.11
'@playwright/test':
specifier: ^1.63.0
version: 1.63.0
'@repo/typescript-config':
specifier: workspace:*
version: link:packages/typescript-config
@ -3074,6 +3077,11 @@ packages:
resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==}
engines: {node: '>= 10.0.0'}
'@playwright/test@1.63.0':
resolution: {integrity: sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==}
engines: {node: '>=20'}
hasBin: true
'@radix-ui/number@1.1.3':
resolution: {integrity: sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA==}
@ -6952,6 +6960,16 @@ packages:
pkg-types@1.3.1:
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
playwright-core@1.63.0:
resolution: {integrity: sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==}
engines: {node: '>=20'}
hasBin: true
playwright@1.63.0:
resolution: {integrity: sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==}
engines: {node: '>=20'}
hasBin: true
plop@4.0.5:
resolution: {integrity: sha512-pJz6oWC9LyBp5mBrRp8AUV2RNiuGW+t/HOs4zwN+b/3YxoObZOOFvjn1mJMpAeKi2pbXADMFOOVQVTVXEdDHDw==}
engines: {node: '>=18'}
@ -9238,6 +9256,10 @@ snapshots:
'@parcel/watcher-win32-ia32': 2.5.6
'@parcel/watcher-win32-x64': 2.5.6
'@playwright/test@1.63.0':
dependencies:
playwright: 1.63.0
'@radix-ui/number@1.1.3': {}
'@radix-ui/primitive@1.1.3': {}
@ -13054,6 +13076,12 @@ snapshots:
mlly: 1.8.2
pathe: 2.0.3
playwright-core@1.63.0: {}
playwright@1.63.0:
dependencies:
playwright-core: 1.63.0
plop@4.0.5(@types/node@25.9.1):
dependencies:
'@types/liftoff': 4.0.3

0
tests/e2e/.gitkeep Normal file
View File

29
tests/e2e/README.md Normal file
View File

@ -0,0 +1,29 @@
# Infraestructura E2E
Suite de Playwright para navegador, frontend, backend y MariaDB E2E. Aún no contiene pruebas funcionales.
## Estructura
El primer nivel debe coincidir exactamente con el módulo propietario en `modules`: por ejemplo, `identity` usará `tests/e2e/identity/login.spec.ts` y facturas de clientes `tests/e2e/customer-invoices/`. No usar `auth`, `invoices` ni `settings`. `support/` es exclusivamente infraestructura transversal.
## Variables y base de datos
Copia `apps/server/.env.e2e.example` a `apps/server/.env.e2e` y completa una MariaDB exclusiva E2E; `DB_NAME` nunca debe ser la base de desarrollo. Copia `apps/web/.env.e2e.example` a `apps/web/.env.e2e`.
El backend arranca con `node --env-file=.env.e2e`, que prevalece sobre `.env`. La plantilla usa `DB_SYNC_MODE=none`; no hay reset, seed ni operación destructiva en esta fase. Las futuras operaciones destructivas deberán rechazar cualquier base que no sea E2E.
`E2E_BASE_URL` permite usar un stack E2E ya iniciado y evita levantar procesos locales. Futuras credenciales: `E2E_USER_EMAIL` y `E2E_USER_PASSWORD`, nunca versionadas.
## Ejecución
```bash
pnpm test:e2e
pnpm test:e2e:ui
pnpm test:e2e:headed
```
Localmente se espera backend en `http://127.0.0.1:3002/api/v1/__ready` y Vite en `http://127.0.0.1:5173`.
## Selectores
Prioridad: `id` técnico estable, `data-testid`, atributo técnico como `name` y CSS estable solo excepcionalmente. No usar textos, labels o `aria-label` traducibles, Tailwind visual, `nth-child` ni DOM incidental. Playwright configura `data-testid`.

View File

View File

@ -0,0 +1,13 @@
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
const envFile = resolve("apps/server/.env.e2e");
const databaseName = readFileSync(envFile, "utf8")
.split(/\r?\n/)
.find((line) => line.startsWith("DB_NAME="))
?.slice("DB_NAME=".length)
.trim();
if (databaseName !== "uecko_erp_e2e") {
throw new Error("E2E requires DB_NAME=uecko_erp_e2e in apps/server/.env.e2e.");
}