oggui/ogWebconsole/e2e/helpers/api.ts

140 lines
5.3 KiB
TypeScript

/**
* Helpers para crear y borrar usuarios de test vía la API de ogCore.
* Se usan en globalSetup / globalTeardown de Playwright.
*/
import { Agent } from 'undici';
import * as fs from 'fs';
import * as path from 'path';
export const API_URL = process.env['API_URL'] || 'https://ogserver.local/api';
export const APP_URL = process.env['APP_URL'] || 'https://localhost:4200/oggui';
export const ADMIN_USER = process.env['ADMIN_USER'] || 'ogadmin';
export const ADMIN_PASS = process.env['ADMIN_PASS'] || '12345678';
export const TEST_PASS = 'Test1234!';
// Nombres fijos — sin timestamp para que sean consistentes entre procesos
export const TEST_USERS = {
superAdmin: { username: 'e2e-superadmin', role: 'ROLE_SUPER_ADMIN' },
ouAdmin: { username: 'e2e-ouadmin', role: 'ROLE_ORGANIZATIONAL_UNIT_ADMIN' },
operator: { username: 'e2e-operator', role: 'ROLE_ORGANIZATIONAL_UNIT_OPERATOR' },
minimal: { username: 'e2e-minimal', role: 'ROLE_ORGANIZATIONAL_UNIT_MINIMAL' },
};
// Fichero temporal para pasar IRIs del setup al teardown
const STATE_FILE = path.join(__dirname, '../../.e2e-state.json');
// undici Agent que ignora certificados autofirmados (equivalente a curl -k)
const insecureAgent = new Agent({ connect: { rejectUnauthorized: false } });
async function fetchJson(url: string, init: RequestInit): Promise<any> {
const res = await fetch(url, {
...init,
headers: { 'Content-Type': 'application/ld+json', ...(init.headers as any) },
dispatcher: insecureAgent,
} as any);
const text = await res.text();
try { return JSON.parse(text); } catch { return text; }
}
export async function getAdminToken(): Promise<string> {
const data = await fetchJson(`${API_URL}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: ADMIN_USER, password: ADMIN_PASS }),
});
if (!data.token) throw new Error(`Login fallido: ${JSON.stringify(data)}`);
return data.token;
}
async function findUserByUsername(token: string, username: string): Promise<string | null> {
const data = await fetchJson(`${API_URL}/users?username=${encodeURIComponent(username)}`, {
method: 'GET',
headers: { Authorization: `Bearer ${token}` },
});
const members = data['hydra:member'] ?? [];
return members.length > 0 ? members[0]['@id'] : null;
}
async function findUserGroupByName(token: string, name: string): Promise<string | null> {
const data = await fetchJson(`${API_URL}/user-groups?name=${encodeURIComponent(name)}`, {
method: 'GET',
headers: { Authorization: `Bearer ${token}` },
});
const members = data['hydra:member'] ?? [];
return members.length > 0 ? members[0]['@id'] : null;
}
async function deleteResource(token: string, iri: string): Promise<void> {
await fetch(`${API_URL.replace('/api', '')}${iri}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${token}` },
dispatcher: insecureAgent,
} as any);
}
async function createUserGroup(token: string, role: string, name: string): Promise<string> {
const data = await fetchJson(`${API_URL}/user-groups`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
body: JSON.stringify({ name, permissions: [role], enabled: true }),
});
if (!data['@id']) throw new Error(`No se pudo crear UserGroup ${name}: ${JSON.stringify(data)}`);
return data['@id'];
}
async function createUser(token: string, username: string, ugIri: string): Promise<string> {
const data = await fetchJson(`${API_URL}/users`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
body: JSON.stringify({ username, password: TEST_PASS, enabled: true, userGroups: [ugIri] }),
});
if (!data['@id']) throw new Error(`No se pudo crear usuario ${username}: ${JSON.stringify(data)}`);
return data['@id'];
}
export async function setupTestUsers(): Promise<void> {
const token = await getAdminToken();
const userIris: string[] = [];
const ugIris: string[] = [];
for (const { username, role } of Object.values(TEST_USERS)) {
const ugName = `e2e-ug-${username}`;
// Eliminar usuario previo si existe (limpia runs anteriores)
const existingUser = await findUserByUsername(token, username);
if (existingUser) {
await deleteResource(token, existingUser);
console.log(` ↺ Eliminado usuario previo: ${username}`);
}
// Eliminar UserGroup previo si existe
const existingUg = await findUserGroupByName(token, ugName);
if (existingUg) {
await deleteResource(token, existingUg);
}
const ugIri = await createUserGroup(token, role, ugName);
const userIri = await createUser(token, username, ugIri);
ugIris.push(ugIri);
userIris.push(userIri);
console.log(` ✓ ${username} [${role}]`);
}
// Guarda IRIs en fichero para que teardown pueda leerlos (env vars no siempre pasan entre procesos)
fs.writeFileSync(STATE_FILE, JSON.stringify({ userIris, ugIris }, null, 2));
}
export async function teardownTestUsers(): Promise<void> {
if (!fs.existsSync(STATE_FILE)) return;
const { userIris, ugIris } = JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'));
const token = await getAdminToken();
for (const iri of [...userIris, ...ugIris]) {
await deleteResource(token, iri);
console.log(` ✓ Eliminado: ${iri}`);
}
fs.unlinkSync(STATE_FILE);
}