| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- import { test, expect } from '@playwright/test';
- test.describe('地点管理E2E测试', () => {
- test.beforeEach(async ({ page }) => {
- // 登录到管理后台
- await page.goto('/admin/login');
- await page.fill('input[name="username"]', 'admin');
- await page.fill('input[name="password"]', 'admin');
- await page.click('button[type="submit"]');
- // 等待登录完成并跳转到仪表板
- await page.waitForURL('/admin/dashboard');
- // 导航到地点管理页面
- await page.goto('/admin/locations');
- await page.waitForLoadState('networkidle');
- });
- test('应该正确显示地点管理页面', async ({ page }) => {
- // 验证页面标题
- await expect(page.getByRole('heading', { name: '地点管理' })).toBeVisible();
- // 验证新建地点按钮
- await expect(page.getByRole('button', { name: '新建地点' })).toBeVisible();
- // 验证搜索框
- await expect(page.getByPlaceholder('搜索地点名称或地址...')).toBeVisible();
- // 验证筛选器
- await expect(page.getByPlaceholder('选择区域')).toBeVisible();
- await expect(page.getByPlaceholder('状态筛选')).toBeVisible();
- // 验证表格列标题
- await expect(page.getByText('地点名称')).toBeVisible();
- await expect(page.getByText('地址')).toBeVisible();
- await expect(page.getByText('所属区域')).toBeVisible();
- await expect(page.getByText('坐标')).toBeVisible();
- await expect(page.getByText('状态')).toBeVisible();
- await expect(page.getByText('创建时间')).toBeVisible();
- await expect(page.getByText('操作')).toBeVisible();
- });
- test('应该能够搜索地点', async ({ page }) => {
- // 在搜索框中输入关键词
- const searchInput = page.getByPlaceholder('搜索地点名称或地址...');
- await searchInput.fill('北京');
- // 等待搜索结果加载
- await page.waitForTimeout(500);
- // 验证搜索结果包含相关地点
- await expect(page.getByText('北京')).toBeVisible();
- });
- test('应该能够按区域筛选地点', async ({ page }) => {
- // 点击区域筛选器
- const areaFilter = page.getByPlaceholder('选择区域');
- await areaFilter.click();
- // 等待选项加载
- await page.waitForTimeout(500);
- // 验证区域选项存在
- await expect(page.getByText('全部区域')).toBeVisible();
- // 选择第一个区域选项
- const firstAreaOption = page.locator('[role="option"]').first();
- if (await firstAreaOption.isVisible()) {
- await firstAreaOption.click();
- // 等待筛选结果加载
- await page.waitForTimeout(500);
- // 验证筛选后的结果
- await expect(page.locator('tbody tr')).toBeVisible();
- }
- });
- test('应该能够按状态筛选地点', async ({ page }) => {
- // 点击状态筛选器
- const statusFilter = page.getByPlaceholder('状态筛选');
- await statusFilter.click();
- // 等待选项加载
- await page.waitForTimeout(500);
- // 验证状态选项存在
- await expect(page.getByText('全部状态')).toBeVisible();
- await expect(page.getByText('启用')).toBeVisible();
- await expect(page.getByText('禁用')).toBeVisible();
- // 选择"启用"状态
- await page.getByText('启用').click();
- // 等待筛选结果加载
- await page.waitForTimeout(500);
- // 验证筛选后的结果
- await expect(page.locator('tbody tr')).toBeVisible();
- });
- test('应该能够打开新建地点模态框', async ({ page }) => {
- // 点击新建地点按钮
- await page.getByRole('button', { name: '新建地点' }).click();
- // 验证模态框显示
- await expect(page.getByRole('heading', { name: '新建地点' })).toBeVisible();
- // 验证表单字段存在
- await expect(page.getByLabel('地点名称')).toBeVisible();
- await expect(page.getByLabel('地址')).toBeVisible();
- await expect(page.getByLabel('经度')).toBeVisible();
- await expect(page.getByLabel('纬度')).toBeVisible();
- // 关闭模态框
- await page.keyboard.press('Escape');
- // 验证模态框关闭
- await expect(page.getByRole('heading', { name: '新建地点' })).not.toBeVisible();
- });
- test('应该能够查看地点详情', async ({ page }) => {
- // 等待地点列表加载
- await page.waitForSelector('tbody tr');
- // 获取第一个地点的名称
- const firstLocationName = page.locator('tbody tr td').first();
- const locationName = await firstLocationName.textContent();
- // 验证地点名称显示
- expect(locationName).toBeTruthy();
- // 验证地址显示
- const addressCell = page.locator('tbody tr td:nth-child(2)').first();
- const address = await addressCell.textContent();
- expect(address).toBeTruthy();
- // 验证区域信息显示
- const areaCell = page.locator('tbody tr td:nth-child(3)').first();
- await expect(areaCell.locator('[data-radix-collection-item]')).toBeVisible();
- // 验证状态显示
- const statusCell = page.locator('tbody tr td:nth-child(5)').first();
- await expect(statusCell.getByText(/启用|禁用/)).toBeVisible();
- });
- test('应该能够分页浏览地点', async ({ page }) => {
- // 等待分页控件加载
- await page.waitForSelector('button:has-text("上一页"), button:has-text("下一页")');
- // 验证分页信息显示
- await expect(page.getByText(/显示第.*条,共.*条记录/)).toBeVisible();
- // 尝试点击下一页(如果可用)
- const nextButton = page.getByRole('button', { name: '下一页' });
- if (await nextButton.isEnabled()) {
- await nextButton.click();
- // 等待下一页数据加载
- await page.waitForTimeout(500);
- // 验证页面更新
- await expect(page.locator('tbody tr')).toBeVisible();
- }
- });
- test('应该能够编辑地点', async ({ page }) => {
- // 等待地点列表加载
- await page.waitForSelector('tbody tr');
- // 查找编辑按钮并点击
- const editButtons = page.locator('button').filter({ has: page.locator('svg[data-lucide="edit"]') });
- if (await editButtons.first().isVisible()) {
- await editButtons.first().click();
- // 验证编辑模态框显示
- await expect(page.getByRole('heading', { name: '编辑地点' })).toBeVisible();
- // 关闭模态框
- await page.keyboard.press('Escape');
- }
- });
- test('应该能够切换地点状态', async ({ page }) => {
- // 等待地点列表加载
- await page.waitForSelector('tbody tr');
- // 查找启用/禁用按钮
- const toggleButtons = page.getByRole('button').filter({ hasText: /禁用|启用/ });
- if (await toggleButtons.first().isVisible()) {
- // 点击切换状态按钮
- await toggleButtons.first().click();
- // 处理确认对话框
- page.on('dialog', dialog => dialog.accept());
- // 等待状态更新
- await page.waitForTimeout(500);
- // 验证状态可能已更新(按钮文本可能改变)
- const newButtonText = await toggleButtons.first().textContent();
- expect(newButtonText).toBeTruthy();
- }
- });
- test('应该能够删除地点', async ({ page }) => {
- // 等待地点列表加载
- await page.waitForSelector('tbody tr');
- // 查找删除按钮
- const deleteButtons = page.locator('button').filter({ has: page.locator('svg[data-lucide="trash-2"]') });
- if (await deleteButtons.first().isVisible()) {
- // 设置对话框处理
- page.on('dialog', dialog => dialog.accept());
- // 点击删除按钮
- await deleteButtons.first().click();
- // 等待删除操作完成
- await page.waitForTimeout(500);
- // 验证删除成功(可能显示成功消息)
- await expect(page.getByText('地点已成功删除')).toBeVisible();
- }
- });
- test('应该显示空状态当没有地点时', async ({ page }) => {
- // 使用一个不存在的搜索词来模拟空状态
- const searchInput = page.getByPlaceholder('搜索地点名称或地址...');
- await searchInput.fill('不存在的搜索词');
- // 等待搜索结果
- await page.waitForTimeout(500);
- // 验证可能显示空状态或"暂无地点数据"
- const emptyState = page.getByText('暂无地点数据');
- if (await emptyState.isVisible()) {
- await expect(emptyState).toBeVisible();
- }
- });
- test('应该处理网络错误场景', async ({ page }) => {
- // 模拟网络错误 - 通过无效搜索触发
- const searchInput = page.getByPlaceholder('搜索地点名称或地址...');
- await searchInput.fill('error-test');
- // 等待可能的错误处理
- await page.waitForTimeout(500);
- // 验证页面仍然可用
- await expect(page.getByRole('heading', { name: '地点管理' })).toBeVisible();
- await expect(page.getByRole('button', { name: '新建地点' })).toBeVisible();
- });
- });
|