licence-server/tests/e2e/license-detail.spec.ts
Nenad Djukic 1abe7176ec Preimenovanje: dal-license-server -> licence-server (+ debrendiranje)
Vlasnik izlazi iz DAL price za ovaj projekat - postaje samostalan proizvod.
Preimenovanje je mehanicko (import putanje, imena fajlova/baze/UI naslova),
NIJEDNA linija poslovne logike u internal/handler ili internal/service nije
dirana - go build, go vet i go test ./... prolaze cisto pod novim imenom.

- go.mod: module dal-license-server -> licence-server; 28 import linija u
  13 .go fajlova usaglaseno
- internal/config/config.go (+test): default DB_NAME licence_db
- HTML sabloni (7 stranica) + 7 Playwright e2e spec fajlova: "DAL License
  Server" -> "Licence Server" u title/nav-brand, testovi usaglaseni u istom
  prolazu (nista ne moze da se razdvoji)
- package.json/package-lock.json/.gitignore/.claude/project.json: ime
  projekta/binarnog fajla/work_dir
- Usput: package.json je u repository.url nosio OTVORENU Gitea lozinku u
  cistom tekstu - uklonjena (URL sad bez kredencijala). Lozinka je i dalje
  u staroj git istoriji - preporuka: rotirati je posebno.
- CLAUDE.md/README/API/TESTING/docs/SPEC/ARCHITECTURE/SETUP: naslovi, ASCII
  dijagrami, git clone URL, mysqldump primer, systemd predlozak u SETUP.md
  zamenjen stvarnim (obrazac terminia.service - journal log + graceful
  shutdown, ne stari minimalni predlozak)
- Debrendiranje: "Univerzalni licencni server za sve DAL proizvode" ->
  "za vise proizvoda i klijenata"; potpis "Nenad Djukic / DAL d.o.o." ->
  "Nenad Djukic". NE dirano: nazivi ESIR/ARV/LIGHT_TICKET (tudji proizvodi,
  ne DAL brend), "DAL" kao stvaran naziv org-a u RBAC modelu
  (docs/loggerservice/README.md) - to je podatak, ne branding ovog servera.
- docs/asp-terminia/, docs/loggerservice/: prozni pomeni imena servera

Baza (dal_license_db -> licence_db) i deploy na 151 idu u posebnom koraku,
posle preimenovanja Gitea repoa - vidi CLAUDE.md istorijsku belesku na dnu.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 07:55:26 +02:00

239 lines
9.8 KiB
TypeScript

import { test, expect, Page } from '@playwright/test';
async function login(page: Page) {
await page.goto('/login');
await page.fill('input[name="username"]', 'admin');
await page.fill('input[name="password"]', 'admin123');
await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/dashboard/);
}
async function createLicense(page: Page, customerName: string, productCode = 'LIGHT_TICKET', licenseType = 'MONTHLY'): Promise<string> {
await page.goto('/licenses/new');
const productSelect = page.locator('select[name="product_id"]');
const options = productSelect.locator('option');
const count = await options.count();
for (let i = 0; i < count; i++) {
const text = await options.nth(i).textContent();
if (text && text.includes(productCode)) {
await productSelect.selectOption({ index: i });
break;
}
}
await page.selectOption('select[name="license_type"]', licenseType);
await page.fill('input[name="customer_name"]', customerName);
await page.click('button:has-text("Kreiraj licencu")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
return page.url();
}
test.describe('Detalji licence — informacije', () => {
test.beforeEach(async ({ page }) => {
await login(page);
});
test('prikazuje licencni kljuc u naslovu', async ({ page }) => {
await createLicense(page, 'Detail Info Test');
await expect(page.locator('h1 code')).toBeVisible();
const key = await page.locator('h1 code').textContent();
expect(key).toMatch(/^LT-/);
});
test('prikazuje status badge', async ({ page }) => {
await createLicense(page, 'Status Badge Test');
await expect(page.locator('.page-header .badge')).toBeVisible();
});
test('prikazuje sekciju Informacije', async ({ page }) => {
await createLicense(page, 'Info Section Test');
await expect(page.locator('h3', { hasText: 'Informacije' })).toBeVisible();
await expect(page.locator('.detail-table')).toBeVisible();
});
test('prikazuje sve informacione polja', async ({ page }) => {
await createLicense(page, 'All Fields Test');
const table = page.locator('.detail-table');
await expect(table.locator('td', { hasText: 'Proizvod' })).toBeVisible();
await expect(table.locator('td', { hasText: 'Tip' })).toBeVisible();
await expect(table.locator('td', { hasText: 'Firma' })).toBeVisible();
await expect(table.locator('td', { hasText: 'Izdata' })).toBeVisible();
await expect(table.locator('td', { hasText: 'Istice' })).toBeVisible();
await expect(table.locator('td', { hasText: 'Grace period' })).toBeVisible();
await expect(table.locator('td', { hasText: 'Limiti' })).toBeVisible();
await expect(table.locator('td', { hasText: 'Features' })).toBeVisible();
});
test('prikazuje ispravne podatke za LT licencu', async ({ page }) => {
await createLicense(page, 'LT Data Check');
const detailText = await page.locator('.detail-table').textContent();
expect(detailText).toContain('LIGHT_TICKET');
expect(detailText).toContain('MONTHLY');
expect(detailText).toContain('LT Data Check');
expect(detailText).toContain('30 dana');
});
test('prikazuje ispravne podatke za ARV licencu', async ({ page }) => {
await createLicense(page, 'ARV Data Check', 'ARV', 'ANNUAL');
const detailText = await page.locator('.detail-table').textContent();
expect(detailText).toContain('ARV');
expect(detailText).toContain('ANNUAL');
});
test('PERPETUAL prikazuje Neograniceno', async ({ page }) => {
await createLicense(page, 'Perpetual Check', 'ESIR', 'PERPETUAL');
await expect(page.locator('td', { hasText: 'Neograniceno' })).toBeVisible();
});
test('ima ispravan title sa kljucem', async ({ page }) => {
await createLicense(page, 'Title Check');
const title = await page.title();
expect(title).toContain('LT-');
expect(title).toContain('Licence Server');
});
});
test.describe('Detalji licence — aktivacije i audit', () => {
test.beforeEach(async ({ page }) => {
await login(page);
});
test('prikazuje tabelu aktivacija', async ({ page }) => {
await createLicense(page, 'Activation Table Test');
await expect(page.locator('h2', { hasText: 'Aktivacije' })).toBeVisible();
});
test('nova licenca nema aktivacija', async ({ page }) => {
await createLicense(page, 'No Activations Test');
await expect(page.locator('td', { hasText: 'Nema aktivacija' })).toBeVisible();
});
test('tabela aktivacija ima ispravne kolone', async ({ page }) => {
await createLicense(page, 'Activation Cols Test');
const table = page.locator('table').nth(1); // druga tabela
const headers = table.locator('thead th');
await expect(headers.nth(0)).toHaveText('Hostname');
await expect(headers.nth(1)).toHaveText('OS');
await expect(headers.nth(2)).toHaveText('Verzija');
await expect(headers.nth(3)).toHaveText('IP');
});
test('prikazuje audit log za licencu', async ({ page }) => {
await createLicense(page, 'Audit Log Test');
await expect(page.locator('h2', { hasText: 'Audit Log' })).toBeVisible();
});
test('kreiranje licence generise CREATE audit zapis', async ({ page }) => {
await createLicense(page, 'Create Audit Test');
await expect(page.locator('.badge', { hasText: 'CREATE' })).toBeVisible();
});
test('audit tabela ima ispravne kolone', async ({ page }) => {
await createLicense(page, 'Audit Cols Test');
const table = page.locator('table').last();
const headers = table.locator('thead th');
await expect(headers.nth(0)).toHaveText('Vreme');
await expect(headers.nth(1)).toHaveText('Akcija');
await expect(headers.nth(2)).toHaveText('IP');
await expect(headers.nth(3)).toHaveText('Detalji');
});
});
test.describe('Detalji licence — akcije', () => {
test.beforeEach(async ({ page }) => {
await login(page);
});
test('prikazuje sekciju Akcije', async ({ page }) => {
await createLicense(page, 'Actions Section Test');
await expect(page.locator('h3', { hasText: 'Akcije' })).toBeVisible();
});
test('prikazuje dugme za opoziv', async ({ page }) => {
await createLicense(page, 'Revoke Button Test');
await expect(page.locator('button:has-text("Opozovi licencu")')).toBeVisible();
await expect(page.locator('button:has-text("Opozovi licencu")')).toHaveClass(/btn-danger/);
});
test('prikazuje dugme za force release', async ({ page }) => {
await createLicense(page, 'Release Button Test');
await expect(page.locator('button:has-text("Force Release")')).toBeVisible();
await expect(page.locator('button:has-text("Force Release")')).toHaveClass(/btn-warning/);
});
test('prikazuje polje za razlog opoziva', async ({ page }) => {
await createLicense(page, 'Reason Field Test');
await expect(page.locator('input[name="reason"]')).toBeVisible();
await expect(page.locator('input[name="reason"]')).toHaveAttribute('placeholder', 'Razlog opoziva');
});
test('revoke licence menja status na Opozvana', async ({ page }) => {
await createLicense(page, 'Revoke Status Test');
page.on('dialog', dialog => dialog.accept());
await page.fill('input[name="reason"]', 'E2E test razlog');
await page.click('button:has-text("Opozovi licencu")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
await expect(page.locator('.badge.status-revoked')).toBeVisible();
});
test('revoke generise REVOKE audit zapis', async ({ page }) => {
await createLicense(page, 'Revoke Audit Test');
page.on('dialog', dialog => dialog.accept());
await page.fill('input[name="reason"]', 'Audit test');
await page.click('button:has-text("Opozovi licencu")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
await expect(page.locator('.badge', { hasText: 'REVOKE' })).toBeVisible();
});
test('posle revoke-a dugme za opoziv nestaje', async ({ page }) => {
await createLicense(page, 'Revoke Hide Test');
page.on('dialog', dialog => dialog.accept());
await page.click('button:has-text("Opozovi licencu")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
await expect(page.locator('button:has-text("Opozovi licencu")')).toHaveCount(0);
});
test('posle revoke-a force release dugme ostaje', async ({ page }) => {
await createLicense(page, 'Revoke FR Test');
page.on('dialog', dialog => dialog.accept());
await page.click('button:has-text("Opozovi licencu")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
await expect(page.locator('button:has-text("Force Release")')).toBeVisible();
});
test('force release funkcionise', async ({ page }) => {
await createLicense(page, 'Force Release Test');
page.on('dialog', dialog => dialog.accept());
await page.click('button:has-text("Force Release")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
});
test('force release generise FORCE_RELEASE audit zapis', async ({ page }) => {
await createLicense(page, 'FR Audit Test');
page.on('dialog', dialog => dialog.accept());
await page.click('button:has-text("Force Release")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
await expect(page.locator('.badge', { hasText: 'FORCE_RELEASE' })).toBeVisible();
});
});
test.describe('Detalji licence — navigacija', () => {
test.beforeEach(async ({ page }) => {
await login(page);
});
test('klik na licencu iz liste otvara detalje', async ({ page }) => {
await createLicense(page, 'Navigation Test');
await page.goto('/licenses');
const link = page.locator('a:has(code)').first();
await link.click();
await expect(page).toHaveURL(/\/licenses\/\d+/);
await expect(page.locator('h1 code')).toBeVisible();
});
test('navbar licence link je aktivan na detalj stranici', async ({ page }) => {
await createLicense(page, 'Navbar Active Test');
const link = page.locator('a[href="/licenses"]');
await expect(link).toHaveClass(/active/);
});
});