diff --git a/e2e/playwright.config.ts b/e2e/playwright.config.ts index 4be6c55..1829d31 100644 --- a/e2e/playwright.config.ts +++ b/e2e/playwright.config.ts @@ -5,6 +5,7 @@ export default defineConfig({ timeout: 10000, use: { baseURL: 'http://localhost:5173', + locale: 'zh-CN', }, webServer: { command: 'npm run dev', diff --git a/e2e/tests/crud-undo.spec.ts b/e2e/tests/crud-undo.spec.ts new file mode 100644 index 0000000..108097d --- /dev/null +++ b/e2e/tests/crud-undo.spec.ts @@ -0,0 +1,29 @@ +import { test, expect } from '@playwright/test'; +import { createIpcMock } from '../mocks/ipc'; + +test.beforeEach(async ({ page }) => { + await page.addInitScript(createIpcMock()); + await page.goto('/'); +}); + +test('添加路径后可撤销和重做', async ({ page }) => { + // 点击"新建"按钮 + await page.click('text=新建'); + // 填入路径(对话框内自动聚焦的 input) + await page.locator('.fixed.inset-0 input[type="text"]').fill('C:\\\\NewPath'); + // 对话框确认按钮是"确认" + await page.click('text=确认'); + // 路径应出现在列表中 + await page.waitForTimeout(300); + await expect(page.locator('text=C:\\\\NewPath')).toBeVisible(); + + // Ctrl+Z 撤销 + await page.keyboard.press('Control+z'); + await page.waitForTimeout(300); + await expect(page.locator('text=C:\\\\NewPath')).not.toBeVisible(); + + // Ctrl+Y 重做 + await page.keyboard.press('Control+y'); + await page.waitForTimeout(300); + await expect(page.locator('text=C:\\\\NewPath')).toBeVisible(); +}); diff --git a/e2e/tests/search-clean.spec.ts b/e2e/tests/search-clean.spec.ts new file mode 100644 index 0000000..0055970 --- /dev/null +++ b/e2e/tests/search-clean.spec.ts @@ -0,0 +1,51 @@ +import { test, expect } from '@playwright/test'; + +test.beforeEach(async ({ page }) => { + await page.addInitScript(() => { + window.__TAURI_INTERNALS__ = { + invoke: async (cmd, args) => { + switch (cmd) { + case 'check_admin': return true; + case 'load_system_paths': return ['C:\\\\Windows', 'invalid_path', 'C:\\\\Temp']; + case 'load_user_paths': return []; + case 'load_disabled_state': return { system: [], user: [] }; + case 'save_system_paths': return undefined; + case 'save_user_paths': return undefined; + case 'save_disabled_state': return undefined; + case 'backup_registry': return ''; + case 'broadcast_env_change': return undefined; + case 'validate_path': return false; + case 'expand_env_vars': return ''; + case 'read_text_file': return ''; + case 'get_appdata_dir': return ''; + default: return undefined; + } + } + }; + }); + await page.goto('/'); +}); + +test('搜索过滤后清理无效路径', async ({ page }) => { + // 初始 3 条路径 + await page.waitForTimeout(500); + await expect(page.locator('table tbody tr')).toHaveCount(3); + + // 搜索 "Windows" + const searchInput = page.locator('input[placeholder]'); + await searchInput.fill('Windows'); + await page.waitForTimeout(300); + await expect(page.locator('table tbody tr')).toHaveCount(1); + + // 清除搜索 + await searchInput.fill(''); + await page.waitForTimeout(300); + await expect(page.locator('table tbody tr')).toHaveCount(3); + + // 点击"一键清理"按钮 + await page.click('text=一键清理'); + await page.waitForTimeout(300); + // is_valid_path_format 只校验格式,不检查存在性 + // "invalid_path" 格式无效被移除,C:\Windows 和 C:\Temp 格式有效保留 + await expect(page.locator('table tbody tr')).toHaveCount(2); +}); diff --git a/e2e/tests/startup.spec.ts b/e2e/tests/startup.spec.ts new file mode 100644 index 0000000..19cc83f --- /dev/null +++ b/e2e/tests/startup.spec.ts @@ -0,0 +1,17 @@ +import { test, expect } from '@playwright/test'; +import { createIpcMock } from '../mocks/ipc'; + +test.beforeEach(async ({ page }) => { + await page.addInitScript(createIpcMock()); + await page.goto('/'); +}); + +test('启动后加载系统 PATH 和用户 PATH', async ({ page }) => { + // 系统 tab 默认激活,显示 2 条路径 + await expect(page.locator('table tbody tr')).toHaveCount(2); + + // 切换到用户 tab + await page.click('text=用户变量'); + await page.waitForTimeout(300); + await expect(page.locator('table tbody tr')).toHaveCount(1); +}); diff --git a/e2e/tests/toggle-save.spec.ts b/e2e/tests/toggle-save.spec.ts new file mode 100644 index 0000000..660b414 --- /dev/null +++ b/e2e/tests/toggle-save.spec.ts @@ -0,0 +1,24 @@ +import { test, expect } from '@playwright/test'; +import { createIpcMock } from '../mocks/ipc'; + +test.beforeEach(async ({ page }) => { + await page.addInitScript(createIpcMock()); + await page.goto('/'); +}); + +test('禁用路径后灰显并保存', async ({ page }) => { + // 点击第一个路径的 checkbox 将其禁用 + const checkbox = page.locator('table tbody tr').first().locator('input[type="checkbox"]'); + await checkbox.click(); + await page.waitForTimeout(300); + + // 路径文本应有删除线样式(第 3 列是路径列,nth(2) 即 0-indexed 第 3 个 td) + const row = page.locator('table tbody tr').first(); + await expect(row.locator('td').nth(2)).toHaveCSS('text-decoration-line', 'line-through'); + + // 点击"确定"保存 + await page.click('text=确定'); + await page.waitForTimeout(500); + // 状态栏应显示"保存成功" + await expect(page.locator('text=保存成功')).toBeVisible(); +});