feat(aihr): close functional checklist gaps
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { after, test } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createServer } from 'vite';
|
||||
|
||||
const storage = new Map([
|
||||
['aihr_mobile_access_token', 'expired-token'],
|
||||
['aihr_mobile_client_id', 'app-client'],
|
||||
['aihr_mobile_phone', '13800000000'],
|
||||
['aihr_mobile_tenant_id', '000000']
|
||||
]);
|
||||
const redirects = [];
|
||||
let uploadShouldFail = false;
|
||||
|
||||
globalThis.plus = {};
|
||||
globalThis.getCurrentPages = () => [{
|
||||
route: 'pages/user/sop/index',
|
||||
$page: { fullPath: '/pages/user/sop/index?source=rc006' }
|
||||
}];
|
||||
globalThis.uni = {
|
||||
getStorageSync: (key) => storage.get(key) || '',
|
||||
setStorageSync: (key, value) => storage.set(key, value),
|
||||
removeStorageSync: (key) => storage.delete(key),
|
||||
reLaunch: ({ url }) => redirects.push(url),
|
||||
request: ({ fail }) => {
|
||||
queueMicrotask(() => fail({ errMsg: 'request:fail network' }));
|
||||
return { abort: () => {} };
|
||||
},
|
||||
uploadFile: ({ fail, success }) => {
|
||||
queueMicrotask(() => uploadShouldFail
|
||||
? fail({ errMsg: 'uploadFile:fail network' })
|
||||
: success({ statusCode: 200, data: '{"code":200,"data":{"text":"ok"}}' }));
|
||||
return { abort: () => {} };
|
||||
}
|
||||
};
|
||||
|
||||
const vite = await createServer({
|
||||
root: fileURLToPath(new URL('..', import.meta.url)),
|
||||
configFile: false,
|
||||
optimizeDeps: { noDiscovery: true },
|
||||
server: { middlewareMode: true, hmr: false },
|
||||
appType: 'custom'
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await vite.close();
|
||||
delete globalThis.plus;
|
||||
delete globalThis.uni;
|
||||
delete globalThis.window;
|
||||
delete globalThis.getCurrentPages;
|
||||
});
|
||||
|
||||
test('ASR upload failure has a stable retryable result', async () => {
|
||||
uploadShouldFail = true;
|
||||
const { transcribeSpeechFile } = await vite.ssrLoadModule('/src/services/speech.ts');
|
||||
|
||||
await assert.rejects(
|
||||
transcribeSpeechFile({ path: '/tmp/voice.mp3', name: 'voice.mp3', size: 3 }),
|
||||
/语音上传失败/
|
||||
);
|
||||
});
|
||||
|
||||
test('TTS network failure falls back to device speech when supported', async () => {
|
||||
const spoken = [];
|
||||
globalThis.window = {
|
||||
SpeechSynthesisUtterance: class {
|
||||
constructor(text) { this.text = text; }
|
||||
},
|
||||
speechSynthesis: {
|
||||
speak: (utterance) => spoken.push(utterance.text),
|
||||
cancel: () => {}
|
||||
}
|
||||
};
|
||||
const states = [];
|
||||
const errors = [];
|
||||
const { createSpeechPlaybackController } = await vite.ssrLoadModule('/src/services/speech.ts');
|
||||
const controller = createSpeechPlaybackController(
|
||||
(state) => states.push(state.status),
|
||||
(message) => errors.push(message)
|
||||
);
|
||||
|
||||
await controller.toggle('answer-1', '请先确认问题,再说明处理时限');
|
||||
|
||||
assert.deepEqual(spoken, ['请先确认问题,再说明处理时限']);
|
||||
assert.ok(states.includes('loading'));
|
||||
assert.ok(states.includes('playing'));
|
||||
assert.deepEqual(errors, []);
|
||||
controller.destroy();
|
||||
});
|
||||
|
||||
test('401 clears the expired session and relaunches login while 403 does not', async () => {
|
||||
const { ApiError, readPayload } = await vite.ssrLoadModule('/src/services/api.ts');
|
||||
|
||||
assert.throws(
|
||||
() => readPayload(401, { code: 401, msg: 'login expired' }),
|
||||
(error) => error instanceof ApiError && error.statusCode === 401
|
||||
);
|
||||
assert.equal(storage.has('aihr_mobile_access_token'), false);
|
||||
assert.equal(storage.get('aihr_mobile_login_redirect'), '/pages/user/sop/index?source=rc006');
|
||||
assert.deepEqual(redirects, ['/pages/auth/login/index']);
|
||||
|
||||
storage.set('aihr_mobile_access_token', 'new-token');
|
||||
assert.throws(
|
||||
() => readPayload(403, { code: 403, msg: 'forbidden' }),
|
||||
(error) => error instanceof ApiError && error.statusCode === 403
|
||||
);
|
||||
assert.equal(storage.get('aihr_mobile_access_token'), 'new-token');
|
||||
assert.deepEqual(redirects, ['/pages/auth/login/index']);
|
||||
});
|
||||
Reference in New Issue
Block a user