ci(web): Phase P6 — vite build + headless E2E gate on every trunk merge (#1445) (#1454)
ci/woodpecker/push/publish Pipeline was successful

This commit was merged in pull request #1454.
This commit is contained in:
2026-08-27 15:26:10 +00:00
parent b5ee692843
commit e605c83b27
19 changed files with 592 additions and 120 deletions
+20 -28
View File
@@ -1,11 +1,14 @@
import { test, expect } from '@playwright/test';
import { loginAs, ADMIN_USER, TEST_USER } from './helpers/auth.js';
import { loginAs, ADMIN_USER, REQUIRE_SEEDED_AUTH, TEST_USER } from './helpers/auth.js';
test.describe('Admin page — admin user', () => {
test.beforeEach(async ({ page }) => {
await loginAs(page, ADMIN_USER.email, ADMIN_USER.password);
const url = page.url();
test.skip(!url.includes('/chat'), 'No seeded admin user — skipping admin tests');
test.skip(
!REQUIRE_SEEDED_AUTH && !url.includes('/chat'),
'No seeded admin user — skipping admin tests',
);
});
test('admin page loads with the Admin Panel heading', async ({ page }) => {
@@ -31,15 +34,11 @@ test.describe('Admin page — admin user', () => {
await page.goto('/admin');
await page.getByRole('button', { name: /system health/i }).click();
// Health cards or loading indicator should appear
const hasLoading = await page
const loadingOrCard = page
.getByText(/loading health/i)
.isVisible()
.catch(() => false);
const hasCard = await page
.getByText(/database/i)
.isVisible()
.catch(() => false);
expect(hasLoading || hasCard).toBe(true);
.or(page.getByText(/database/i))
.first();
await expect(loadingOrCard).toBeVisible({ timeout: 10_000 });
});
});
@@ -47,26 +46,19 @@ test.describe('Admin page — non-admin user', () => {
test.beforeEach(async ({ page }) => {
await loginAs(page, TEST_USER.email, TEST_USER.password);
const url = page.url();
test.skip(!url.includes('/chat'), 'No seeded test user — skipping non-admin tests');
test.skip(
!REQUIRE_SEEDED_AUTH && !url.includes('/chat'),
'No seeded test user — skipping non-admin tests',
);
});
test('non-admin visiting /admin sees access denied or is redirected', async ({ page }) => {
test('non-admin visiting /admin never sees the admin panel', async ({ page }) => {
await page.goto('/admin');
// Either redirected away or shown an access-denied message
const onAdmin = page.url().includes('/admin');
if (onAdmin) {
// Should show some access-denied content rather than the full admin panel
const hasPanel = await page
.getByRole('heading', { name: /admin panel/i })
.isVisible()
.catch(() => false);
// If heading is visible, the guard allowed access (user may have admin role in this env)
// — not a failure, just informational
if (!hasPanel) {
// access denied message, redirect, or guard placeholder
const url = page.url();
expect(url).toBeTruthy(); // environment-dependent — no hard assertion
}
}
// Wait for the app shell to render (redirect and access-denied views both
// keep the sidebar), then assert the panel itself is absent. globalSetup
// seeds TEST_USER with role 'member', so this is a real authorization
// assertion, not environment-dependent.
await expect(page.getByRole('img', { name: /mosaic logo/i })).toBeVisible({ timeout: 10_000 });
await expect(page.getByRole('heading', { name: /admin panel/i })).not.toBeVisible();
});
});