licence-server/tests/e2e/license-crud.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

211 lines
8.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 selectProduct(page: Page, productCode: string) {
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 });
return;
}
}
}
test.describe('Forma za novu licencu', () => {
test.beforeEach(async ({ page }) => {
await login(page);
await page.goto('/licenses/new');
});
test('prikazuje naslov Nova licenca', async ({ page }) => {
await expect(page.locator('h1')).toHaveText('Nova licenca');
});
test('ima ispravan title', async ({ page }) => {
await expect(page).toHaveTitle('Nova licenca - Licence Server');
});
test('prikazuje sva polja forme', async ({ page }) => {
await expect(page.locator('select[name="product_id"]')).toBeVisible();
await expect(page.locator('select[name="license_type"]')).toBeVisible();
await expect(page.locator('input[name="customer_name"]')).toBeVisible();
await expect(page.locator('input[name="customer_pib"]')).toBeVisible();
await expect(page.locator('input[name="customer_email"]')).toBeVisible();
await expect(page.locator('input[name="limits"]')).toBeVisible();
await expect(page.locator('input[name="grace_days"]')).toBeVisible();
await expect(page.locator('textarea[name="notes"]')).toBeVisible();
});
test('customer_name je obavezan', async ({ page }) => {
await expect(page.locator('input[name="customer_name"]')).toHaveAttribute('required', '');
});
test('product_id je obavezan', async ({ page }) => {
await expect(page.locator('select[name="product_id"]')).toHaveAttribute('required', '');
});
test('license_type je obavezan', async ({ page }) => {
await expect(page.locator('select[name="license_type"]')).toHaveAttribute('required', '');
});
test('dropdown ima sve proizvode (min 3)', async ({ page }) => {
const options = page.locator('select[name="product_id"] option');
const count = await options.count();
expect(count).toBeGreaterThanOrEqual(3);
const texts = await options.allTextContents();
expect(texts.some(t => t.includes('ESIR'))).toBe(true);
expect(texts.some(t => t.includes('ARV'))).toBe(true);
expect(texts.some(t => t.includes('LIGHT_TICKET'))).toBe(true);
});
test('dropdown ima sve tipove licenci', async ({ page }) => {
const options = page.locator('select[name="license_type"] option');
const texts = await options.allTextContents();
expect(texts.join(' ')).toContain('Mesecna');
expect(texts.join(' ')).toContain('Godisnja');
expect(texts.join(' ')).toContain('Trajna');
expect(texts.join(' ')).toContain('Trial');
});
test('grace_days ima default 30', async ({ page }) => {
const val = await page.locator('input[name="grace_days"]').inputValue();
expect(val).toBe('30');
});
test('limits polje ima placeholder', async ({ page }) => {
await expect(page.locator('input[name="limits"]')).toHaveAttribute('placeholder', '{"max_operators": 3}');
});
test('email polje ima type email', async ({ page }) => {
await expect(page.locator('input[name="customer_email"]')).toHaveAttribute('type', 'email');
});
test('otkazi dugme vodi na listu licenci', async ({ page }) => {
await page.click('a:has-text("Otkazi")');
await expect(page).toHaveURL(/\/licenses$/);
});
test('forma ima POST method i ispravnu action', async ({ page }) => {
const form = page.locator('form.form-card');
await expect(form).toHaveAttribute('method', 'POST');
await expect(form).toHaveAttribute('action', '/licenses');
});
test('ima Kreiraj licencu dugme', async ({ page }) => {
await expect(page.locator('button:has-text("Kreiraj licencu")')).toBeVisible();
await expect(page.locator('button:has-text("Kreiraj licencu")')).toHaveClass(/btn-primary/);
});
});
test.describe('Kreiranje licence — svi proizvodi', () => {
test.beforeEach(async ({ page }) => {
await login(page);
});
test('kreiranje LIGHT_TICKET MONTHLY licence sa svim poljima', async ({ page }) => {
await page.goto('/licenses/new');
await selectProduct(page, 'LIGHT_TICKET');
await page.selectOption('select[name="license_type"]', 'MONTHLY');
await page.fill('input[name="customer_name"]', 'E2E Komplet Test DOO');
await page.fill('input[name="customer_pib"]', '111222333');
await page.fill('input[name="customer_email"]', 'komplet@test.rs');
await page.fill('input[name="limits"]', '{"max_operators": 5}');
await page.fill('input[name="grace_days"]', '15');
await page.fill('textarea[name="notes"]', 'Komplet E2E test sa svim poljima');
await page.click('button:has-text("Kreiraj licencu")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
const key = await page.locator('h1 code').textContent();
expect(key).toMatch(/^LT-/);
expect(key).toMatch(/^LT-[A-HJ-NP-Y2-9]{4}-[A-HJ-NP-Y2-9]{4}-[A-HJ-NP-Y2-9]{4}-[A-HJ-NP-Y2-9]{4}$/);
});
test('kreiranje LIGHT_TICKET PERPETUAL licence', async ({ page }) => {
await page.goto('/licenses/new');
await selectProduct(page, 'LIGHT_TICKET');
await page.selectOption('select[name="license_type"]', 'PERPETUAL');
await page.fill('input[name="customer_name"]', 'E2E Perpetual LT');
await page.click('button:has-text("Kreiraj licencu")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
// Perpetual treba da prikaze Neograniceno za istek
await expect(page.locator('td', { hasText: 'Neograniceno' })).toBeVisible();
});
test('kreiranje ARV ANNUAL licence', async ({ page }) => {
await page.goto('/licenses/new');
await selectProduct(page, 'ARV');
await page.selectOption('select[name="license_type"]', 'ANNUAL');
await page.fill('input[name="customer_name"]', 'E2E ARV Godisnja');
await page.fill('input[name="customer_email"]', 'arv@test.rs');
await page.click('button:has-text("Kreiraj licencu")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
const key = await page.locator('h1 code').textContent();
expect(key).toMatch(/^ARV-/);
});
test('kreiranje ARV TRIAL licence', async ({ page }) => {
await page.goto('/licenses/new');
await selectProduct(page, 'ARV');
await page.selectOption('select[name="license_type"]', 'TRIAL');
await page.fill('input[name="customer_name"]', 'E2E ARV Trial');
await page.click('button:has-text("Kreiraj licencu")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
});
test('kreiranje ESIR PERPETUAL licence', async ({ page }) => {
await page.goto('/licenses/new');
await selectProduct(page, 'ESIR');
await page.selectOption('select[name="license_type"]', 'PERPETUAL');
await page.fill('input[name="customer_name"]', 'E2E ESIR Prodavnica');
await page.fill('input[name="customer_pib"]', '555666777');
await page.click('button:has-text("Kreiraj licencu")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
const key = await page.locator('h1 code').textContent();
expect(key).toMatch(/^ESIR-/);
});
test('kreiranje ESIR MONTHLY licence', async ({ page }) => {
await page.goto('/licenses/new');
await selectProduct(page, 'ESIR');
await page.selectOption('select[name="license_type"]', 'MONTHLY');
await page.fill('input[name="customer_name"]', 'E2E ESIR Mesecna');
await page.click('button:has-text("Kreiraj licencu")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
});
test('kreirana licenca se pojavljuje u listi', async ({ page }) => {
const uniqueName = `E2E Lista Test ${Date.now()}`;
await page.goto('/licenses/new');
await selectProduct(page, 'LIGHT_TICKET');
await page.selectOption('select[name="license_type"]', 'MONTHLY');
await page.fill('input[name="customer_name"]', uniqueName);
await page.click('button:has-text("Kreiraj licencu")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
// Proveri da je u listi
await page.goto('/licenses');
await expect(page.locator('td', { hasText: uniqueName })).toBeVisible();
});
test('kreirana licenca ima status Aktivna', async ({ page }) => {
await page.goto('/licenses/new');
await selectProduct(page, 'LIGHT_TICKET');
await page.selectOption('select[name="license_type"]', 'MONTHLY');
await page.fill('input[name="customer_name"]', 'E2E Status Check');
await page.click('button:has-text("Kreiraj licencu")');
await expect(page).toHaveURL(/\/licenses\/\d+/);
await expect(page.locator('.badge.status-active')).toBeVisible();
});
});