Files
kefu/deploy/protocol-integration-20260916/qa/browser.mjs
T
2026-09-21 10:34:06 +08:00

64 lines
5.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {createRequire} from 'node:module';
import {writeFileSync} from 'node:fs';
const require=createRequire('C:/kefu/admin-web/package.json');
const {chromium}=require('playwright');
const root='C:/kefu/deploy/protocol-integration-20260916/qa';
const browser=await chromium.launch({executablePath:'C:/Program Files/Google/Chrome/Application/chrome.exe',headless:true,args:['--no-proxy-server']});
const context=await browser.newContext({viewport:{width:1600,height:1050},locale:'zh-CN'});
await context.route('**/*',route=>new URL(route.request().url()).hostname==='127.0.0.1'?route.continue():route.abort());
const page=await context.newPage();page.setDefaultTimeout(20000);
const errors=[],checks=[],searches=[];
page.on('pageerror',error=>errors.push(error.message));
page.on('request',request=>{if(request.method()==='POST'&&request.url().includes('/knowledge/search'))searches.push(request.postDataJSON());});
const account=async name=>{await page.locator('.ant-card-extra .ant-select-selector').click();await page.locator('.ant-select-dropdown:visible').getByText(name,{exact:true}).click();};
const query=page.getByPlaceholder(/输入一个真实业务问题/);
const search=page.getByRole('button',{name:/^检\s*索$/});
const assert=(value,text)=>{if(!value)throw Error(text);};
try{
await page.goto('http://127.0.0.1:18871/#/auth/login');
await page.getByPlaceholder('用户名',{exact:true}).fill('admin');
await page.getByPlaceholder('密码',{exact:true}).fill('KnowledgeQA@2026');
await page.getByRole('button',{name:'login',exact:true}).click();
await page.waitForURL(url=>!url.hash.includes('/auth/login'));
await page.goto('http://127.0.0.1:18871/#/knowledge/center');
await account('检索验收客服(SQ001)');
await page.getByRole('tab',{name:'检索测试',exact:true}).click();
if(process.argv.includes('--before')){
await search.click();await page.getByText('[object Object]',{exact:true}).waitFor();
await page.screenshot({path:`${root}/00-before-object-error.png`,fullPage:true});
console.log('Reproduced: empty search displays [object Object]');
}else{
for(const value of ['', ' ', '约', ' 约 ']){
await query.fill(value);await search.click();
await page.getByText('请输入至少 2 个字符的检索问题',{exact:true}).waitFor();
}
await query.fill('约'.repeat(2001));await search.click();
await page.getByText('检索问题不能超过 2000 个字符',{exact:true}).waitFor();
assert(searches.length===0,'Invalid searches reached API');
checks.push('空白、单字和超长问题在页面提示,不发送无效请求');
await query.fill(' 预约挂号 ');await query.press('Enter');
await page.getByText(/关键词检索.*1 条命中/).waitFor();
assert(searches[0].query==='预约挂号','Query not trimmed');
await page.screenshot({path:`${root}/01-success.png`,fullPage:true});
checks.push('正常问题支持回车检索并去除首尾空白,只返回 1 条已发布知识,不命中草稿或待发布');
await context.route('**/api/knowledge/search**',async route=>{
await route.fulfill({status:422,contentType:'application/json',body:JSON.stringify({detail:[{type:'string_too_short',loc:['body','query'],msg:'String should have at least 2 characters',input:'PRIVATE-MUST-NOT-RENDER',ctx:{min_length:2}}]})});
},{times:1});
await query.fill('校验错误模拟');await search.click();
await page.locator('.ant-alert').filter({hasText:'检索问题至少需要 2 个字符'}).waitFor();
let text=await page.locator('body').innerText();assert(!text.includes('[object Object]')&&!text.includes('PRIVATE-MUST-NOT-RENDER'),'Unsafe error display');
assert(!text.includes('1 条命中'),'Old result left after failed search');
await page.screenshot({path:`${root}/02-readable-error.png`,fullPage:true});
checks.push('后端 422 数组错误显示中文说明,无对象字符串、不回显请求内容,失败后清除旧结果');
await account('空知识验收客服(SQ002)');
await page.getByText('当前账号暂无已发布知识,请先审核并发布知识后再测试检索。',{exact:true}).waitFor();
await query.fill('预约挂号');await search.click();
await page.getByText('当前账号没有已发布知识,审核通过后还需发布才能检索。',{exact:true}).waitFor();
await page.screenshot({path:`${root}/03-no-published-knowledge.png`,fullPage:true});
checks.push('无已发布知识的账号正常返回 0 命中,并提示先发布');
assert(!errors.length,JSON.stringify(errors));
const result={passed:true,checks,pageErrors:errors};writeFileSync(`${root}/result.json`,JSON.stringify(result,null,2));console.log(JSON.stringify(result));
}
}catch(error){await page.screenshot({path:`${root}/failure.png`,fullPage:true});writeFileSync(`${root}/failure.txt`,String(error)+'\n'+await page.locator('body').innerText());throw error;}
finally{await browser.close();}