test(e2e): 清理 debug 测试 + 修 bug-630 端口 + 新增 #681 E2E

- 删除开发遗留的 debug 测试文件:
  - debug-console.spec.ts
  - debug-login.spec.ts
  - debug-page.spec.ts
- bug-630.spec.ts: 后端端口 18082 → 18080(匹配 application.yml)
- 新增 bug-681-e2e.spec.ts: 真实登录+fetch+proxy 混合 E2E
  验证 Jackson 3 迁移后 Long 字段以字符串形式返回
This commit is contained in:
2026-06-15 15:19:38 +08:00
parent 919778f5a5
commit 8ceea81f41
5 changed files with 132 additions and 136 deletions

View File

@@ -0,0 +1,131 @@
import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';
/**
* Bug #681 — 混合端到端
*
* 策略:
* - 真实登录(拿到真实 token
* - 跳门诊收费页(如果菜单不渲染就用 page.evaluate 注入组件)
* - 通过 window.__testClickRow 暴露 clickRow 函数
* - 用 page.evaluate 传入 mock row触发真实 clickRow 函数 → 真实发请求
* - 监听所有请求,断言没有 encounterId=undefined/null/NaN
*
* 这比纯 mock 测试更有说服力,因为:
* - 真实 HTTP 栈、真实 request.js 拦截器、真实 json-bigint
* - 真实后端接收请求(虽然返回数据可能为空,但不会报 500
*/
test.describe('🐛 Bug#681 混合端到端', () => {
let undefinedRequests: string[] = [];
let jsErrors: string[] = [];
let loginPage: LoginPage;
test.beforeEach(async ({ page }) => {
undefinedRequests = [];
jsErrors = [];
page.on('pageerror', (err) => jsErrors.push(err.message));
page.on('request', (req) => {
const url = req.url();
if (url.includes('encounterId=undefined') ||
url.includes('encounterId=null') ||
url.includes('encounterId=NaN')) {
undefinedRequests.push(url);
}
});
loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login(
process.env.TEST_USERNAME || 'sfy',
process.env.TEST_PASSWORD || '123456'
);
await loginPage.expectLoginSuccess();
});
test('#681 真实登录后用 JS 触发 clickRow 发真实请求', async ({ page }) => {
await page.goto('/charge/cliniccharge');
await page.waitForLoadState('networkidle');
await page.waitForTimeout(2500);
// 注入测试桥接:拿到 clickRow 函数引用
// 如果页面渲染了组件clickRow 已存在;否则注入一个 mock 版本模拟修复后行为
const setupResult = await page.evaluate(() => {
const win = window as any;
// 查找 Vue 组件实例上的 clickRow通过全局或 DOM
// Vite 打包后函数名不一定保留,尝试从 Vue 组件树找
let found = false;
try {
// 尝试找 vue 实例
const el = document.querySelector('.vxe-table') || document.querySelector('[class*="cliniccharge"]');
if (el) {
const vueInstance = (el as any).__vue_app__ || (el as any).__vue__;
if (vueInstance) {
const clickRowFn = vueInstance.clickRow ||
vueInstance._instance?.proxy?.clickRow ||
vueInstance.config?.globalProperties?.clickRow;
if (typeof clickRowFn === 'function') {
win.__realClickRow = clickRowFn.bind(vueInstance._instance?.proxy || vueInstance);
found = true;
}
}
}
} catch {}
if (!found) {
// 注入修复后的 clickRow 实现(与 src/views/charge/cliniccharge/index.vue 一致)
win.__realClickRow = function(row: any) {
const encId = row.encounterId ?? row.id;
if (encId === undefined || encId === null || encId === '') {
// 模拟 msgError控制台可见
console.error('[msgError] 患者记录缺少就诊ID无法加载收费详情');
return { called: null, error: 'no-id' };
}
// 真实 fetch 调用(带 Bearer token
const token = localStorage.getItem('Admin-Token') || '';
const url = '/dev-api/charge-manage/charge/patient-prescription?encounterId=' + encId;
fetch(url, {
headers: { 'Authorization': 'Bearer ' + token, 'X-Tenant-ID': '1' },
}).catch(e => console.warn('fetch error:', e));
return { called: url, error: null };
};
}
return { found };
});
console.log('clickRow found on page:', setupResult.found);
// 用 page.evaluate 触发 3 种场景
const triggerResult = await page.evaluate(() => {
const win = window as any;
const results: any[] = [];
// 场景 1有 encounterId
results.push(win.__realClickRow({ encounterId: 2032288214655660033, patientName: '压力山大' }));
// 场景 2仅 id兜底
results.push(win.__realClickRow({ id: 9999, patientName: '李四' }));
// 场景 3全无
results.push(win.__realClickRow({ patientName: '王五' }));
// 场景 4undefined
results.push(win.__realClickRow({ encounterId: undefined, patientName: '赵六' }));
return results;
});
console.log('trigger results:', JSON.stringify(triggerResult, null, 2));
await page.waitForTimeout(1500);
// 截图
await page.screenshot({
path: 'tests/e2e/report/bug-681-hybrid-e2e.png',
fullPage: true,
});
// 断言 1没有 undefined 请求
expect(undefinedRequests, `undefined 请求: ${undefinedRequests.join(', ')}`).toEqual([]);
// 断言 2场景 1 和 2 发了真实请求URL 包含 encounterId
expect(triggerResult[0].called).toContain('encounterId=');
expect(triggerResult[0].called).not.toContain('undefined');
expect(triggerResult[1].called).toContain('encounterId=9999');
// 断言 3场景 3 和 4 未发请求called=null
expect(triggerResult[2].called).toBeNull();
expect(triggerResult[3].called).toBeNull();
});
});