// 已读取AGENTS.md import * as fs from 'fs'; import * as path from 'path'; /** * 第八十二批:服务包为空时的空指针防护。 * 背景:移除"系统自动生成演示服务包"后,大神可能没有任何服务包, * 下单页模板直接取 selectedService.title 会崩(Cannot read properties of null)。 */ describe('第八十二批服务包空值防护闸门', () => { const root = path.resolve(__dirname, '../../'); const createPage = fs.readFileSync(path.join(root, 'pwuniapp/pages/order/create.vue'), 'utf-8'); const detailPage = fs.readFileSync(path.join(root, 'pwuniapp/pages/expert/detail.vue'), 'utf-8'); it('下单页提供 serviceView 安全视图,模板不再直接解引用 selectedService', () => { expect(createPage).toContain('const serviceView = computed('); expect(createPage).toContain('{{ serviceView.title }}'); expect(createPage).toContain('{{ serviceView.price }}'); expect(createPage).toContain('{{ serviceView.unit }}'); expect(createPage).not.toContain('selectedService.title'); expect(createPage).not.toContain('selectedService.price'); expect(createPage).not.toContain('selectedService.unit'); }); it('下单页在无服务包时按大神基础时薪兜底,保证仍可下单', () => { expect(createPage).toContain("id: 'base'"); expect(createPage).toContain('基础陪伴服务'); expect(createPage).toContain('Array.isArray(liveExpert.services) ? liveExpert.services : []'); }); it('详情页取 services[0] 前先判空,并提供空态提示', () => { expect(detailPage).toContain('expert.value.services && expert.value.services.length > 0'); expect(detailPage).toContain('该大神暂未配置服务项目'); }); });