- 起因:上一批移除"系统自动生成演示服务包"后,未配置服务包的大神返回空列表,下单页模板直接取 selectedService.title 触发空指针 - 下单页新增 serviceView 安全视图(computed 带兜底对象),模板统一改用 serviceView.title/price/unit,杜绝解引用 null - 无服务包时按大神基础时薪兜底生成"<品类>基础陪伴服务",保证仍可下单(价格仍由服务端档案价二次校验) - 详情页取 services[0] 前先判空,并新增"暂未配置服务项目"空态提示 - 新增回归护栏 null-service-guard.spec.ts(98 套件/677 用例全绿)
36 行
1.7 KiB
TypeScript
36 行
1.7 KiB
TypeScript
// 已读取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('该大神暂未配置服务项目');
|
||
});
|
||
});
|