From 37315eca4c84fdf09b2a261dd5097747d03203e3 Mon Sep 17 00:00:00 2001 From: zichun Date: Mon, 1 Jun 2026 17:13:37 +0800 Subject: [PATCH] test(fe-shell): 应用外壳 E2E 关键旅程 REQ-USR-003 --- frontend/tests/e2e/shell.spec.ts | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+), 0 deletions(-) create mode 100644 frontend/tests/e2e/shell.spec.ts diff --git a/frontend/tests/e2e/shell.spec.ts b/frontend/tests/e2e/shell.spec.ts new file mode 100644 index 0000000..c369115 --- /dev/null +++ b/frontend/tests/e2e/shell.spec.ts @@ -0,0 +1,103 @@ +import { test, expect, type Page } from '@playwright/test'; + +// 桩后端:版本下拉 / 登录 / 用户列表(仅为标签挂载,不验列表内容)。不依赖真实后端起服。 +async function stubBackend(page: Page) { + await page.route('**/api/usr/companies', async (route) => { + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ + code: 0, + message: 'success', + data: [{ id: 1, sCompanyName: '甲公司', sVersion: '标准版' }], + }), + }); + }); + await page.route('**/api/usr/login', async (route) => { + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ + code: 0, + message: 'success', + data: { + token: 'tk-e2e', + user: { id: 1, sUserName: '朱子纯', sUserType: '超级管理员', sLanguage: '中文' }, + }, + }), + }); + }); + await page.route('**/api/usr/users**', async (route) => { + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ + code: 0, + message: 'success', + data: { records: [], total: 0, pageNum: 1, pageSize: 10 }, + }), + }); + }); +} + +async function login(page: Page) { + await page.goto('/login'); + await page.getByPlaceholder('请输入你的用户名').fill('admin'); + await page.getByPlaceholder('请输入你的密码').fill('secret'); + // 单一版本时 LoginPage 自动选中(spec § 6.3),无需手动展开下拉 + await expect(page.getByText('甲公司(标准版)')).toBeVisible(); + await page.getByRole('button', { name: /登\s*录/ }).click(); +} + +test.describe('应用外壳关键旅程', () => { + test('login then lands on home with topbar and KPI title', async ({ page }) => { + await stubBackend(page); + await login(page); + await expect(page).toHaveURL(/\/$/); + await expect(page.getByRole('button', { name: '全部导航' })).toBeVisible(); + await expect(page.getByText('KPI监控')).toBeVisible(); + }); + + test('open and close 全部导航 overlay', async ({ page }) => { + await stubBackend(page); + await login(page); + await page.getByRole('button', { name: '全部导航' }).click(); + await expect(page.getByTestId('nav-overlay')).toBeVisible(); + await expect(page.getByText('期初设置')).toBeVisible(); + await expect(page.getByText('API对接管理')).toBeVisible(); + // Esc 关闭 + await page.keyboard.press('Escape'); + await expect(page.getByTestId('nav-overlay')).toHaveCount(0); + }); + + test('open 用户列表 tab from common ops then close back to home', async ({ page }) => { + await stubBackend(page); + await login(page); + // 常用操作卡内「用户列表」 + await page.getByRole('button', { name: '用户列表' }).click(); + await expect(page).toHaveURL(/\/usr\/users$/); + await expect(page.getByTestId('tab-userlist')).toBeVisible(); + // 关闭用户列表标签 → 回主页 + await page.getByTestId('tab-close-userlist').click(); + await expect(page).toHaveURL(/\/$/); + await expect(page.getByTestId('tab-userlist')).toHaveCount(0); + }); + + test('logout returns to /login', async ({ page }) => { + await stubBackend(page); + await login(page); + await page.getByText('朱子纯(超级管理员)').click(); + await page.getByText('退出登录').click(); + await expect(page).toHaveURL(/\/login$/); + await expect(page.getByText('已退出登录')).toBeVisible(); + }); + + test('visiting / unauthenticated redirects to /login', async ({ page }) => { + await stubBackend(page); + // 不登录,清 token 后直接访问 / + await page.goto('/login'); + await page.evaluate(() => localStorage.removeItem('xly_erp_token')); + await page.goto('/'); + await expect(page).toHaveURL(/\/login$/); + }); +}); -- libgit2 0.22.2