From f61ce71daa998f5169e4bbe015cadead41f7f0f6 Mon Sep 17 00:00:00 2001 From: dongmucat <1127093059@qq.com> Date: Mon, 22 Jun 2026 17:22:19 +0800 Subject: [PATCH] test(web): ISSUE-61 cover security settings real requests Signed-off-by: dongmucat <1127093059@qq.com> --- web/e2e/settings-pages.spec.ts | 6 +- web/e2e/settings-security-capability.spec.ts | 102 +++++++------------ 2 files changed, 38 insertions(+), 70 deletions(-) diff --git a/web/e2e/settings-pages.spec.ts b/web/e2e/settings-pages.spec.ts index de2abd6e..38f28760 100644 --- a/web/e2e/settings-pages.spec.ts +++ b/web/e2e/settings-pages.spec.ts @@ -1,11 +1,13 @@ import { expect, test } from '@playwright/test' import { setEnglishLocale } from './helpers/auth-fixtures' -import { registerSession } from './helpers/session' +import { createFreshSession } from './helpers/session' test.describe('Settings Pages (Real API)', () => { + test.use({ baseURL: 'http://127.0.0.1:3000' }) + test.beforeEach(async ({ page }, testInfo) => { await setEnglishLocale(page) - await registerSession(page, testInfo) + await createFreshSession(page, testInfo) }) test('opens profile settings page', async ({ page }) => { diff --git a/web/e2e/settings-security-capability.spec.ts b/web/e2e/settings-security-capability.spec.ts index 30d94ea8..b2d45910 100644 --- a/web/e2e/settings-security-capability.spec.ts +++ b/web/e2e/settings-security-capability.spec.ts @@ -1,93 +1,50 @@ import { expect, test, type Page } from '@playwright/test' import { setEnglishLocale } from './helpers/auth-fixtures' +import { csrfHeaders } from './helpers/csrf' +import { loginWithCredentials } from './helpers/session' -interface MockSessionUser { - userId: string - displayName: string - email: string - avatarUrl: string - oauthProvider: string - canChangePassword: boolean - platformRoles: string[] +function getOptionalEnv(name: string): string | undefined { + const value = process.env[name]?.trim() + return value ? value : undefined } -function apiEnvelope(data: unknown) { +function adminCredentials() { return { - code: 0, - msg: 'OK', - data, - timestamp: new Date().toISOString(), - requestId: 'e2e-security-capability', + username: getOptionalEnv('E2E_ADMIN_USERNAME') ?? getOptionalEnv('BOOTSTRAP_ADMIN_USERNAME') ?? 'admin', + password: getOptionalEnv('E2E_ADMIN_PASSWORD') ?? getOptionalEnv('BOOTSTRAP_ADMIN_PASSWORD') ?? 'ChangeMe!2026', } } -async function mockSession(page: Page, user: MockSessionUser) { - await page.route('**/api/v1/auth/me', async (route) => { - await route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify(apiEnvelope(user)), - }) - }) - - await page.route('**/api/web/me/namespaces', async (route) => { - await route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify(apiEnvelope([])), - }) - }) - - await page.route('**/api/web/notifications/unread-count', async (route) => { - await route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify(apiEnvelope({ count: 0 })), - }) - }) - - await page.route('**/api/web/notifications/sse', async (route) => { - await route.fulfill({ - status: 200, - contentType: 'text/event-stream', - body: ': ok\n\n', - }) - }) +async function currentDisplayName(page: Page, headers?: Record): Promise { + const response = await page.context().request.get('/api/v1/auth/me', { headers }) + expect(response.ok()).toBeTruthy() + const body = await response.json() as { data: { displayName: string } } + return body.data.displayName } -test.describe('Security Settings capability', () => { - test('shows the security menu entry and password form for local admin accounts', async ({ page }) => { +test.describe('Security Settings capability (Real API)', () => { + test.use({ baseURL: 'http://127.0.0.1:3000' }) + + test('shows the security menu entry and password form for local admin accounts', async ({ page }, testInfo) => { await setEnglishLocale(page) - await mockSession(page, { - userId: 'local-admin', - displayName: 'Local Admin', - email: 'local-admin@example.test', - avatarUrl: '', - oauthProvider: '', - canChangePassword: true, - platformRoles: ['USER', 'SUPER_ADMIN'], - }) + await loginWithCredentials(page, adminCredentials(), testInfo) + const displayName = await currentDisplayName(page) await page.goto('/settings/security') await expect(page.getByRole('heading', { name: 'Security Settings' })).toBeVisible() await expect(page.getByLabel('Current Password')).toBeVisible() await expect(page.getByLabel('New Password')).toBeVisible() - await page.getByRole('button', { name: 'Local Admin' }).click() + await page.getByRole('button', { name: displayName }).click() await expect(page.getByRole('link', { name: 'Security Settings' })).toBeVisible() }) - test('hides the security menu entry and form when password changes are unavailable', async ({ page }) => { + test('hides the security menu entry and rejects password changes without a local credential', async ({ page }) => { await setEnglishLocale(page) - await mockSession(page, { - userId: 'oauth-only-user', - displayName: 'OAuth Only User', - email: 'oauth-only@example.test', - avatarUrl: '', - oauthProvider: 'github', - canChangePassword: false, - platformRoles: ['USER'], + await page.context().setExtraHTTPHeaders({ + 'X-Mock-User-Id': 'local-user', }) + const displayName = await currentDisplayName(page, { 'X-Mock-User-Id': 'local-user' }) await page.goto('/settings/security') @@ -96,7 +53,16 @@ test.describe('Security Settings capability', () => { await expect(page.getByLabel('Current Password')).toHaveCount(0) await expect(page.getByRole('button', { name: 'Update Password' })).toHaveCount(0) - await page.getByRole('button', { name: 'OAuth Only User' }).click() + await page.getByRole('button', { name: displayName }).click() await expect(page.getByRole('link', { name: 'Security Settings' })).toHaveCount(0) + + const response = await page.context().request.post('/api/v1/auth/local/change-password', { + data: { + currentPassword: 'Passw0rd!123', + newPassword: 'N3wPassw0rd!123', + }, + headers: await csrfHeaders(page, { 'X-Mock-User-Id': 'local-user' }), + }) + expect(response.status()).toBe(400) }) })