|
- import fs from 'node:fs'
- import path from 'node:path'
-
- import type { APIRequestContext, Locator, Page } from '@playwright/test'
-
- import { expect } from './fixtures'
-
- export interface AdminCredentials { username: string; password: string }
-
- export function readAdminCredentials(): AdminCredentials {
- const configured = process.env.E2E_ACCOUNT_FILE?.trim()
- const filename = path.resolve(configured || '../账号.MD')
- if (!fs.existsSync(filename)) throw new Error(`测试账号文件不存在:${filename}`)
- const values = new Map<string, string>()
- for (const line of fs.readFileSync(filename, 'utf8').split(/\r?\n/)) {
- const match = line.match(/^\s*([^::]+)\s*[::]\s*(.*?)\s*$/)
- if (match?.[1] && match[2]) values.set(match[1].trim(), match[2].trim())
- }
- const username = values.get('账号') || values.get('用户名') || ''
- const password = values.get('密码') || ''
- if (!username || !password) throw new Error('账号.MD 必须包含“账号”和“密码”两项')
- return { username, password }
- }
-
- type RecordValue = Record<string, unknown>
- const asRecord = (value: unknown): RecordValue => value && typeof value === 'object' ? value as RecordValue : {}
- export const envelopeData = <T = unknown>(value: unknown): T => {
- const body = asRecord(value)
- return ('data' in body ? body.data : value) as T
- }
-
- export async function adminAccessToken(request: APIRequestContext) {
- const credentials = readAdminCredentials()
- const response = await request.post('/api/auth/v1/auth/login', {
- data: { roleCode: 'admin', username: credentials.username, password: credentials.password, rememberMe: false },
- })
- expect(response.ok(), `管理员 API 登录失败:HTTP ${response.status()}`).toBeTruthy()
- const data = asRecord(envelopeData(await response.json()))
- const tokens = asRecord(data.tokens)
- const accessToken = String(data.accessToken ?? tokens.accessToken ?? '')
- if (!accessToken) throw new Error('管理员登录响应缺少 accessToken')
- return accessToken
- }
-
- export async function authHeaders(request: APIRequestContext) {
- const accessToken = await adminAccessToken(request)
- return { Authorization: `Bearer ${accessToken}` }
- }
-
- export async function loginAsAdmin(page: Page) {
- const credentials = readAdminCredentials()
- await page.goto('/login')
- await page.locator('[data-role-code="admin"]').click()
- const username = page.locator('input[name="username"]')
- const password = page.locator('input[name="password"]')
- await username.fill(credentials.username)
- await password.fill(credentials.password)
- await page.getByRole('button', { name: /登录系统|正在验证身份/ }).click()
- await expect(page).not.toHaveURL(/\/login(?:\?|$)/)
- await expect(page.locator('.app-shell, .main-layout, .platform-shell').first()).toBeVisible()
- }
-
- export const visibleDialog = (page: Page) => page.locator('.el-dialog:visible').last()
- export const formItem = (scope: Locator, label: string | RegExp) => scope.locator('.el-form-item').filter({ hasText: label }).first()
-
- export async function fillFormItem(scope: Locator, label: string | RegExp, value: string) {
- const control = formItem(scope, label).locator('input:not([type="hidden"]), textarea').first()
- await expect(control).toBeVisible()
- await control.fill(value)
- }
-
- export async function chooseSelectOption(page: Page, scope: Locator, label: string | RegExp, option: string | RegExp) {
- const item = formItem(scope, label)
- await item.locator('.el-select').click()
- const dropdown = page.locator('.el-select-dropdown:visible').last()
- await expect(dropdown).toBeVisible()
- await dropdown.locator('.el-select-dropdown__item').filter({ hasText: option }).first().click()
- }
-
- export async function confirmMessageBox(page: Page, buttonName: string | RegExp) {
- const box = page.locator('.el-message-box:visible').last()
- await expect(box).toBeVisible()
- await box.getByRole('button', { name: buttonName }).click()
- }
-
- export const tableRowByText = (page: Page, text: string) => page
- .locator('.el-table__body-wrapper .el-table__row, tbody tr')
- .filter({ hasText: text })
- .first()
|