chore: remove portal from admin app — extracted to fiberops-portal (FIBEROPS-249)

- Delete app/(portal)/ route group (login, dashboard, invoices, tickets)
- Delete lib/portal-api.ts and lib/portal-auth-store.ts
- Remove Phase 9 portal tests (17–22) from business-flow E2E spec
- Keep portalAccessEnabled in Client type and admin client profile view
This commit is contained in:
2026-04-01 03:30:18 +00:00
parent ff90ed9fa0
commit a6e13e611c
8 changed files with 3 additions and 854 deletions

View File

@@ -2,7 +2,7 @@ import { test, expect, Page } from '@playwright/test';
/**
* FIBEROPS-248: Full business flow E2E
* Simulates complete ISP business day — admin ops + subscriber portal
* Simulates complete ISP business day — admin ops (tests 116)
*
* Seed data (pre-created via API):
* Plan: Basic 25Mbps (₱999, POSTPAID)
@@ -11,15 +11,14 @@ import { test, expect, Page } from '@playwright/test';
* Invoice: INV-2026-000015
* Ticket: "No internet connection"
* Lead: Maria Reyes
* Portal: ACC-000029 / Portal123!
*
* Note: Subscriber portal tests (1722) live in the fiberops-portal repo.
*/
const BASE = 'http://192.168.1.167:3002';
const TENANT_SLUG = 'demo-isp';
const ADMIN_EMAIL = 'admin@demo-isp.com';
const ADMIN_PASSWORD = 'Admin123!';
const PORTAL_ACCOUNT = 'ACC-000029';
const PORTAL_PASSWORD = 'Portal123!';
async function adminLogin(page: Page) {
await page.goto(`${BASE}/login`);
@@ -281,108 +280,3 @@ test('16. Audit Log — page renders', async ({ page }) => {
await expect(page.locator('body')).toBeVisible();
});
// ─── Phase 9: Subscriber Portal ──────────────────────────────────────────────
test('17. Portal — login page renders with FiberOps branding', async ({ page }) => {
await page.goto(`${BASE}/portal/login`);
await page.waitForTimeout(2000);
await expect(page.locator('text=FiberOps').first()).toBeVisible();
await expect(page.locator('input[type="password"]')).toBeVisible();
});
test('18. Portal — rejects wrong credentials', async ({ page }) => {
await page.goto(`${BASE}/portal/login`);
await page.waitForTimeout(2000);
await page.locator('input[placeholder*="demo-isp"], input').nth(0).fill(TENANT_SLUG);
await page.locator('input[placeholder*="ACC"], input').nth(1).fill(PORTAL_ACCOUNT);
await page.locator('input[type="password"]').fill('wrongpassword');
await page.locator('button:has-text("Sign In")').click();
await page.waitForTimeout(3000);
// Should stay on login, show error
expect(page.url()).toContain('portal');
await expect(page.locator('text=failed, text=invalid, text=error').first()).toBeVisible({ timeout: 5000 }).catch(() => {
// Error may appear differently — just check no dashboard redirect
expect(page.url()).not.toContain('dashboard');
});
});
test('19. Portal — login succeeds with correct credentials', async ({ page }) => {
await page.goto(`${BASE}/portal/login`);
await page.waitForTimeout(2000);
// 3 inputs: ISP Code, Account Number, Password
const inputs = page.locator('input');
await inputs.nth(0).fill(TENANT_SLUG);
await inputs.nth(1).fill(PORTAL_ACCOUNT);
await inputs.nth(2).fill(PORTAL_PASSWORD);
await page.locator('button:has-text("Sign In")').click();
await expect(page).toHaveURL(/portal\/dashboard/, { timeout: 15000 });
});
test('20. Portal dashboard — shows account info', async ({ page }) => {
await page.goto(`${BASE}/portal/login`);
await page.waitForTimeout(2000);
const inputs = page.locator('input');
await inputs.nth(0).fill(TENANT_SLUG);
await inputs.nth(1).fill(PORTAL_ACCOUNT);
await inputs.nth(2).fill(PORTAL_PASSWORD);
await page.locator('button:has-text("Sign In")').click();
await page.waitForURL(/portal\/dashboard/, { timeout: 15000 });
await page.waitForTimeout(2000);
// Should show subscriber name or account
await expect(page.locator('text=Juan, text=ACC-000029, text=Basic 25Mbps').first()).toBeVisible({ timeout: 8000 }).catch(() => {
// At least the dashboard rendered
expect(page.url()).toContain('dashboard');
});
});
test('21. Portal invoices — page loads while authenticated', async ({ page }) => {
await page.goto(`${BASE}/portal/login`);
await page.waitForTimeout(2000);
const inputs = page.locator('input');
await inputs.nth(0).fill(TENANT_SLUG);
await inputs.nth(1).fill(PORTAL_ACCOUNT);
await inputs.nth(2).fill(PORTAL_PASSWORD);
await page.locator('button:has-text("Sign In")').click();
await page.waitForURL(/portal\/dashboard/, { timeout: 15000 });
await page.goto(`${BASE}/portal/invoices`);
await page.waitForTimeout(2000);
// Should not redirect back to login
expect(page.url()).not.toContain('/portal/login');
await expect(page.locator('body')).toBeVisible();
});
test('22. Portal tickets — page loads and can raise new ticket', async ({ page }) => {
await page.goto(`${BASE}/portal/login`);
await page.waitForTimeout(2000);
const inputs = page.locator('input');
await inputs.nth(0).fill(TENANT_SLUG);
await inputs.nth(1).fill(PORTAL_ACCOUNT);
await inputs.nth(2).fill(PORTAL_PASSWORD);
await page.locator('button:has-text("Sign In")').click();
await page.waitForURL(/portal\/dashboard/, { timeout: 15000 });
await page.goto(`${BASE}/portal/tickets`);
await page.waitForTimeout(2000);
expect(page.url()).not.toContain('/portal/login');
// Try raising a ticket
const newBtn = page.locator('button:has-text("New"), button:has-text("Raise"), button:has-text("Create")').first();
if (await newBtn.isVisible({ timeout: 3000 }).catch(() => false)) {
await newBtn.click();
await page.waitForTimeout(1000);
const subjectField = page.getByLabel('Subject').first();
if (await subjectField.isVisible({ timeout: 2000 }).catch(() => false)) {
await subjectField.fill('Internet slow today');
await page.locator('button:has-text("Submit"), button:has-text("Create"), button[type=submit]').last().click();
await page.waitForTimeout(2000);
}
}
await expect(page.locator('body')).toBeVisible();
});