FactuGES_ERP/docs/frontend/frontend-tests-E2E.md
2026-09-10 17:25:44 +02:00

8.2 KiB
Raw Blame History

Frontend ERP – Convención de organización y naming de tests E2E

Estado: convención adoptada para Playwright y la suite E2E del ERP.

1. Propósito

Definir una convención única para organizar, nombrar e identificar los tests E2E del ERP, de forma que sean fáciles de localizar, mantener y relacionar con el módulo y la feature funcional que validan.

2. Principio de organización

El primer nivel de directorios bajo tests/e2e debe corresponder exactamente con el nombre del módulo propietario existente bajo /modules.

Regla:

tests/e2e/<module>/

Ejemplos:

modules/identity
→ tests/e2e/identity

modules/customers
→ tests/e2e/customers

modules/companies
→ tests/e2e/companies

modules/catalogs
→ tests/e2e/catalogs

modules/customer-invoices
→ tests/e2e/customer-invoices

No deben crearse categorías E2E alternativas como:

auth/
invoices/
settings/

si no coinciden con el módulo propietario real.

3. Convención de nombres de fichero

El nombre del fichero debe representar la feature o el flujo funcional probado. No debe incluir numeración de casos.

Ejemplos:

login.spec.ts
protected-routes.spec.ts
logout.spec.ts
create-customer.spec.ts
update-customer.spec.ts

Se adopta *.spec.ts como sufijo estándar.

Al vivir dentro de:

tests/e2e/

no es necesario añadir e2e al nombre del fichero.

4. Convención de identificadores de casos

Cada test funcional debe tener un identificador estable con este formato:

<MODULE>-<FEATURE>-<NNN>

Donde:

  • MODULE: nombre lógico del módulo propietario, en mayúsculas.
  • FEATURE: feature o flujo funcional que agrupa el caso.
  • NNN: secuencia numérica de tres dígitos comenzando en 001 dentro de la feature.

Ejemplos:

IDENTITY-LOGIN-001
IDENTITY-LOGIN-002
IDENTITY-ROUTES-001
IDENTITY-LOGOUT-001

5. Ejemplo: Identity

Estructura:

tests/e2e/identity/
├── login.spec.ts
├── protected-routes.spec.ts
└── logout.spec.ts

Casos:

IDENTITY-LOGIN-001
  Login correcto y persistencia tras recarga

IDENTITY-LOGIN-002
  Rechazo de credenciales incorrectas

IDENTITY-ROUTES-001
  Acceso a ruta protegida sin sesión

IDENTITY-LOGOUT-001
  Cierre de sesión

Ejemplo en Playwright:

test(
  "IDENTITY-LOGIN-001: login correcto y persistencia tras recarga",
  async ({ page }) => {
    // ...
  },
);

test(
  "IDENTITY-LOGIN-002: rechazo de credenciales incorrectas",
  async ({ page }) => {
    // ...
  },
);

6. Ejemplos en otros módulos

Customers

tests/e2e/customers/create-customer.spec.ts
→ CUSTOMERS-CREATE-001
→ CUSTOMERS-CREATE-002

tests/e2e/customers/update-customer.spec.ts
→ CUSTOMERS-UPDATE-001

Ejemplos:

CUSTOMERS-CREATE-001
  Alta válida de cliente

CUSTOMERS-CREATE-002
  Validaciones de alta

CUSTOMERS-UPDATE-001
  Modificación válida de cliente

Customer Invoices

Para módulos grandes se permite añadir la bounded feature al identificador:

tests/e2e/customer-invoices/proformas/create-proforma.spec.ts
→ CUSTOMER-INVOICES-PROFORMA-CREATE-001

No deben introducirse abreviaturas arbitrarias diferentes para el mismo módulo.

Evitar mezclar, por ejemplo:

CUSTOMER-INVOICES-...
INVOICES-...
CI-...

salvo que en el futuro se acuerde formalmente una abreviatura estable.

7. Subdirectorios en módulos grandes

Un módulo grande puede subdividirse por bounded feature, pero el primer nivel bajo tests/e2e continúa siendo siempre el módulo propietario.

Ejemplo:

tests/e2e/customer-invoices/
├── proformas/
├── issued-invoices/
└── recurring-proformas/

Correcto:

tests/e2e/customer-invoices/proformas/
tests/e2e/customer-invoices/issued-invoices/
tests/e2e/customer-invoices/recurring-proformas/

Evitar:

tests/e2e/proformas/
tests/e2e/issued-invoices/
tests/e2e/recurring-proformas/

porque perdería la trazabilidad directa con:

modules/customer-invoices

8. Reglas de numeración

La numeración:

  • se reinicia por feature;
  • utiliza siempre tres dígitos: 001, 002, 003...;
  • identifica el caso, no su prioridad;
  • no determina el orden de ejecución;
  • no debe cambiar por reordenar tests dentro del fichero;
  • no debe reutilizarse para representar otro escenario funcional diferente.

Ejemplo:

IDENTITY-LOGIN-001
IDENTITY-LOGIN-002
IDENTITY-LOGIN-003

IDENTITY-ROUTES-001
IDENTITY-ROUTES-002

IDENTITY-LOGOUT-001

No usar una única secuencia global como:

IDENTITY-001
IDENTITY-002
IDENTITY-003
...

porque pierde información sobre la feature.

9. Naming del test

El identificador debe formar parte del título de test().

Correcto:

test("IDENTITY-LOGIN-002: rechazo de credenciales incorrectas", async ({
  page,
}) => {
  // ...
});

Evitar:

test("rechaza credenciales incorrectas", async ({ page }) => {
  // ...
});

si ese test pertenece al catálogo E2E formal.

El texto posterior al identificador debe describir el comportamiento desde el punto de vista funcional.

10. Localización de tests

La inclusión del identificador en el título permite localizar cualquier caso mediante búsqueda textual.

Ejemplo:

rg -n --glob "*.spec.ts" "IDENTITY-LOGIN-002" tests/e2e

Para localizar todos los casos de una feature:

rg -n --glob "*.spec.ts" "IDENTITY-LOGIN-" tests/e2e

Para obtener solo los ficheros:

rg -l --glob "*.spec.ts" "IDENTITY-LOGIN-002" tests/e2e

11. Convención de selectores E2E

Los tests no deben depender de textos traducidos.

Orden de preferencia:

1. id técnico estable
2. data-testid estable
3. atributo técnico estable, por ejemplo name
4. selector CSS técnico y estable, solo excepcionalmente

Ejemplos:

page.locator("#login-email");
page.getByTestId("login-submit");
page.locator('input[name="email"]');

Evitar como contrato principal:

page.getByText("Entrar");
page.getByLabel("Email");
page.getByRole("button", { name: "Entrar" });

porque esos textos pueden variar con el locale.

También evitar:

clases Tailwind visuales
nth-child
selectores dependientes de posición
estructura DOM incidental
IDs generados mediante React.useId()

Las clases CSS solo deben utilizarse excepcionalmente cuando sean clases técnicas deliberadamente estables, no clases de presentación.

12. Accesibilidad

La estrategia de selectores E2E no sustituye la accesibilidad.

Los componentes deben mantener correctamente:

label
htmlFor
role
aria-label
aria-describedby
aria-live

cuando corresponda.

Los atributos técnicos para testing son un contrato complementario.

13. Independencia de los tests

Cada caso E2E debe poder ejecutarse:

de forma aislada
en cualquier orden
junto con el resto de la suite

El identificador:

IDENTITY-LOGIN-002

no significa que el test dependa de:

IDENTITY-LOGIN-001

Los tests no deben depender del estado dejado por casos anteriores.

14. Relación entre directorio, fichero y caso

Regla general:

Directorio
→ módulo propietario

Fichero
→ feature o flujo funcional

Caso
→ MODULE-FEATURE-NNN

Ejemplo:

tests/e2e/identity/login.spec.ts
→ IDENTITY-LOGIN-001
→ IDENTITY-LOGIN-002

tests/e2e/identity/protected-routes.spec.ts
→ IDENTITY-ROUTES-001

tests/e2e/identity/logout.spec.ts
→ IDENTITY-LOGOUT-001

15. Criterio para nuevas features

Antes de crear un nuevo test:

  1. identificar el módulo propietario real bajo /modules;
  2. localizar o crear el fichero correspondiente al flujo funcional;
  3. determinar el nombre estable de la feature;
  4. asignar el siguiente NNN disponible dentro de esa feature;
  5. incluir el identificador completo en el título de test().

No crear nuevos prefijos para pequeñas variaciones del mismo flujo si no existe una diferencia funcional clara.

16. Regla mental final

tests/e2e/<module>/<feature>.spec.ts

<MODULE>-<FEATURE>-<NNN>

Ejemplo:

tests/e2e/identity/login.spec.ts
IDENTITY-LOGIN-001

La estructura física indica quién es propietario del comportamiento.

El fichero indica qué flujo se está probando.

El identificador indica qué caso funcional concreto se está ejecutando.