import { expect, test } from '@playwright/test' /** * DCS 编辑器 - 画布编辑器核心功能测试 * * 测试画布页面管理、侧边栏标签切换、组件面板等核心交互。 * 每个测试独立运行,通过创建画布进入编辑器。 */ /** 辅助函数:创建画布并进入编辑器 */ async function enterEditor(page: import('@playwright/test').Page, canvasName = '测试画布') { await page.goto('/') await page.waitForLoadState('networkidle') await page.locator('.add-card').click() const dialog = page.locator('.el-dialog') await expect(dialog).toBeVisible({ timeout: 5000 }) await dialog.locator('input').first().fill(canvasName) await dialog.locator('button').filter({ hasText: '创建' }).click() await expect(page.locator('.dcs-editor')).toBeVisible({ timeout: 10000 }) } test.describe('画布编辑器核心功能', () => { test('编辑器加载后显示画布舞台', async ({ page }) => { await enterEditor(page, '画布加载测试') // 画布舞台(wrapper)应该可见 await expect(page.locator('.canvas-wrapper')).toBeVisible() // 画布内 canvas 元素应存在 await expect(page.locator('.canvas-wrapper canvas')).toBeVisible() // 标尺应该可见 await expect(page.locator('.ruler-top')).toBeVisible() await expect(page.locator('.ruler-left')).toBeVisible() }) test('侧边栏标签 - 默认显示图层面板', async ({ page }) => { await enterEditor(page, '侧边栏标签测试') // 默认激活的标签应该是"图层" const activeTab = page.locator('.sidebar-tab-item.active') await expect(activeTab).toContainText('图层') // 图层面板区域应该可见 await expect(page.locator('.layers-tab')).toBeVisible() }) test('侧边栏标签 - 切换到组件面板', async ({ page }) => { await enterEditor(page, '组件面板测试') // 点击"组件"标签 await page.locator('.sidebar-tab-item').filter({ hasText: '组件' }).click() // 组件标签应变为激活状态 const activeTab = page.locator('.sidebar-tab-item.active') await expect(activeTab).toContainText('组件') // 组件面板应该可见,且包含提示文字 await expect(page.locator('.components-tab')).toBeVisible() await expect(page.locator('.components-hint')).toContainText('拖拽添加到画布') }) test('侧边栏标签 - 切换到模板面板', async ({ page }) => { await enterEditor(page, '模板面板测试') // 点击"模板"标签 await page.locator('.sidebar-tab-item').filter({ hasText: '模板' }).click() // 模板标签应变为激活状态 const activeTab = page.locator('.sidebar-tab-item.active') await expect(activeTab).toContainText('模板') }) test('侧边栏标签 - 可以依次切换回图层面板', async ({ page }) => { await enterEditor(page, '标签回切测试') // 先切到组件 await page.locator('.sidebar-tab-item').filter({ hasText: '组件' }).click() await expect(page.locator('.sidebar-tab-item.active')).toContainText('组件') // 再切回图层 await page.locator('.sidebar-tab-item').filter({ hasText: '图层' }).click() await expect(page.locator('.sidebar-tab-item.active')).toContainText('图层') await expect(page.locator('.layers-tab')).toBeVisible() }) test('组件面板显示所有可用组件', async ({ page }) => { await enterEditor(page, '组件列表测试') // 切换到组件面板 await page.locator('.sidebar-tab-item').filter({ hasText: '组件' }).click() await expect(page.locator('.components-tab')).toBeVisible() // 验证组件卡片数量(constants.ts 定义了 5 个:矩形、数值、文本、棒图、按钮) const cards = page.locator('.component-card') await expect(cards).toHaveCount(5) // 验证各组件名称 await expect(page.locator('.card-title').filter({ hasText: '矩形' })).toBeVisible() await expect(page.locator('.card-title').filter({ hasText: '数值' })).toBeVisible() await expect(page.locator('.card-title').filter({ hasText: '文本' })).toBeVisible() await expect(page.locator('.card-title').filter({ hasText: '棒图' })).toBeVisible() await expect(page.locator('.card-title').filter({ hasText: '按钮' })).toBeVisible() }) test('图层面板显示页面列表和画布页数', async ({ page }) => { await enterEditor(page, '页面列表测试') // 图层面板应可见 await expect(page.locator('.layers-tab')).toBeVisible() // 页面头部应显示页数 await expect(page.locator('.page-header')).toContainText('页数') // 页面列表应至少有一个活动页面 const activePage = page.locator('.page-row.active') await expect(activePage).toBeVisible() }) test('点击画布背景可以取消图层选中', async ({ page }) => { await enterEditor(page, '取消选中测试') // 点击画布背景区域 await page.locator('.canvas-wrapper').click({ position: { x: 50, y: 50 } }) // 状态栏不应显示选中信息(没有选中任何图层时不会显示"已选中") await expect(page.locator('.editor-status-bar .status-right')).not.toContainText('已选中') }) test('撤销按钮初始状态为禁用', async ({ page }) => { await enterEditor(page, '撤销状态测试') // 撤销按钮初始应该是禁用的(没有操作历史) const undoBtn = page.locator('.editor-header .icon-btn').filter({ has: page.locator('.fa-rotate-left') }) await expect(undoBtn).toBeDisabled() // 重做按钮初始也应该是禁用的 const redoBtn = page.locator('.editor-header .icon-btn').filter({ has: page.locator('.fa-rotate-right') }) await expect(redoBtn).toBeDisabled() }) test('头部包含分享和运行按钮', async ({ page }) => { await enterEditor(page, '头部按钮测试') // 分享按钮 await expect(page.locator('.share-btn')).toBeVisible() await expect(page.locator('.share-btn')).toContainText('分享') // 运行组合按钮 await expect(page.locator('.run-combo-btn')).toBeVisible() await expect(page.locator('.run-main-btn')).toBeVisible() }) test('工具栏显示工具按钮', async ({ page }) => { await enterEditor(page, '工具栏测试') // 工具栏应可见 await expect(page.locator('.tool-rail')).toBeVisible() // 工具按钮应存在(至少有移动工具、文本工具、矩形工具 + 底部折叠按钮) const toolButtons = page.locator('.tool-rail .tool-btn') const count = await toolButtons.count() expect(count).toBeGreaterThanOrEqual(3) }) test('侧边栏可以折叠和展开', async ({ page }) => { await enterEditor(page, '折叠展开测试') // 确认侧边栏面板初始可见 await expect(page.locator('.editor-sidebar-panel')).toBeVisible() // 点击折叠按钮(工具栏底部的按钮,有 fa-angles-left 图标) const collapseBtn = page.locator('.tool-bottom .tool-btn') await collapseBtn.click() // 侧边栏应添加 is-collapsed 类 await expect(page.locator('.editor-sidebar-shell.is-collapsed')).toBeVisible() // 再次点击展开 await collapseBtn.click() await expect(page.locator('.editor-sidebar-shell:not(.is-collapsed)')).toBeVisible() }) })