Entorno para test E2E
This commit is contained in:
parent
42b197c16d
commit
94b6515a03
6
.gitignore
vendored
6
.gitignore
vendored
@ -10,3 +10,9 @@ dist-ssr
|
|||||||
server/dist
|
server/dist
|
||||||
public/dist
|
public/dist
|
||||||
out
|
out
|
||||||
|
|
||||||
|
playwright-report/
|
||||||
|
test-results/
|
||||||
|
blob-report/
|
||||||
|
apps/server/.env.e2e
|
||||||
|
apps/web/.env.e2e
|
||||||
|
|||||||
29
apps/server/.env.e2e.example
Normal file
29
apps/server/.env.e2e.example
Normal 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
|
||||||
2
apps/web/.env.e2e.example
Normal file
2
apps/web/.env.e2e.example
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
VITE_API_SERVER_URL=http://127.0.0.1:3002/api/v1
|
||||||
|
VITE_FORCE_INITIAL_ONBOARDING=false
|
||||||
@ -21,11 +21,15 @@
|
|||||||
"check": "biome check .",
|
"check": "biome check .",
|
||||||
"check:write": "biome check --write --unsafe .",
|
"check:write": "biome check --write --unsafe .",
|
||||||
"test:frontend": "node --experimental-test-module-mocks --import tsx --test",
|
"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",
|
"test:unit": "node --import tsx --test",
|
||||||
"typecheck": "tsc -p tsconfig.json --noEmit"
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.4.11",
|
"@biomejs/biome": "2.4.11",
|
||||||
|
"@playwright/test": "^1.63.0",
|
||||||
"@repo/typescript-config": "workspace:*",
|
"@repo/typescript-config": "workspace:*",
|
||||||
"@tailwindcss/postcss": "^4.2.2",
|
"@tailwindcss/postcss": "^4.2.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.58.1",
|
"@typescript-eslint/eslint-plugin": "^8.58.1",
|
||||||
|
|||||||
40
playwright.config.ts
Normal file
40
playwright.config.ts
Normal 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,
|
||||||
|
});
|
||||||
@ -11,6 +11,9 @@ importers:
|
|||||||
'@biomejs/biome':
|
'@biomejs/biome':
|
||||||
specifier: 2.4.11
|
specifier: 2.4.11
|
||||||
version: 2.4.11
|
version: 2.4.11
|
||||||
|
'@playwright/test':
|
||||||
|
specifier: ^1.63.0
|
||||||
|
version: 1.63.0
|
||||||
'@repo/typescript-config':
|
'@repo/typescript-config':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:packages/typescript-config
|
version: link:packages/typescript-config
|
||||||
@ -3074,6 +3077,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==}
|
resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==}
|
||||||
engines: {node: '>= 10.0.0'}
|
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':
|
'@radix-ui/number@1.1.3':
|
||||||
resolution: {integrity: sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA==}
|
resolution: {integrity: sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA==}
|
||||||
|
|
||||||
@ -6952,6 +6960,16 @@ packages:
|
|||||||
pkg-types@1.3.1:
|
pkg-types@1.3.1:
|
||||||
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
|
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:
|
plop@4.0.5:
|
||||||
resolution: {integrity: sha512-pJz6oWC9LyBp5mBrRp8AUV2RNiuGW+t/HOs4zwN+b/3YxoObZOOFvjn1mJMpAeKi2pbXADMFOOVQVTVXEdDHDw==}
|
resolution: {integrity: sha512-pJz6oWC9LyBp5mBrRp8AUV2RNiuGW+t/HOs4zwN+b/3YxoObZOOFvjn1mJMpAeKi2pbXADMFOOVQVTVXEdDHDw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@ -9238,6 +9256,10 @@ snapshots:
|
|||||||
'@parcel/watcher-win32-ia32': 2.5.6
|
'@parcel/watcher-win32-ia32': 2.5.6
|
||||||
'@parcel/watcher-win32-x64': 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/number@1.1.3': {}
|
||||||
|
|
||||||
'@radix-ui/primitive@1.1.3': {}
|
'@radix-ui/primitive@1.1.3': {}
|
||||||
@ -13054,6 +13076,12 @@ snapshots:
|
|||||||
mlly: 1.8.2
|
mlly: 1.8.2
|
||||||
pathe: 2.0.3
|
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):
|
plop@4.0.5(@types/node@25.9.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/liftoff': 4.0.3
|
'@types/liftoff': 4.0.3
|
||||||
|
|||||||
0
tests/e2e/.gitkeep
Normal file
0
tests/e2e/.gitkeep
Normal file
29
tests/e2e/README.md
Normal file
29
tests/e2e/README.md
Normal 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`.
|
||||||
0
tests/e2e/support/.gitkeep
Normal file
0
tests/e2e/support/.gitkeep
Normal file
13
tests/e2e/support/ensure-e2e-database.mjs
Normal file
13
tests/e2e/support/ensure-e2e-database.mjs
Normal 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.");
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user