8.2 KiB
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 en001dentro 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:
- identificar el módulo propietario real bajo
/modules; - localizar o crear el fichero correspondiente al flujo funcional;
- determinar el nombre estable de la feature;
- asignar el siguiente
NNNdisponible dentro de esa feature; - 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.