diff --git a/e2e/diag-phase5-smoke.cjs b/e2e/diag-phase5-smoke.cjs new file mode 100644 index 000000000..6f636fefa --- /dev/null +++ b/e2e/diag-phase5-smoke.cjs @@ -0,0 +1,117 @@ +// Phase 5 smoke test: verify Tabler layout, BS5 modal shim, and core navigation +// Tests: login, dashboard loads, modal opens/closes, case page loads, no JS errors +const { chromium } = require('@playwright/test'); +const fs = require('node:fs'); +const dotenv = require('dotenv'); + +const BASE = process.env.BASE_URL || 'https://127.0.0.1:8443'; +const env = dotenv.parse(fs.readFileSync('../.env')); +const PASS = env.IRIS_ADM_PASSWORD; + +let errors = 0; +function ok(label) { console.log(` ✓ ${label}`); } +function fail(label, msg) { console.error(` ✗ ${label}: ${msg}`); errors++; } + +(async () => { + const browser = await chromium.launch({ args: ['--ignore-certificate-errors'] }); + const ctx = await browser.newContext({ ignoreHTTPSErrors: true }); + const page = await ctx.newPage(); + + const jsErrors = []; + page.on('pageerror', e => jsErrors.push(e.message)); + + try { + // 1. Login + console.log('\n[1] Login'); + await page.goto(BASE + '/'); + await page.getByRole('textbox', { name: 'Username' }).fill('administrator'); + await page.getByRole('textbox', { name: 'Password' }).fill(PASS); + await page.getByRole('button', { name: 'Sign in' }).click(); + await page.waitForURL('**/dashboard**', { timeout: 15000 }); + ok('login and redirect to dashboard'); + + // 2. Tabler layout loaded (check for .page container from 5.1) + console.log('\n[2] Tabler layout'); + const pageDiv = await page.$('div.page'); + pageDiv ? ok('div.page container present (Tabler)') : fail('Tabler container', 'div.page not found — Atlantis .wrapper still in DOM?'); + + // Check tabler.min.css loaded (check for a Tabler-specific CSS class presence) + const tablerLink = await page.$('link[href*="tabler.min.css"]'); + tablerLink ? ok('tabler.min.css link present') : fail('tabler.min.css', 'link tag not found in head'); + + // Check Atlantis CSS is gone + const atlantisLink = await page.$('link[href*="atlantis.css"]'); + !atlantisLink ? ok('atlantis.css removed') : fail('atlantis.css', 'still loaded — not removed from layout'); + + // 3. JS errors so far + console.log('\n[3] JS errors after login'); + const criticalErrors = jsErrors.filter(e => + e.includes('TypeError') || e.includes('is not a function') || e.includes('is not defined') + ); + criticalErrors.length === 0 + ? ok('no TypeError/undefined JS errors on login+dashboard') + : fail('JS errors', criticalErrors.slice(0, 3).join(' | ')); + jsErrors.length = 0; + + // 4. Navigate to case 1 and test modal shim + console.log('\n[4] Case page + modal shim'); + await page.goto(BASE + '/case?cid=1', { timeout: 15000 }); + await page.waitForLoadState('networkidle', { timeout: 15000 }); + ok('case page loaded'); + + // Trigger a modal via the BS5 shim — click "Add task" button + const addTaskBtn = page.getByRole('button', { name: 'Add task' }); + if (await addTaskBtn.isVisible({ timeout: 5000 }).catch(() => false)) { + await addTaskBtn.click(); + // Modal heading should appear + const heading = page.getByRole('heading', { name: 'Add task' }); + const visible = await heading.isVisible({ timeout: 5000 }).catch(() => false); + visible ? ok('modal opens via BS5 shim (Add task)') : fail('modal shim', 'Add task modal heading not visible after click'); + + // Close modal + const closeBtn = page.locator('.modal.show .btn-close').first(); + if (await closeBtn.isVisible({ timeout: 3000 }).catch(() => false)) { + await closeBtn.click(); + const gone = await heading.isHidden({ timeout: 5000 }).catch(() => false); + gone ? ok('modal closes via btn-close (data-bs-dismiss)') : fail('modal close', 'modal still visible after btn-close click'); + } + } else { + console.log(' ~ Add task button not found on case page (case may not have tasks tab visible)'); + } + + // 5. Case notes page (ext layout with Milkdown) + console.log('\n[5] Case notes ext layout'); + await page.goto(BASE + '/case/notes?cid=1', { timeout: 15000 }); + await page.waitForLoadState('networkidle', { timeout: 15000 }); + const extPageDiv = await page.$('div.page'); + extPageDiv ? ok('default_ext layout: div.page container present') : fail('ext layout', 'div.page not found on notes page'); + + // 6. JS errors on case pages + console.log('\n[6] JS errors on case pages'); + const caseErrors = jsErrors.filter(e => + e.includes('TypeError') || e.includes('is not a function') || e.includes('is not defined') + ); + caseErrors.length === 0 + ? ok('no critical JS errors on case pages') + : fail('JS errors on case', caseErrors.slice(0, 3).join(' | ')); + + // 7. Manage page (checks data-bs-toggle in navigation) + console.log('\n[7] Manage page'); + await page.goto(BASE + '/manage/cases', { timeout: 15000 }); + await page.waitForLoadState('networkidle', { timeout: 10000 }); + ok('manage/cases page loaded'); + + } catch (e) { + fail('unexpected error', e.message); + } finally { + await browser.close(); + } + + console.log(`\n${'─'.repeat(50)}`); + if (errors === 0) { + console.log('Phase 5 smoke: ALL PASS'); + } else { + console.log(`Phase 5 smoke: ${errors} FAILURE(S) — see above`); + process.exit(1); + } +})(); diff --git a/e2e/playwright.config.js b/e2e/playwright.config.js index b557a7709..8fd0561de 100644 --- a/e2e/playwright.config.js +++ b/e2e/playwright.config.js @@ -50,7 +50,7 @@ module.exports = defineConfig({ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ - baseURL: 'https://localhost', + baseURL: process.env.BASE_URL || 'https://localhost', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', diff --git a/source/app/blueprints/pages/dashboard/templates/index.html b/source/app/blueprints/pages/dashboard/templates/index.html index 006230fbb..ae72b59cf 100644 --- a/source/app/blueprints/pages/dashboard/templates/index.html +++ b/source/app/blueprints/pages/dashboard/templates/index.html @@ -5,8 +5,9 @@ {% block stylesheets %} + - + {% endblock stylesheets %} {% block content %} @@ -39,7 +40,7 @@