diff --git a/web/e2e/namespace-delete.spec.ts b/web/e2e/namespace-delete.spec.ts index 6c100848..a68820aa 100644 --- a/web/e2e/namespace-delete.spec.ts +++ b/web/e2e/namespace-delete.spec.ts @@ -1,9 +1,15 @@ import type { Page } from '@playwright/test' import { expect, test } from '@playwright/test' import { setEnglishLocale } from './helpers/auth-fixtures' -import { registerSession } from './helpers/session' +import { loginWithCredentials } from './helpers/session' import { E2eTestDataBuilder, type SeededNamespace } from './helpers/test-data-builder' +function getAdminCredentials() { + const username = process.env.E2E_ADMIN_USERNAME ?? process.env.BOOTSTRAP_ADMIN_USERNAME ?? 'admin' + const password = process.env.E2E_ADMIN_PASSWORD ?? process.env.BOOTSTRAP_ADMIN_PASSWORD ?? 'ChangeMe!2026' + return { username, password } +} + async function archiveNamespaceViaApi(page: Page, slug: string): Promise { const response = await page.context().request.post( `/api/web/namespaces/${encodeURIComponent(slug)}/archive`, @@ -20,18 +26,23 @@ function namespaceCard(page: Page, namespace: SeededNamespace) { .first() } +// Namespace lifecycle ties archive and delete to the OWNER role, and only +// SKILL_ADMIN/SUPER_ADMIN can create a TEAM namespace via the portal API. +// Since there is no REST endpoint to transfer ownership to a regular E2E user, +// we run this spec under the admin account so the created namespace belongs to +// the acting session (creator becomes OWNER automatically). test.describe('Namespace Delete (Real API)', () => { - test.beforeEach(async ({ page }, testInfo) => { + test.beforeEach(async ({ page }) => { await setEnglishLocale(page) - await registerSession(page, testInfo) }) test('delete button only visible after namespace is archived', async ({ page }, testInfo) => { + await loginWithCredentials(page, getAdminCredentials(), testInfo) const builder = new E2eTestDataBuilder(page, testInfo) await builder.init() try { - const namespace = await builder.ensureWritableNamespace() + const namespace = await builder.createNamespace('e2e-delete') await page.goto('/dashboard/namespaces') await expect(page.getByText(`@${namespace.slug}`)).toBeVisible() @@ -52,11 +63,12 @@ test.describe('Namespace Delete (Real API)', () => { }) test('delete confirm button stays disabled until reason is provided', async ({ page }, testInfo) => { + await loginWithCredentials(page, getAdminCredentials(), testInfo) const builder = new E2eTestDataBuilder(page, testInfo) await builder.init() try { - const namespace = await builder.ensureWritableNamespace() + const namespace = await builder.createNamespace('e2e-delete') await archiveNamespaceViaApi(page, namespace.slug) await page.goto('/dashboard/namespaces') @@ -79,11 +91,12 @@ test.describe('Namespace Delete (Real API)', () => { }) test('successfully deletes an archived namespace', async ({ page }, testInfo) => { + await loginWithCredentials(page, getAdminCredentials(), testInfo) const builder = new E2eTestDataBuilder(page, testInfo) await builder.init() try { - const namespace = await builder.ensureWritableNamespace() + const namespace = await builder.createNamespace('e2e-delete') await archiveNamespaceViaApi(page, namespace.slug) await page.goto('/dashboard/namespaces')