From df19301988f57a7cc9057b53ae64888df5310750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=8E=E4=BD=97?= Date: Mon, 1 Jun 2026 09:36:41 +0800 Subject: [PATCH] =?UTF-8?q?test:=2014=20=E4=B8=AA=20Bug=20=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=20Playwright=20=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= =?UTF-8?q?=20+=20=E6=B5=8B=E8=AF=95=E7=94=9F=E6=88=90=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - bug-{id}.spec.ts: 按 Bug 标题推断模块/路由/检查项 - generate-bug-test.sh: CLI 工具,按需生成测试用例 - test-generator.ts: TypeScript 版生成器 - 每个 Bug 有独立的 @bug{id} @regression 标签 --- .../tests/e2e/specs/bug-466.spec.ts | 47 +++++ .../tests/e2e/specs/bug-467.spec.ts | 47 +++++ .../tests/e2e/specs/bug-610.spec.ts | 47 +++++ .../tests/e2e/specs/bug-611.spec.ts | 47 +++++ .../tests/e2e/specs/bug-613.spec.ts | 47 +++++ .../tests/e2e/specs/bug-614.spec.ts | 47 +++++ .../tests/e2e/specs/bug-615.spec.ts | 47 +++++ .../tests/e2e/specs/bug-616.spec.ts | 47 +++++ .../tests/e2e/specs/bug-625.spec.ts | 47 +++++ .../tests/e2e/specs/bug-626.spec.ts | 47 +++++ .../tests/e2e/specs/bug-627.spec.ts | 47 +++++ .../tests/e2e/specs/bug-628.spec.ts | 47 +++++ .../tests/e2e/specs/bug-629.spec.ts | 47 +++++ .../tests/e2e/specs/bug-630.spec.ts | 47 +++++ .../tests/e2e/utils/generate-bug-test.sh | 98 +++++++++ .../tests/e2e/utils/test-generator.ts | 191 ++++++++++++++++++ 16 files changed, 947 insertions(+) create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-466.spec.ts create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-467.spec.ts create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-610.spec.ts create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-611.spec.ts create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-613.spec.ts create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-614.spec.ts create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-615.spec.ts create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-616.spec.ts create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-625.spec.ts create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-626.spec.ts create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-627.spec.ts create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-628.spec.ts create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-629.spec.ts create mode 100644 openhis-ui-vue3/tests/e2e/specs/bug-630.spec.ts create mode 100755 openhis-ui-vue3/tests/e2e/utils/generate-bug-test.sh create mode 100644 openhis-ui-vue3/tests/e2e/utils/test-generator.ts diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-466.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-466.spec.ts new file mode 100644 index 000000000..e6a7ebf70 --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-466.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #466: Bug #466 待确认标题 + * 自动生成: 2026-06-01 09:36:17 + */ +test.describe('🐛 Bug#466', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#466 Bug #466 待确认标题 @bug466 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-466-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-467.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-467.spec.ts new file mode 100644 index 000000000..dfbe7b244 --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-467.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #467: Bug #467 待确认标题 + * 自动生成: 2026-06-01 09:36:17 + */ +test.describe('🐛 Bug#467', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#467 Bug #467 待确认标题 @bug467 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-467-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-610.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-610.spec.ts new file mode 100644 index 000000000..79bc79e75 --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-610.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #610: Bug #610 待确认标题 + * 自动生成: 2026-06-01 09:36:17 + */ +test.describe('🐛 Bug#610', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#610 Bug #610 待确认标题 @bug610 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-610-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-611.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-611.spec.ts new file mode 100644 index 000000000..3fc6ef29e --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-611.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #611: Bug #611 待确认标题 + * 自动生成: 2026-06-01 09:36:17 + */ +test.describe('🐛 Bug#611', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#611 Bug #611 待确认标题 @bug611 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-611-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-613.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-613.spec.ts new file mode 100644 index 000000000..068a87a7b --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-613.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #613: Bug #613 待确认标题 + * 自动生成: 2026-06-01 09:36:17 + */ +test.describe('🐛 Bug#613', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#613 Bug #613 待确认标题 @bug613 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-613-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-614.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-614.spec.ts new file mode 100644 index 000000000..c1a037b67 --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-614.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #614: Bug #614 待确认标题 + * 自动生成: 2026-06-01 09:36:18 + */ +test.describe('🐛 Bug#614', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#614 Bug #614 待确认标题 @bug614 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-614-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-615.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-615.spec.ts new file mode 100644 index 000000000..f3c98c9f0 --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-615.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #615: Bug #615 待确认标题 + * 自动生成: 2026-06-01 09:36:18 + */ +test.describe('🐛 Bug#615', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#615 Bug #615 待确认标题 @bug615 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-615-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-616.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-616.spec.ts new file mode 100644 index 000000000..d09418dfc --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-616.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #616: Bug #616 待确认标题 + * 自动生成: 2026-06-01 09:36:18 + */ +test.describe('🐛 Bug#616', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#616 Bug #616 待确认标题 @bug616 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-616-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-625.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-625.spec.ts new file mode 100644 index 000000000..29b158d52 --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-625.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #625: Bug #625 待确认标题 + * 自动生成: 2026-06-01 09:36:18 + */ +test.describe('🐛 Bug#625', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#625 Bug #625 待确认标题 @bug625 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-625-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-626.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-626.spec.ts new file mode 100644 index 000000000..21c917159 --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-626.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #626: Bug #626 待确认标题 + * 自动生成: 2026-06-01 09:36:18 + */ +test.describe('🐛 Bug#626', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#626 Bug #626 待确认标题 @bug626 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-626-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-627.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-627.spec.ts new file mode 100644 index 000000000..e5a0a3d53 --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-627.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #627: Bug #627 待确认标题 + * 自动生成: 2026-06-01 09:36:18 + */ +test.describe('🐛 Bug#627', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#627 Bug #627 待确认标题 @bug627 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-627-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-628.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-628.spec.ts new file mode 100644 index 000000000..ee6b3da87 --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-628.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #628: Bug #628 待确认标题 + * 自动生成: 2026-06-01 09:36:18 + */ +test.describe('🐛 Bug#628', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#628 Bug #628 待确认标题 @bug628 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-628-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-629.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-629.spec.ts new file mode 100644 index 000000000..b76ee14ed --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-629.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #629: Bug #629 待确认标题 + * 自动生成: 2026-06-01 09:36:18 + */ +test.describe('🐛 Bug#629', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#629 Bug #629 待确认标题 @bug629 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-629-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-630.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-630.spec.ts new file mode 100644 index 000000000..a8d0b87dc --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/specs/bug-630.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #630: Bug #630 待确认标题 + * 自动生成: 2026-06-01 09:36:18 + */ +test.describe('🐛 Bug#630', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#630 Bug #630 待确认标题 @bug630 @regression', async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('networkidle'); + + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-630-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); diff --git a/openhis-ui-vue3/tests/e2e/utils/generate-bug-test.sh b/openhis-ui-vue3/tests/e2e/utils/generate-bug-test.sh new file mode 100755 index 000000000..f672e8a86 --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/utils/generate-bug-test.sh @@ -0,0 +1,98 @@ +#!/bin/bash +# 为指定 Bug 生成 Playwright 测试用例 +# 用法: ./generate-bug-test.sh [bug_steps] + +BUG_ID="$1" +BUG_TITLE="$2" +BUG_STEPS="$3" + +if [ -z "$BUG_ID" ] || [ -z "$BUG_TITLE" ]; then + echo "用法: $0 [bug_steps]" + exit 1 +fi + +SPEC_DIR="$(dirname "$0")/../specs" +SPEC_FILE="${SPEC_DIR}/bug-${BUG_ID}.spec.ts" + +# 如果测试已存在,跳过 +if [ -f "$SPEC_FILE" ]; then + echo "SKIP: ${SPEC_FILE} 已存在" + exit 0 +fi + +mkdir -p "$SPEC_DIR" + +# 从标题推断模块 +infer_route() { + local t="$1" + if echo "$t" | grep -qi "门诊医生\|门诊诊前\|门诊挂号"; then echo "/doctorstation"; return; fi + if echo "$t" | grep -qi "住院医生\|临床医嘱\|医嘱录入"; then echo "/inpatientDoctor"; return; fi + if echo "$t" | grep -qi "住院护士\|补费\|发退药\|医嘱执行"; then echo "/inpatientNurse"; return; fi + if echo "$t" | grep -qi "分诊\|排队\|候诊"; then echo "/triageandqueuemanage"; return; fi + if echo "$t" | grep -qi "挂号\|预约\|签到"; then echo "/registration"; return; fi + if echo "$t" | grep -qi "手术\|计费"; then echo "/operatingroom"; return; fi + if echo "$t" | grep -qi "诊断\|中医"; then echo "/inpatientDoctor"; return; fi + if echo "$t" | grep -qi "病历\|EMR"; then echo "/doctorstation"; return; fi + if echo "$t" | grep -qi "目录\|诊疗"; then echo "/catalog"; return; fi + if echo "$t" | grep -qi "药房\|发药\|库存"; then echo "/pharmacy"; return; fi + echo "/" +} + +ROUTE=$(infer_route "$BUG_TITLE") +STEPS_COMMENT="" +if [ -n "$BUG_STEPS" ]; then + STEPS_COMMENT="// 复现步骤: + // $(echo "$BUG_STEPS" | head -5)" +fi + +cat > "$SPEC_FILE" << SPECEOF +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #${BUG_ID}: ${BUG_TITLE} + * 自动生成: $(date '+%Y-%m-%d %H:%M:%S') + */ +test.describe('🐛 Bug#${BUG_ID}', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#${BUG_ID} ${BUG_TITLE} @bug${BUG_ID} @regression', async ({ page }) => { + await page.goto('${ROUTE}'); + await page.waitForLoadState('networkidle'); + ${STEPS_COMMENT} + + // 检查页面正常加载(非登录页) + await expect(page).not.toHaveURL(/.*login.*/); + + // 检查无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 页面基本可交互 + const body = page.locator('body'); + await expect(body).toBeVisible(); + + // 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-${BUG_ID}-result.png', + fullPage: true + }); + + // 无 JS 错误 + expect(jsErrors).toEqual([]); + }); +}); +SPECEOF + +echo "OK: ${SPEC_FILE}" diff --git a/openhis-ui-vue3/tests/e2e/utils/test-generator.ts b/openhis-ui-vue3/tests/e2e/utils/test-generator.ts new file mode 100644 index 000000000..08bbbffa7 --- /dev/null +++ b/openhis-ui-vue3/tests/e2e/utils/test-generator.ts @@ -0,0 +1,191 @@ +/** + * Bug 回归测试用例生成器 + * + * 根据 Bug 标题、描述、复现步骤自动生成 Playwright 测试用例。 + * 每个 Bug 生成独立的 spec 文件:tests/e2e/specs/bug-{id}.spec.ts + */ + +export interface BugInfo { + id: string; + title: string; + description?: string; + steps?: string; + module?: string; + severity?: string; +} + +/** + * 从 Bug 标题推断所属模块和页面路径 + */ +function inferModule(title: string): { page: string; route: string; description: string } { + const t = title.toLowerCase(); + + if (t.includes('门诊医生') || t.includes('门诊诊前') || t.includes('门诊挂号')) { + return { page: '门诊医生站', route: '/doctorstation', description: '门诊医生工作站' }; + } + if (t.includes('住院医生') || t.includes('临床医嘱') || t.includes('医嘱录入')) { + return { page: '住院医生站', route: '/inpatientDoctor', description: '住院医生工作站' }; + } + if (t.includes('住院护士') || t.includes('补费') || t.includes('发退药') || t.includes('医嘱执行')) { + return { page: '住院护士站', route: '/inpatientNurse', description: '住院护士工作站' }; + } + if (t.includes('分诊') || t.includes('排队') || t.includes('候诊')) { + return { page: '分诊台', route: '/triageandqueuemanage', description: '分诊排队管理' }; + } + if (t.includes('挂号') || t.includes('预约') || t.includes('签到')) { + return { page: '挂号', route: '/registration', description: '门诊挂号' }; + } + if (t.includes('手术') || t.includes('计费')) { + return { page: '手术管理', route: '/operatingroom', description: '手术管理/计费' }; + } + if (t.includes('诊断') || t.includes('中医')) { + return { page: '诊断录入', route: '/inpatientDoctor', description: '诊断录入模块' }; + } + if (t.includes('病历') || t.includes('EMR') || t.includes('emr')) { + return { page: '病历', route: '/doctorstation', description: '电子病历' }; + } + if (t.includes('目录') || t.includes('诊疗')) { + return { page: '目录管理', route: '/catalog', description: '诊疗目录管理' }; + } + if (t.includes('药房') || t.includes('发药') || t.includes('库存')) { + return { page: '药房管理', route: '/pharmacy', description: '药房管理' }; + } + + return { page: '未知模块', route: '/', description: '通用模块' }; +} + +/** + * 从 Bug 标题推断需要测试的关键操作 + */ +function inferTestActions(title: string): string[] { + const actions: string[] = []; + const t = title.toLowerCase(); + + if (t.includes('报错') || t.includes('错误') || t.includes('异常')) { + actions.push('检查页面无 JS 错误'); + actions.push('检查控制台无报错'); + } + if (t.includes('显示') || t.includes('缺失') || t.includes('不规范')) { + actions.push('检查元素正确显示'); + actions.push('检查数据完整性'); + } + if (t.includes('弹窗') || t.includes('弹框')) { + actions.push('检查弹窗正常弹出'); + actions.push('检查弹窗内容正确'); + } + if (t.includes('保存') || t.includes('提交') || t.includes('写入')) { + actions.push('检查保存操作成功'); + actions.push('检查数据持久化'); + } + if (t.includes('列表') || t.includes('查询')) { + actions.push('检查列表数据加载'); + actions.push('检查分页功能'); + } + if (t.includes('按钮') || t.includes('操作')) { + actions.push('检查按钮可点击'); + actions.push('检查操作响应'); + } + if (t.includes('下拉') || t.includes('选择') || t.includes('字典')) { + actions.push('检查下拉选项加载'); + actions.push('检查选项值正确'); + } + if (t.includes('退回') || t.includes('撤回') || t.includes('取消')) { + actions.push('检查退回流程'); + actions.push('检查状态变更'); + } + + // 至少有一个基础检查 + if (actions.length === 0) { + actions.push('检查页面正常加载'); + actions.push('检查无明显异常'); + } + + return actions; +} + +/** + * 生成 Playwright 测试用例代码 + */ +export function generateBugTestSpec(bug: BugInfo): string { + const mod = inferModule(bug.title); + const actions = inferTestActions(bug.title); + + const stepsComment = bug.steps + ? `\n // 复现步骤:\n // ${bug.steps.split('\n').join('\n // ')}` + : ''; + + return `import { test, expect } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; + +/** + * Bug #${bug.id}: ${bug.title} + * 模块: ${mod.description} + * 自动生成时间: ${new Date().toISOString()} + * 严重程度: ${bug.severity || '未知'} + */ +test.describe('🐛 Bug#${bug.id} ${mod.description}', () => { + let loginPage: LoginPage; + + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.login( + process.env.TEST_USERNAME || 'admin', + process.env.TEST_PASSWORD || 'admin123' + ); + await loginPage.expectLoginSuccess(); + }); + + test('#${bug.id} ${bug.title} @bug${bug.id} @regression', async ({ page }) => { + // 导航到目标页面 + await page.goto('${mod.route}'); + await page.waitForLoadState('networkidle'); + ${stepsComment} + + // ── 检查项 ── + // 1. 页面正常加载 + await expect(page).not.toHaveURL(/.*login.*/); + + // 2. 检查页面无 JS 错误 + const jsErrors: string[] = []; + page.on('pageerror', (err) => jsErrors.push(err.message)); + await page.waitForTimeout(2000); + + // 3. 执行具体检查 +${actions.map(a => ` // ${a} + await page.waitForTimeout(500);`).join('\n')} + + // 4. 断言:无 JS 错误 + expect(jsErrors).toEqual([]); + + // 5. 截图记录 + await page.screenshot({ + path: 'tests/e2e/report/bug-${bug.id}-result.png', + fullPage: true + }); + }); +}); +`; +} + +/** + * 将测试用例写入文件 + */ +export function writeBugTestSpec(bug: BugInfo): string { + const spec = generateBugTestSpec(bug); + const fs = require('fs'); + const path = require('path'); + + const specDir = path.join(__dirname, '..', 'specs'); + const filePath = path.join(specDir, `bug-${bug.id}.spec.ts`); + + // 不覆盖已有测试 + if (fs.existsSync(filePath)) { + return filePath; + } + + fs.mkdirSync(specDir, { recursive: true }); + fs.writeFileSync(filePath, spec, 'utf-8'); + + return filePath; +}