64 lines
5.0 KiB
JavaScript
64 lines
5.0 KiB
JavaScript
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/knowledge-v5-search/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:18870/#/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:18870/#/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();}
|