dal-license-server/tests/e2e/api-client.spec.ts
djuka 5a046110f0 Dodao Playwright E2E testove i azurirao CLAUDE.md
- 7 E2E test fajlova (54 testa ukupno):
  - login.spec.ts: prijava, pogresna lozinka, redirect bez sesije
  - dashboard.spec.ts: statistike, navbar, odjava, root redirect
  - licenses.spec.ts: tabela, filteri, pretraga
  - license-crud.spec.ts: forma, kreiranje LT/ARV/ESIR licence
  - license-detail.spec.ts: informacije, aktivacije, audit, revoke, force release
  - audit.spec.ts: audit log stranica, kolone, generisanje zapisa
  - api-client.spec.ts: activate, deactivate, validate, revoke flow, API key auth
- CLAUDE.md: dodato pravilo o rigoroznom testiranju

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 07:50:43 +00:00

257 lines
8.0 KiB
TypeScript

import { test, expect } from '@playwright/test';
const BASE = 'http://localhost:8090';
const API_KEY = 'dev-api-key-minimum-32-characters-long';
test.describe('Klijentski API', () => {
let licenseKey: string;
test.beforeAll(async ({ request }) => {
// Kreiraj licencu za testove
const res = await request.post(`${BASE}/api/v1/admin/licenses`, {
headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' },
data: {
product_id: 3, // LIGHT_TICKET
license_type: 'MONTHLY',
customer_name: 'API Test Firma',
customer_email: 'api@test.rs',
limits: { max_operators: 3 },
features: ['TICKET_VALIDATION', 'REPORTS'],
grace_days: 30,
},
});
expect(res.status()).toBe(201);
const body = await res.json();
licenseKey = body.license_key;
expect(licenseKey).toMatch(/^LT-/);
});
test('aktivacija licence', async ({ request }) => {
const res = await request.post(`${BASE}/api/v1/activate`, {
data: {
license_key: licenseKey,
machine_fingerprint: 'sha256:e2e-test-fingerprint-001',
app_version: '1.0.0',
os: 'linux',
hostname: 'E2E-TEST-PC',
},
});
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.license).toBeDefined();
expect(body.signature).toBeDefined();
expect(body.signature).toMatch(/^RSA-SHA256:/);
expect(body.license.product).toBe('LIGHT_TICKET');
expect(body.license.license_type).toBe('MONTHLY');
expect(body.license.customer.name).toBe('API Test Firma');
});
test('ponovna aktivacija sa istim fingerprint-om (refresh)', async ({ request }) => {
const res = await request.post(`${BASE}/api/v1/activate`, {
data: {
license_key: licenseKey,
machine_fingerprint: 'sha256:e2e-test-fingerprint-001',
app_version: '1.0.0',
os: 'linux',
hostname: 'E2E-TEST-PC',
},
});
expect(res.status()).toBe(200);
});
test('aktivacija sa drugog racunara — odbijeno', async ({ request }) => {
const res = await request.post(`${BASE}/api/v1/activate`, {
data: {
license_key: licenseKey,
machine_fingerprint: 'sha256:drugi-racunar-002',
app_version: '1.0.0',
os: 'windows',
hostname: 'DRUGI-PC',
},
});
expect(res.status()).toBe(400);
const body = await res.json();
expect(body.error.code).toBe('ALREADY_ACTIVATED');
});
test('validacija aktivne licence', async ({ request }) => {
const res = await request.post(`${BASE}/api/v1/validate`, {
data: {
license_key: licenseKey,
machine_fingerprint: 'sha256:e2e-test-fingerprint-001',
},
});
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.valid).toBe(true);
expect(body.revoked).toBe(false);
});
test('deaktivacija licence', async ({ request }) => {
const res = await request.post(`${BASE}/api/v1/deactivate`, {
data: {
license_key: licenseKey,
machine_fingerprint: 'sha256:e2e-test-fingerprint-001',
},
});
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.can_reactivate).toBe(true);
});
test('re-aktivacija sa novog racunara posle deaktivacije', async ({ request }) => {
const res = await request.post(`${BASE}/api/v1/activate`, {
data: {
license_key: licenseKey,
machine_fingerprint: 'sha256:novi-racunar-003',
app_version: '1.0.1',
os: 'windows',
hostname: 'NOVI-PC',
},
});
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.license.machine_fingerprint).toBe('sha256:novi-racunar-003');
});
test('aktivacija sa nepostojecim kljucem', async ({ request }) => {
const res = await request.post(`${BASE}/api/v1/activate`, {
data: {
license_key: 'LT-FAKE-KEY1-KEY2-KEY3',
machine_fingerprint: 'sha256:test',
app_version: '1.0.0',
os: 'linux',
hostname: 'TEST',
},
});
expect(res.status()).toBe(400);
const body = await res.json();
expect(body.error.code).toBe('INVALID_KEY');
});
test('validacija nepostojeceg kljuca', async ({ request }) => {
const res = await request.post(`${BASE}/api/v1/validate`, {
data: {
license_key: 'LT-NEMA-OVOG-KLUC-AAAA',
machine_fingerprint: 'sha256:test',
},
});
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.valid).toBe(false);
});
});
test.describe('Admin API autentifikacija', () => {
test('bez API kljuca — 401', async ({ request }) => {
const res = await request.get(`${BASE}/api/v1/admin/licenses`);
expect(res.status()).toBe(401);
});
test('pogresan API kljuc — 401', async ({ request }) => {
const res = await request.get(`${BASE}/api/v1/admin/licenses`, {
headers: { 'X-API-Key': 'pogresan-kljuc' },
});
expect(res.status()).toBe(401);
});
test('ispravan API kljuc — 200', async ({ request }) => {
const res = await request.get(`${BASE}/api/v1/admin/licenses`, {
headers: { 'X-API-Key': API_KEY },
});
expect(res.status()).toBe(200);
});
test('products endpoint', async ({ request }) => {
const res = await request.get(`${BASE}/api/v1/admin/products`, {
headers: { 'X-API-Key': API_KEY },
});
expect(res.status()).toBe(200);
const body = await res.json();
expect(Array.isArray(body)).toBe(true);
expect(body.length).toBeGreaterThanOrEqual(3);
});
test('stats endpoint', async ({ request }) => {
const res = await request.get(`${BASE}/api/v1/admin/stats`, {
headers: { 'X-API-Key': API_KEY },
});
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.total_licenses).toBeDefined();
expect(body.by_product).toBeDefined();
});
test('audit endpoint', async ({ request }) => {
const res = await request.get(`${BASE}/api/v1/admin/audit`, {
headers: { 'X-API-Key': API_KEY },
});
expect(res.status()).toBe(200);
const body = await res.json();
expect(Array.isArray(body)).toBe(true);
});
test('health endpoint', async ({ request }) => {
const res = await request.get(`${BASE}/api/v1/health`);
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.status).toBe('ok');
});
});
test.describe('Admin API — Revoke flow', () => {
let licenseId: number;
let licenseKey: string;
test.beforeAll(async ({ request }) => {
const res = await request.post(`${BASE}/api/v1/admin/licenses`, {
headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' },
data: {
product_id: 3,
license_type: 'MONTHLY',
customer_name: 'Revoke Flow Test',
grace_days: 30,
},
});
const body = await res.json();
licenseId = body.id;
licenseKey = body.license_key;
});
test('revoke licence', async ({ request }) => {
const res = await request.post(`${BASE}/api/v1/admin/licenses/${licenseId}/revoke`, {
headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' },
data: { reason: 'E2E test revoke' },
});
expect(res.status()).toBe(200);
});
test('aktivacija opozvane licence — odbijeno', async ({ request }) => {
const res = await request.post(`${BASE}/api/v1/activate`, {
data: {
license_key: licenseKey,
machine_fingerprint: 'sha256:revoke-test',
app_version: '1.0.0',
os: 'linux',
hostname: 'TEST',
},
});
expect(res.status()).toBe(400);
const body = await res.json();
expect(body.error.code).toBe('KEY_REVOKED');
});
test('validacija opozvane licence', async ({ request }) => {
const res = await request.post(`${BASE}/api/v1/validate`, {
data: {
license_key: licenseKey,
machine_fingerprint: 'sha256:revoke-test',
},
});
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.valid).toBe(false);
expect(body.revoked).toBe(true);
});
});