| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- import { test, expect } from '@playwright/test';
- import { TenantLoginPage } from '../pages/tenant/tenant-login.page';
- import { TenantFileManagementPage } from '../pages/tenant/tenant-file-management.page';
- /**
- * E2E测试:租户后台统一文件管理UI交互
- *
- * 目的:验证租户后台的文件管理功能在实际浏览器环境中能够正常工作
- * 覆盖:登录、导航、CRUD操作、文件上传、选择器集成、删除等所有交互场景
- *
- * ## 测试前置条件
- *
- * 1. 数据库中存在测试租户(tenant_id=1)
- * 2. 数据库中存在测试超级管理员(username=admin, password=admin123)
- * 3. 测试环境可访问(http://localhost:8080 或 E2E_BASE_URL 指定的环境)
- * 4. MinIO服务正常运行
- *
- * ## 测试数据准备
- *
- * ```sql
- * -- 创建测试租户
- * INSERT INTO tenant_mt (id, name, code, status, created_at, updated_at)
- * VALUES (1, '测试租户', 'test-tenant', 1, NOW(), NOW());
- *
- * -- 创建测试超级管理员 (密码: admin123)
- * INSERT INTO users_mt (id, tenant_id, username, password, registration_source, is_disabled, is_deleted, created_at, updated_at)
- * VALUES (1, 1, 'admin', '$2b$10$x3t2kofPmACnk6y6lfL6ouU836LBEuZE9BinQ3ZzA4Xd04izyY42K', 'web', 0, 0, NOW(), NOW());
- * ```
- */
- // 测试配置
- const BASE_URL = process.env.E2E_BASE_URL || 'http://localhost:8080';
- const TEST_USERNAME = process.env.TEST_USERNAME || 'superadmin';
- const TEST_PASSWORD = process.env.TEST_PASSWORD || 'admin123';
- test.describe('租户后台统一文件管理UI交互测试', () => {
- let loginPage: TenantLoginPage;
- let fileManagementPage: TenantFileManagementPage;
- // 每个测试前清除状态并登录
- test.beforeEach(async ({ page }) => {
- // 清除localStorage和cookies,确保干净的测试状态
- await page.context().clearCookies();
- await page.goto('/tenant/login');
- await page.evaluate(() => {
- localStorage.clear();
- sessionStorage.clear();
- });
- loginPage = new TenantLoginPage(page);
- fileManagementPage = new TenantFileManagementPage(page);
- // 导航到登录页并登录
- await page.goto('/tenant/login');
- await loginPage.goto();
- await loginPage.login(TEST_USERNAME, TEST_PASSWORD);
- await loginPage.expectLoginSuccess();
- });
- test.describe('任务1: 登录流程测试', () => {
- test('应该成功登录并跳转到租户控制台', async ({ page }) => {
- await expect(page).toHaveURL(/\/tenant\/dashboard/);
- await expect(page.getByRole('heading', { name: /租户控制台|仪表盘|Dashboard/i })).toBeVisible();
- });
- });
- test.describe('任务2: 导航测试', () => {
- test('应该能够导航到文件管理页面', async ({ page }) => {
- // 点击文件管理菜单项
- const fileMenu = page.getByRole('link', { name: /文件管理/i });
- await expect(fileMenu).toBeVisible();
- await fileMenu.click();
- // 验证URL和页面标题
- await expect(page).toHaveURL(/\/tenant\/files/);
- await expect(page.getByRole('heading', { name: /文件管理/i })).toBeVisible();
- });
- test('文件管理菜单项应该在导航栏中可见', async ({ page }) => {
- // 验证文件管理菜单存在
- await expect(page.getByRole('link', { name: /文件管理/i })).toBeVisible();
- });
- });
- test.describe('任务3: 文件列表展示测试', () => {
- test('应该显示文件管理页面标题', async ({ page }) => {
- await fileManagementPage.goto();
- await expect(fileManagementPage.pageTitle).toBeVisible();
- });
- test('应该显示文件列表表格', async ({ page }) => {
- await fileManagementPage.goto();
- await expect(fileManagementPage.table).toBeVisible();
- });
- test('应该显示搜索输入框', async ({ page }) => {
- await fileManagementPage.goto();
- await expect(fileManagementPage.searchInput).toBeVisible();
- });
- });
- test.describe('任务4: 文件搜索测试', () => {
- test('应该能够按文件名搜索', async ({ page }) => {
- await fileManagementPage.goto();
- // 搜索存在的文件
- await fileManagementPage.search('test');
- // 等待搜索结果
- await page.waitForTimeout(500);
- // 验证搜索结果(可能为空,但功能应该工作)
- const fileCount = await fileManagementPage.getFileCount();
- expect(fileCount).toBeGreaterThanOrEqual(0);
- });
- test('应该清空搜索显示所有文件', async ({ page }) => {
- await fileManagementPage.goto();
- // 先搜索
- await fileManagementPage.search('test');
- await page.waitForTimeout(500);
- // 清空搜索
- await fileManagementPage.searchInput.fill('');
- await fileManagementPage.searchButton.click();
- await page.waitForTimeout(500);
- // 验证返回到列表视图
- await expect(fileManagementPage.table).toBeVisible();
- });
- });
- test.describe('任务5: 文件上传测试', () => {
- test('应该显示上传文件按钮', async ({ page }) => {
- await fileManagementPage.goto();
- await expect(fileManagementPage.createButton).toBeVisible();
- });
- test('点击上传按钮应该打开上传对话框', async ({ page }) => {
- await fileManagementPage.goto();
- await fileManagementPage.clickUpload();
- // 验证上传对话框显示
- await expect(page.getByRole('dialog')).toBeVisible({ timeout: 3000 });
- });
- });
- test.describe('任务6: 文件编辑测试', () => {
- test('应该能够点击编辑按钮(如果有文件)', async ({ page }) => {
- await fileManagementPage.goto();
- const fileCount = await fileManagementPage.getFileCount();
- if (fileCount > 0) {
- // 如果有文件,点击第一行的编辑按钮
- const firstRow = page.getByRole('row').nth(1);
- const editButton = firstRow.getByRole('button', { name: /编辑/i });
- if (await editButton.isVisible()) {
- await editButton.click();
- // 验证编辑对话框显示
- await expect(page.getByRole('dialog')).toBeVisible({ timeout: 3000 });
- }
- }
- });
- });
- test.describe('任务7: 文件删除测试', () => {
- test('应该能够点击删除按钮(如果有文件)', async ({ page }) => {
- await fileManagementPage.goto();
- const fileCount = await fileManagementPage.getFileCount();
- if (fileCount > 0) {
- // 如果有文件,点击第一行的删除按钮
- const firstRow = page.getByRole('row').nth(1);
- const deleteButton = firstRow.getByRole('button', { name: /删除/i });
- if (await deleteButton.isVisible()) {
- // 获取第一行文件名用于后续验证
- const fileNameCell = firstRow.getByRole('cell').first();
- const fileName = await fileNameCell.textContent();
- await deleteButton.click();
- // 验证确认对话框显示
- await expect(page.getByRole('dialog')).toBeVisible({ timeout: 3000 });
- // 取消删除以保持测试数据
- await fileManagementPage.cancelDelete();
- }
- }
- });
- test('应该能够取消删除操作', async ({ page }) => {
- await fileManagementPage.goto();
- const fileCount = await fileManagementPage.getFileCount();
- if (fileCount > 0) {
- const firstRow = page.getByRole('row').nth(1);
- const deleteButton = firstRow.getByRole('button', { name: /删除/i });
- if (await deleteButton.isVisible()) {
- await deleteButton.click();
- await fileManagementPage.cancelDelete();
- // 验证对话框关闭
- await expect(page.getByRole('dialog')).not.toBeVisible({ timeout: 3000 });
- }
- }
- });
- });
- test.describe('任务8: 文件选择器集成测试', () => {
- test('应该能够在广告创建页面看到文件选择器', async ({ page }) => {
- // 导航到广告管理页面
- await page.goto('/tenant/unified-advertisements');
- // 点击创建广告按钮
- const createButton = page.getByRole('button', { name: /创建|新建|添加/i }).first();
- if (await createButton.isVisible()) {
- await createButton.click();
- // 等待对话框打开
- await page.waitForTimeout(500);
- // 验证文件选择器存在(通过查找包含"图片"的label)
- const imageLabel = page.getByRole('label', { name: /图片|广告图/i });
- if (await imageLabel.isVisible()) {
- // 文件选择器应该有一个包含"file-selector"测试ID的元素
- await expect(page.getByTestId('file-selector')).toBeVisible({ timeout: 3000 });
- }
- }
- });
- });
- test.describe('任务9: 分页测试', () => {
- test('应该显示分页组件(如果有足够数据)', async ({ page }) => {
- await fileManagementPage.goto();
- await page.waitForTimeout(500);
- const fileCount = await fileManagementPage.getFileCount();
- if (fileCount > 10) {
- // 如果有超过10条记录,应该显示分页
- await expect(fileManagementPage.pagination).toBeVisible();
- }
- });
- });
- test.describe('任务10: 错误处理测试', () => {
- test('应该显示错误提示当API请求失败时', async ({ page }) => {
- // 这个测试需要模拟网络失败或API错误
- // 在实际E2E环境中可能需要额外设置
- await fileManagementPage.goto();
- await page.waitForTimeout(500);
- // 验证页面正常加载(无错误状态)
- await expect(fileManagementPage.pageTitle).toBeVisible();
- });
- });
- });
|