import { test, expect } from '@playwright/test' // 测试账号配置 const TEST_USERNAME = process.env.TEST_USERNAME || 'admin' const TEST_PASSWORD = process.env.TEST_PASSWORD || '123456' test.describe('登录登出测试', () => { test.beforeEach(async ({ page }) => { // 清除登录状态 await page.goto('/login') await page.evaluate(() => { localStorage.clear() document.cookie.split(';').forEach((c) => { document.cookie = c.replace(/^ +/, '').replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`) }) }) await page.reload() }) test('登录页面正确显示', async ({ page }) => { await expect(page.getByPlaceholder('用户名')).toBeVisible() await expect(page.getByPlaceholder('密码')).toBeVisible() await expect(page.getByRole('button', { name: '登录' })).toBeVisible() await expect(page.getByText('记住我')).toBeVisible() }) test('空表单提交显示验证错误', async ({ page }) => { await page.getByRole('button', { name: '登录' }).click() await expect(page.getByText('请输入用户名')).toBeVisible() await expect(page.getByText('请输入密码')).toBeVisible() }) test('错误密码登录失败', async ({ page }) => { await page.getByPlaceholder('用户名').fill(TEST_USERNAME) await page.getByPlaceholder('密码').fill('wrongpassword') const loginBtn = page.getByRole('button', { name: '登录' }) await loginBtn.click() // 等待一段时间后验证仍在登录页 await page.waitForTimeout(3000) await expect(page).toHaveURL(/\/login/) // 验证登录按钮恢复可用状态(加载结束) await expect(loginBtn).toBeEnabled() }) test('登录成功并显示用户名 admin', async ({ page }) => { // 输入登录信息 await page.getByPlaceholder('用户名').fill(TEST_USERNAME) await page.getByPlaceholder('密码').fill(TEST_PASSWORD) // 等待登录按钮可用并点击 const loginBtn = page.getByRole('button', { name: '登录' }) await expect(loginBtn).toBeEnabled() await loginBtn.click() // 等待登录 API 响应并跳转 await page.waitForURL(/^(?!.*\/login).*$/, { timeout: 15000 }) // 验证用户名显示为 admin (layout__username 类) await expect(page.locator('.layout__username')).toBeVisible({ timeout: 10000 }) await expect(page.locator('.layout__username')).toContainText('admin') }) test('记住我功能保存用户名', async ({ page }) => { // 确保记住我选中 const rememberCheckbox = page.locator('.login__checkbox') await rememberCheckbox.check() // 输入用户名并登录 await page.getByPlaceholder('用户名').fill(TEST_USERNAME) await page.getByPlaceholder('密码').fill(TEST_PASSWORD) await page.getByRole('button', { name: '登录' }).click() // 等待登录成功 await page.waitForURL(/^(?!.*\/login).*$/, { timeout: 15000 }) // 验证 localStorage 保存了用户名 const savedUsername = await page.evaluate(() => localStorage.getItem('login_remember')) expect(savedUsername).toBe(TEST_USERNAME) }) test('登录后可以正常登出', async ({ page }) => { // 先登录 await page.getByPlaceholder('用户名').fill(TEST_USERNAME) await page.getByPlaceholder('密码').fill(TEST_PASSWORD) const loginBtn = page.getByRole('button', { name: '登录' }) await expect(loginBtn).toBeEnabled() await loginBtn.click() await page.waitForURL(/^(?!.*\/login).*$/, { timeout: 15000 }) // 点击用户下拉菜单 (layout__user 类) await page.locator('.layout__user').click() await page.waitForTimeout(500) // 点击退出登录 await page.getByText('退出登录').first().click() // 验证跳转到登录页 await expect(page).toHaveURL(/\/login/, { timeout: 10000 }) }) test('修改密码弹窗可以打开', async ({ page }) => { // 先登录 await page.getByPlaceholder('用户名').fill(TEST_USERNAME) await page.getByPlaceholder('密码').fill(TEST_PASSWORD) const loginBtn = page.getByRole('button', { name: '登录' }) await expect(loginBtn).toBeEnabled() await loginBtn.click() await page.waitForURL(/^(?!.*\/login).*$/, { timeout: 15000 }) // 点击用户下拉菜单 await page.locator('.layout__user').click() await page.waitForTimeout(500) // 点击修改密码 await page.locator('.layout__dropdown-item').filter({ hasText: '修改密码' }).click() // 验证弹窗显示 await expect(page.getByRole('dialog')).toBeVisible() await expect(page.locator('.el-dialog__title')).toContainText('修改密码') }) test('密码显示/隐藏切换', async ({ page }) => { const passwordInput = page.getByPlaceholder('密码') const toggleBtn = page.locator('.login__password-toggle') // 默认是密码模式 await expect(passwordInput).toHaveAttribute('type', 'password') // 点击切换按钮显示密码 await toggleBtn.click() await expect(passwordInput).toHaveAttribute('type', 'text') // 再次点击隐藏密码 await toggleBtn.click() await expect(passwordInput).toHaveAttribute('type', 'password') }) })