feat(aihr): harden M0-M2 mobile training flows
This commit is contained in:
@@ -92,6 +92,11 @@ test('消息咨询只以消息 ID 作为受控上下文,并让每轮文字或
|
||||
test('消息咨询会新开会话,隐藏媒体和数据工具,并在撤回时清空对话', async () => {
|
||||
const page = await read('../src/pages/user/sop/index.vue');
|
||||
|
||||
assert.match(page, /if \(!conversationStarted\.value\) \{\s*\/\/ Do not start project selection[\s\S]*await activateBroadcastConsultation\(pending, accountKey, pageGeneration\);/);
|
||||
assert.match(page, /!broadcastContext\.value && !broadcastContextLoading\.value && !broadcastContextPrompting\.value/);
|
||||
assert.match(page, /const cancelPendingBroadcastConsultation = \(\) => \{\s*broadcastContextGeneration \+= 1;\s*broadcastContextLoading\.value = false;\s*broadcastContextPrompting\.value = false;/);
|
||||
assert.match(page, /onHide\(\(\) => \{\s*showGeneration \+= 1;\s*candidateRefreshGeneration \+= 1;\s*cancelPendingBroadcastConsultation\(\);/);
|
||||
assert.match(page, /onUnload\(\(\) => \{\s*showGeneration \+= 1;\s*cancelPendingBroadcastConsultation\(\);/);
|
||||
assert.match(page, /error\.statusCode === 404 \|\| error\.bizCode === 404/);
|
||||
assert.match(page, /const pending = readBroadcastQuestionContext\(accountKey\);\s*if \(!pending\) \{\s*if \(broadcastContext\.value\) \{\s*clearBroadcastConsultation\(\);\s*resetConversation\(false\);/);
|
||||
assert.match(page, /const startNewConversation = \(\) => \{\s*clearBroadcastConsultation\(\);\s*resetConversation\(true\);/);
|
||||
|
||||
@@ -4,6 +4,17 @@ import test from 'node:test';
|
||||
|
||||
const read = (path) => readFile(new URL(path, import.meta.url), 'utf8');
|
||||
|
||||
const centeredButtonRule = (source, selector) => {
|
||||
const rule = source.match(new RegExp(`\\.${selector}\\s*\\{([^}]*)\\}`))?.[1] || '';
|
||||
|
||||
assert.ok(rule, `missing .${selector} style rule`);
|
||||
assert.match(rule, /display:\s*flex/);
|
||||
assert.match(rule, /align-items:\s*center/);
|
||||
assert.match(rule, /justify-content:\s*center/);
|
||||
assert.match(rule, /padding:\s*0(?:;|\s)/);
|
||||
assert.match(rule, /line-height:\s*1(?:;|\s)/);
|
||||
};
|
||||
|
||||
test('银城大喇叭仅使用认证后的真实广播接口', async () => {
|
||||
const service = await read('../src/services/broadcast.ts');
|
||||
|
||||
@@ -74,3 +85,18 @@ test('消息详情只交接短期且账号绑定的消息 ID,再进入问模
|
||||
assert.match(service, /context\.accountKey !== accountKey \|\| context\.expiresAt <= now/);
|
||||
assert.match(service, /clearBroadcastQuestionContext\(\)/);
|
||||
});
|
||||
|
||||
test('M0/M1 的短文本操作控件始终在可点击区域内居中', async () => {
|
||||
const [base, list, detail, ask] = await Promise.all([
|
||||
read('../src/styles/base.css'),
|
||||
read('../src/pages/user/broadcast/index.vue'),
|
||||
read('../src/pages/user/broadcast/detail.vue'),
|
||||
read('../src/pages/user/sop/index.vue')
|
||||
]);
|
||||
|
||||
assert.match(base, /\.primary-button,\s*\.secondary-button,\s*\.ghost-button\s*\{[^}]*display:\s*flex[^}]*align-items:\s*center[^}]*justify-content:\s*center/);
|
||||
centeredButtonRule(list, 'scope-tab');
|
||||
centeredButtonRule(list, 'load-more');
|
||||
centeredButtonRule(detail, 'ask-message-button');
|
||||
centeredButtonRule(ask, 'broadcast-context-action');
|
||||
});
|
||||
|
||||
@@ -42,6 +42,32 @@ test('训练页提交失败会回滚本次乐观追加的对话', async () => {
|
||||
assert.match(source, /uni\.showToast\(\{ title: message\.value \|\| '提交失败', icon: 'none'/);
|
||||
});
|
||||
|
||||
test('训练求助先留存会话事件,再以 practice_help 来源检索 SOP', async () => {
|
||||
const [practicePage, practiceService, knowledgeService] = await Promise.all([
|
||||
pageSource('../src/pages/user/practice/index.vue'),
|
||||
pageSource('../src/services/practice.ts'),
|
||||
pageSource('../src/services/knowledge.ts')
|
||||
]);
|
||||
|
||||
assert.match(practiceService, /sessions\/\$\{encodeURIComponent\(sessionId\)\}\/help/);
|
||||
assert.match(practicePage, /await recordPracticeHelp\(sessionId\.value, roundIndex\.value\)/);
|
||||
assert.match(practicePage, /'practice_help'/);
|
||||
assert.match(knowledgeService, /'practice_help'/);
|
||||
});
|
||||
|
||||
test('语音 profile 透传方言枚举,并保持普通话默认值', async () => {
|
||||
const [apiTypes, speechService] = await Promise.all([
|
||||
pageSource('../src/types/api.ts'),
|
||||
pageSource('../src/services/speech.ts')
|
||||
]);
|
||||
|
||||
assert.match(apiTypes, /dialect\?: 'mandarin' \| 'cantonese' \| 'sichuanese'/);
|
||||
assert.match(speechService, /dialect: 'mandarin'/);
|
||||
assert.match(speechService, /customerVoiceProfile = \([\s\S]*?dialect:/);
|
||||
assert.match(speechService, /dialect === 'cantonese'.*'zh-HK'/);
|
||||
assert.match(speechService, /dialect === 'sichuanese'[\s\S]*?当前设备语音不支持四川话/);
|
||||
});
|
||||
|
||||
test('训练结果回到顶部,SOP 答案生成后定位到回答区', async () => {
|
||||
const [practiceSource, sopSource, navigationSource] = await Promise.all([
|
||||
pageSource('../src/pages/user/practice/index.vue'),
|
||||
@@ -99,6 +125,15 @@ test('登录页按高保真原型保留品牌结构和紧凑验证码行', async
|
||||
assert.doesNotMatch(source, /grid-template-columns:\s*1fr;[\s\S]*?\.code-button/);
|
||||
});
|
||||
|
||||
test('移动端短信登录不再让客户端选择租户', async () => {
|
||||
const source = await pageSource('../src/pages/auth/login/index.vue');
|
||||
const loginRequest = source.match(/url: '\/auth\/mobile\/sms-login',[\s\S]*?auth: false/)?.[0] || '';
|
||||
|
||||
assert.match(loginRequest, /phonenumber: value/);
|
||||
assert.match(loginRequest, /smsCode: formData\.smsCode\.trim\(\)/);
|
||||
assert.doesNotMatch(loginRequest, /tenantId:/);
|
||||
});
|
||||
|
||||
test('共享视觉基座包含员工端主色和卡片圆角 token', async () => {
|
||||
const source = await pageSource('../src/styles/base.css');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user