// 已读取AGENTS.md import * as fs from 'fs'; import * as path from 'path'; /** * 第八十八批:大神语音介绍(录音试听)真实落地。 * 说明:「语音试听」= 大神自我介绍录音;平台不提供实时语音房/连麦。 */ describe('第八十八批语音介绍闸门', () => { const root = path.resolve(__dirname, '../../'); const read = (p: string) => fs.readFileSync(path.join(root, p), 'utf-8'); const indexCode = read('server/src/index.ts'); const repoCode = read('server/src/db/repository.ts'); const mysqlCode = read('server/src/db/mysql.ts'); const api = read('pwuniapp/common/api.js'); const detail = read('pwuniapp/pages/expert/detail.vue'); const workspace = read('pwuniapp/pages/expert/workspace.vue'); it('数据库与仓储支持语音介绍地址/时长', () => { expect(mysqlCode).toContain('voice_intro_url'); expect(repoCode).toContain('voiceIntroUrl'); expect(repoCode).toContain('async updateCompanionVoice('); }); it('提供语音上传接口(音频白名单 + 限流 + 归属校验)', () => { expect(indexCode).toContain("app.post(\n '/api/companions/:id/voice'"); expect(indexCode).toContain("name: 'voice_upload'"); expect(indexCode).toContain("'audio/mpeg'"); expect(indexCode).toContain("assertCompanionActor(req, own, '上传语音介绍')"); expect(indexCode).toContain('fileSize: 5 * 1024 * 1024'); }); it('详情页真实播放(不再用 setTimeout 假动画)', () => { expect(detail).toContain('voiceIntroUrl'); expect(detail).toContain('uni.createInnerAudioContext()'); expect(detail).not.toContain('4s 真实原声'); // 播放器需在卸载时销毁,避免泄漏 expect(detail).toContain('voiceAudio.destroy()'); }); it('工作台支持录音上传与试听', () => { expect(workspace).toContain('uni.getRecorderManager()'); expect(workspace).toContain('uploadVoiceIntro('); expect(workspace).toContain('format: \'mp3\''); expect(workspace).toContain('duration: 60000'); expect(workspace).toContain('uni.createInnerAudioContext()'); }); it('上传类接口携带用户令牌(含图片上传修复)', () => { expect(api).toContain('function authHeader()'); expect(api).toContain('export function uploadVoiceIntro('); expect(api).toContain('header: authHeader()'); }); });