补齐平台订阅、外部登录、CRM 同步与用户端页面;Nginx 转发用户端接口,登录页使用 Google 与 Apple 标志。 Co-authored-by: Cursor <cursoragent@cursor.com>
590 行
20 KiB
TypeScript
590 行
20 KiB
TypeScript
/**
|
|
* OmniCard AI (CRMmp) - mpuniapp 案例作品集详情测试套件 (TDD Red -> Green)
|
|
*
|
|
* 严格按照 AGENTS.md 3.3、4.3、5.1 规范与 PRD pages/portal/case-detail 设计编写
|
|
*/
|
|
|
|
type CaseKpi = {
|
|
label: string;
|
|
value: string;
|
|
};
|
|
|
|
type CaseDetailState = {
|
|
cardId: string;
|
|
blockId: string;
|
|
loading: boolean;
|
|
empty: boolean;
|
|
errorMessage: string;
|
|
title: string;
|
|
content: string;
|
|
images: string[];
|
|
kpis: CaseKpi[];
|
|
pdfUrl: string;
|
|
youtubeUrl: string;
|
|
videoUrl?: string;
|
|
blockType?: string;
|
|
};
|
|
|
|
type CaseDetailPageOptions = {
|
|
cardId?: string;
|
|
blockId?: string;
|
|
id?: string;
|
|
};
|
|
|
|
type MockBentoBlock = {
|
|
id: number | string;
|
|
cardId: string;
|
|
type: string;
|
|
colSpan: number;
|
|
rowSpan: number;
|
|
sortOrder: number;
|
|
title?: string;
|
|
content?: string;
|
|
mediaUrl?: string;
|
|
linkUrl?: string;
|
|
metaJson?:
|
|
| string
|
|
| {
|
|
images?: string[];
|
|
kpis?: CaseKpi[];
|
|
metrics?: CaseKpi[];
|
|
pdfUrl?: string;
|
|
youtubeUrl?: string;
|
|
client?: string;
|
|
industry?: string;
|
|
region?: string;
|
|
challenge?: string;
|
|
solution?: string;
|
|
[key: string]: unknown;
|
|
};
|
|
};
|
|
|
|
type MockPortalCard = {
|
|
id: string;
|
|
name: string;
|
|
title: string;
|
|
company: string;
|
|
status: string;
|
|
bentoBlocks: MockBentoBlock[];
|
|
};
|
|
|
|
type UniRequestSuccessRes = {
|
|
statusCode: number;
|
|
data: unknown;
|
|
header: Record<string, string>;
|
|
};
|
|
|
|
type UniRequestOption = {
|
|
url: string;
|
|
method?: string;
|
|
data?: Record<string, string>;
|
|
success?: (res: UniRequestSuccessRes) => void;
|
|
fail?: (err: { errMsg: string }) => void;
|
|
complete?: () => void;
|
|
};
|
|
|
|
type UseCaseDetailModule = {
|
|
createCaseDetailState: () => CaseDetailState;
|
|
applyCaseDetailOptions: (
|
|
state: CaseDetailState,
|
|
options: CaseDetailPageOptions | null
|
|
) => boolean;
|
|
pickCaseBlock: (
|
|
card: MockPortalCard | null,
|
|
blockId: string
|
|
) => MockBentoBlock | null;
|
|
applyPortalCase: (state: CaseDetailState, card: MockPortalCard | null) => boolean;
|
|
loadCaseDetail: (state: CaseDetailState) => Promise<boolean>;
|
|
buildExchangePath: (cardId: string) => string;
|
|
openCaseExchange: (cardId: string) => void;
|
|
goCaseBack: () => void;
|
|
openCaseExternalLink: (url: string) => boolean;
|
|
resolveCaseDetailText: (key: string) => string;
|
|
};
|
|
|
|
function loadUseCaseDetail(): UseCaseDetailModule {
|
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
return require('../../../mpuniapp/pages/portal/useCaseDetail.uts') as UseCaseDetailModule;
|
|
}
|
|
|
|
function buildMockPortal(): MockPortalCard {
|
|
return {
|
|
id: 'card-101',
|
|
name: 'Alex Vance',
|
|
title: 'Managing Director & Global Partner',
|
|
company: 'Nexus Tech Global Ltd',
|
|
status: 'published',
|
|
bentoBlocks: [
|
|
{
|
|
id: 1,
|
|
cardId: 'card-101',
|
|
type: 'hero',
|
|
colSpan: 2,
|
|
rowSpan: 1,
|
|
sortOrder: 0,
|
|
title: 'Hero Block',
|
|
},
|
|
{
|
|
id: 2,
|
|
cardId: 'card-101',
|
|
type: 'case',
|
|
colSpan: 2,
|
|
rowSpan: 1,
|
|
sortOrder: 1,
|
|
title: 'Middle East Energy Hub',
|
|
content: 'Built scalable renewable energy microgrid in UAE.',
|
|
mediaUrl: 'https://cdn.omnicard.ai/case/cover.jpg',
|
|
metaJson: {
|
|
images: [
|
|
'https://cdn.omnicard.ai/case/1.jpg',
|
|
'https://cdn.omnicard.ai/case/2.jpg',
|
|
],
|
|
kpis: [{ label: 'ROI', value: '32%' }],
|
|
pdfUrl: 'https://cdn.omnicard.ai/case/brief.pdf',
|
|
youtubeUrl: 'https://www.youtube.com/watch?v=abc123',
|
|
},
|
|
},
|
|
{
|
|
id: 3,
|
|
cardId: 'card-101',
|
|
type: 'article',
|
|
colSpan: 1,
|
|
rowSpan: 1,
|
|
sortOrder: 2,
|
|
title: 'The Future of Cross-Border Trade',
|
|
},
|
|
{
|
|
id: 4,
|
|
cardId: 'card-101',
|
|
type: 'video',
|
|
colSpan: 2,
|
|
rowSpan: 2,
|
|
sortOrder: 3,
|
|
title: 'Automation Screening Lab Video Demo',
|
|
content: 'Robotic arms 7x24 high throughput screening.',
|
|
mediaUrl: 'https://cdn.omnicard.ai/video/poster.jpg',
|
|
linkUrl: 'https://cdn.omnicard.ai/video/demo.mp4',
|
|
metaJson: {
|
|
videoUrl: 'https://cdn.omnicard.ai/video/demo.mp4',
|
|
poster: 'https://cdn.omnicard.ai/video/poster.jpg',
|
|
duration: '02:05',
|
|
kpis: [{ label: 'Speedup', value: '4.2x' }],
|
|
},
|
|
},
|
|
],
|
|
};
|
|
}
|
|
|
|
describe('OmniCard AI 用户端案例详情业务逻辑测试 (useCaseDetail.uts)', () => {
|
|
let lastRequestOptions: UniRequestOption | null;
|
|
let navigateToUrl: string;
|
|
let navigateBackCount: number;
|
|
let openUrlCalls: string[];
|
|
let mockRequestResponse: {
|
|
statusCode?: number;
|
|
data?: {
|
|
code?: number;
|
|
message?: string;
|
|
data?: MockPortalCard | null;
|
|
};
|
|
failError?: { errMsg: string };
|
|
};
|
|
let originalWindow: (Window & typeof globalThis) | undefined;
|
|
|
|
beforeEach(() => {
|
|
lastRequestOptions = null;
|
|
navigateToUrl = '';
|
|
navigateBackCount = 0;
|
|
openUrlCalls = [];
|
|
mockRequestResponse = {
|
|
statusCode: 200,
|
|
data: {
|
|
code: 1000,
|
|
message: 'success',
|
|
data: buildMockPortal(),
|
|
},
|
|
};
|
|
|
|
originalWindow = (global as { window?: Window & typeof globalThis }).window;
|
|
(global as { window?: { open: (url: string, target?: string) => null } }).window = {
|
|
open: (url: string) => {
|
|
openUrlCalls.push(url);
|
|
return null;
|
|
},
|
|
};
|
|
|
|
(global as { uni?: Record<string, unknown> }).uni = {
|
|
getStorageSync: () => '',
|
|
setStorageSync: () => undefined,
|
|
showToast: () => undefined,
|
|
setClipboardData: () => undefined,
|
|
navigateTo: (options: { url: string }) => {
|
|
navigateToUrl = options.url;
|
|
},
|
|
navigateBack: () => {
|
|
navigateBackCount += 1;
|
|
},
|
|
request: (options: UniRequestOption) => {
|
|
lastRequestOptions = options;
|
|
setTimeout(() => {
|
|
if (mockRequestResponse.failError) {
|
|
options.fail?.(mockRequestResponse.failError);
|
|
} else {
|
|
options.success?.({
|
|
statusCode: mockRequestResponse.statusCode ?? 200,
|
|
data: mockRequestResponse.data,
|
|
header: {},
|
|
});
|
|
}
|
|
options.complete?.();
|
|
}, 0);
|
|
return {
|
|
abort: () => undefined,
|
|
};
|
|
},
|
|
};
|
|
});
|
|
|
|
afterEach(() => {
|
|
delete (global as { uni?: unknown }).uni;
|
|
if (originalWindow != null) {
|
|
(global as { window?: Window & typeof globalThis }).window = originalWindow;
|
|
} else {
|
|
delete (global as { window?: unknown }).window;
|
|
}
|
|
});
|
|
|
|
describe('1. 从门户聚合数据选出 case 块', () => {
|
|
it('1.1 能从 mock portal 数据选出 id 匹配且 type 为 case 的块', () => {
|
|
const { pickCaseBlock } = loadUseCaseDetail();
|
|
const card = buildMockPortal();
|
|
|
|
const block = pickCaseBlock(card, '2');
|
|
|
|
expect(block).not.toBeNull();
|
|
expect(block?.type).toBe('case');
|
|
expect(block?.title).toBe('Middle East Energy Hub');
|
|
expect(block?.content).toContain('renewable');
|
|
});
|
|
|
|
it('1.2 applyPortalCase 写入标题、正文、多图、KPI 与外链', () => {
|
|
const { createCaseDetailState, applyCaseDetailOptions, applyPortalCase } =
|
|
loadUseCaseDetail();
|
|
|
|
const state = createCaseDetailState();
|
|
applyCaseDetailOptions(state, { cardId: 'card-101', blockId: '2' });
|
|
const found = applyPortalCase(state, buildMockPortal());
|
|
|
|
expect(found).toBe(true);
|
|
expect(state.empty).toBe(false);
|
|
expect(state.title).toBe('Middle East Energy Hub');
|
|
expect(state.content).toBe(
|
|
'Built scalable renewable energy microgrid in UAE.'
|
|
);
|
|
expect(state.images).toEqual([
|
|
'https://cdn.omnicard.ai/case/1.jpg',
|
|
'https://cdn.omnicard.ai/case/2.jpg',
|
|
]);
|
|
expect(state.kpis).toEqual([{ label: 'ROI', value: '32%' }]);
|
|
expect(state.pdfUrl).toBe('https://cdn.omnicard.ai/case/brief.pdf');
|
|
expect(state.youtubeUrl).toBe('https://www.youtube.com/watch?v=abc123');
|
|
});
|
|
|
|
it('1.3 无 images 时回退 mediaUrl 单图,metrics 可作为 KPI', () => {
|
|
const { createCaseDetailState, applyCaseDetailOptions, applyPortalCase } =
|
|
loadUseCaseDetail();
|
|
const card = buildMockPortal();
|
|
card.bentoBlocks[1].mediaUrl = 'https://cdn.omnicard.ai/case/cover.jpg';
|
|
card.bentoBlocks[1].metaJson = {
|
|
metrics: [{ label: 'Capacity', value: '120MW' }],
|
|
};
|
|
|
|
const state = createCaseDetailState();
|
|
applyCaseDetailOptions(state, { cardId: 'card-101', blockId: '2' });
|
|
applyPortalCase(state, card);
|
|
|
|
expect(state.images).toEqual(['https://cdn.omnicard.ai/case/cover.jpg']);
|
|
expect(state.kpis).toEqual([{ label: 'Capacity', value: '120MW' }]);
|
|
});
|
|
|
|
it('1.4 metaJson 为字符串且 metrics 使用 name 时仍能解析', () => {
|
|
const { createCaseDetailState, applyCaseDetailOptions, applyPortalCase } =
|
|
loadUseCaseDetail();
|
|
const card = buildMockPortal();
|
|
card.bentoBlocks[1].metaJson = JSON.stringify({
|
|
metrics: [{ name: 'Uplift', value: 18 }],
|
|
});
|
|
|
|
const state = createCaseDetailState();
|
|
applyCaseDetailOptions(state, { cardId: 'card-101', blockId: '2' });
|
|
applyPortalCase(state, card);
|
|
|
|
expect(state.kpis).toEqual([{ label: 'Uplift', value: '18' }]);
|
|
});
|
|
});
|
|
|
|
describe('2. 缺 block 返空', () => {
|
|
it('2.1 找不到 blockId 时 pickCaseBlock 返回 null', () => {
|
|
const { pickCaseBlock } = loadUseCaseDetail();
|
|
const block = pickCaseBlock(buildMockPortal(), '999');
|
|
expect(block).toBeNull();
|
|
});
|
|
|
|
it('2.2 id 匹配但 type 不是 case 时同样返空', () => {
|
|
const { pickCaseBlock } = loadUseCaseDetail();
|
|
const article = pickCaseBlock(buildMockPortal(), '3');
|
|
const hero = pickCaseBlock(buildMockPortal(), '1');
|
|
expect(article).toBeNull();
|
|
expect(hero).toBeNull();
|
|
});
|
|
|
|
it('2.3 applyPortalCase 缺块时 empty=true 且展示字段清空', () => {
|
|
const { createCaseDetailState, applyCaseDetailOptions, applyPortalCase } =
|
|
loadUseCaseDetail();
|
|
|
|
const state = createCaseDetailState();
|
|
applyCaseDetailOptions(state, { cardId: 'card-101', blockId: '999' });
|
|
const found = applyPortalCase(state, buildMockPortal());
|
|
|
|
expect(found).toBe(false);
|
|
expect(state.empty).toBe(true);
|
|
expect(state.loading).toBe(false);
|
|
expect(state.title).toBe('');
|
|
expect(state.content).toBe('');
|
|
expect(state.images).toEqual([]);
|
|
expect(state.kpis).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('3. onLoad 拉取门户详情', () => {
|
|
it('3.1 loadCaseDetail 通过 fetchPortalCard 选出 case 块', async () => {
|
|
const { createCaseDetailState, applyCaseDetailOptions, loadCaseDetail } =
|
|
loadUseCaseDetail();
|
|
|
|
const state = createCaseDetailState();
|
|
applyCaseDetailOptions(state, { cardId: 'card-101', blockId: '2' });
|
|
const found = await loadCaseDetail(state);
|
|
|
|
expect(found).toBe(true);
|
|
expect(lastRequestOptions).not.toBeNull();
|
|
expect(lastRequestOptions?.url).toContain('/open/card/portal/detail');
|
|
expect(state.empty).toBe(false);
|
|
expect(state.title).toBe('Middle East Energy Hub');
|
|
});
|
|
|
|
it('3.2 缺 block 时 loadCaseDetail 返空', async () => {
|
|
const { createCaseDetailState, applyCaseDetailOptions, loadCaseDetail } =
|
|
loadUseCaseDetail();
|
|
|
|
const state = createCaseDetailState();
|
|
applyCaseDetailOptions(state, { cardId: 'card-101', blockId: '888' });
|
|
const found = await loadCaseDetail(state);
|
|
|
|
expect(found).toBe(false);
|
|
expect(state.empty).toBe(true);
|
|
expect(state.title).toBe('');
|
|
});
|
|
|
|
it('3.3 缺少 cardId 或 blockId 时不请求并返空', async () => {
|
|
const { createCaseDetailState, applyCaseDetailOptions, loadCaseDetail } =
|
|
loadUseCaseDetail();
|
|
|
|
const state = createCaseDetailState();
|
|
applyCaseDetailOptions(state, {});
|
|
const found = await loadCaseDetail(state);
|
|
|
|
expect(found).toBe(false);
|
|
expect(state.empty).toBe(true);
|
|
expect(lastRequestOptions).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('4. 咨询互换 CTA', () => {
|
|
it('4.1 主 CTA 跳转 /pages/portal/exchange?cardId=', () => {
|
|
const { buildExchangePath, openCaseExchange } = loadUseCaseDetail();
|
|
|
|
expect(buildExchangePath('card-101')).toBe(
|
|
'/pages/portal/exchange?cardId=card-101'
|
|
);
|
|
|
|
openCaseExchange('card-101');
|
|
expect(navigateToUrl).toBe('/pages/portal/exchange?cardId=card-101');
|
|
});
|
|
|
|
it('4.2 空状态返回调用 navigateBack', () => {
|
|
const { goCaseBack } = loadUseCaseDetail();
|
|
goCaseBack();
|
|
expect(navigateBackCount).toBe(1);
|
|
});
|
|
});
|
|
|
|
describe('5. Bento Grid 模块化结构化数据与国际化解析', () => {
|
|
it('5.1 支持从 metaJson 解析 client, industry, region, challenge, solution', () => {
|
|
const { createCaseDetailState, applyCaseDetailOptions, applyPortalCase } =
|
|
loadUseCaseDetail();
|
|
const card = buildMockPortal();
|
|
card.bentoBlocks[1].metaJson = {
|
|
client: 'Global Logistics Corp',
|
|
industry: 'Supply Chain IoT',
|
|
region: 'Middle East & North Africa',
|
|
challenge: 'High latency in cross-border tracking and data silos.',
|
|
solution: 'Deployed dual-frequency NFC sensors and cloud-native mesh.',
|
|
kpis: [{ label: 'On-time Delivery', value: '99.8%' }],
|
|
};
|
|
|
|
const state = createCaseDetailState();
|
|
applyCaseDetailOptions(state, { cardId: 'card-101', blockId: '2' });
|
|
applyPortalCase(state, card);
|
|
|
|
expect((state as any).client).toBe('Global Logistics Corp');
|
|
expect((state as any).industry).toBe('Supply Chain IoT');
|
|
expect((state as any).region).toBe('Middle East & North Africa');
|
|
expect((state as any).challenge).toBe(
|
|
'High latency in cross-border tracking and data silos.'
|
|
);
|
|
expect((state as any).solution).toBe(
|
|
'Deployed dual-frequency NFC sensors and cloud-native mesh.'
|
|
);
|
|
expect(state.kpis).toEqual([{ label: 'On-time Delivery', value: '99.8%' }]);
|
|
});
|
|
|
|
it('5.2 resolveCaseDetailText 外链行动作为打开语义(中英,非裸复制)', () => {
|
|
const { resolveCaseDetailText } = loadUseCaseDetail();
|
|
|
|
expect(resolveCaseDetailText('badge')).toBeDefined();
|
|
expect(resolveCaseDetailText('overview')).toBeDefined();
|
|
expect(resolveCaseDetailText('challenge')).toBeDefined();
|
|
expect(resolveCaseDetailText('solution')).toBeDefined();
|
|
expect(resolveCaseDetailText('kpis')).toBeDefined();
|
|
expect(resolveCaseDetailText('resources')).toBeDefined();
|
|
|
|
const pdfAction = resolveCaseDetailText('pdfAction');
|
|
const videoAction = resolveCaseDetailText('videoAction');
|
|
expect(pdfAction.length).toBeGreaterThan(0);
|
|
expect(videoAction.length).toBeGreaterThan(0);
|
|
expect(pdfAction).not.toMatch(/^https?:\/\//i);
|
|
expect(videoAction).not.toMatch(/^https?:\/\//i);
|
|
expect(pdfAction.toLowerCase()).not.toContain('copy');
|
|
expect(videoAction.toLowerCase()).not.toContain('copy');
|
|
expect(pdfAction).not.toContain('复制');
|
|
expect(videoAction).not.toContain('复制');
|
|
});
|
|
|
|
it('5.3 openCaseExternalLink 有 url 时 window.open 打开外链', () => {
|
|
const { openCaseExternalLink } = loadUseCaseDetail();
|
|
const pdf = 'https://cdn.omnicard.ai/case/brief.pdf';
|
|
const video = 'https://www.youtube.com/watch?v=abc123';
|
|
|
|
expect(openCaseExternalLink(pdf)).toBe(true);
|
|
expect(openCaseExternalLink(video)).toBe(true);
|
|
expect(openUrlCalls).toEqual([pdf, video]);
|
|
});
|
|
|
|
it('5.4 openCaseExternalLink 无 url 时不打开、不复制', () => {
|
|
let clipboardCalls = 0;
|
|
(global as { uni?: Record<string, unknown> }).uni = {
|
|
...(global as { uni?: Record<string, unknown> }).uni,
|
|
setClipboardData: () => {
|
|
clipboardCalls += 1;
|
|
},
|
|
};
|
|
|
|
const { openCaseExternalLink } = loadUseCaseDetail();
|
|
expect(openCaseExternalLink('')).toBe(false);
|
|
expect(openCaseExternalLink(' ')).toBe(false);
|
|
expect(openUrlCalls).toEqual([]);
|
|
expect(clipboardCalls).toBe(0);
|
|
});
|
|
|
|
it('5.5 缺 pdf/youtube 时 applyPortalCase 外链字段为空(页面应隐藏行)', () => {
|
|
const { createCaseDetailState, applyCaseDetailOptions, applyPortalCase } =
|
|
loadUseCaseDetail();
|
|
const card = buildMockPortal();
|
|
card.bentoBlocks[1].metaJson = {
|
|
kpis: [{ label: 'ROI', value: '32%' }],
|
|
};
|
|
|
|
const state = createCaseDetailState();
|
|
applyCaseDetailOptions(state, { cardId: 'card-101', blockId: '2' });
|
|
applyPortalCase(state, card);
|
|
|
|
expect(state.pdfUrl).toBe('');
|
|
expect(state.youtubeUrl).toBe('');
|
|
});
|
|
});
|
|
|
|
describe('6. 视频演示 (video) 块详情支持与直链解析 (TDD)', () => {
|
|
it('6.1 pickCaseBlock 支持匹配 type 为 video 的块', () => {
|
|
const { pickCaseBlock } = loadUseCaseDetail();
|
|
const card = buildMockPortal();
|
|
|
|
const block = pickCaseBlock(card, '4');
|
|
expect(block).not.toBeNull();
|
|
expect(block?.type).toBe('video');
|
|
expect(block?.title).toBe('Automation Screening Lab Video Demo');
|
|
});
|
|
|
|
it('6.2 applyPortalCase 对 video 块能正确提取 videoUrl、blockType 与海报封面', () => {
|
|
const { createCaseDetailState, applyCaseDetailOptions, applyPortalCase } =
|
|
loadUseCaseDetail();
|
|
|
|
const state = createCaseDetailState();
|
|
applyCaseDetailOptions(state, { cardId: 'card-101', blockId: '4' });
|
|
const found = applyPortalCase(state, buildMockPortal());
|
|
|
|
expect(found).toBe(true);
|
|
expect(state.empty).toBe(false);
|
|
expect((state as any).blockType).toBe('video');
|
|
expect((state as any).videoUrl).toBe('https://cdn.omnicard.ai/video/demo.mp4');
|
|
expect(state.title).toBe('Automation Screening Lab Video Demo');
|
|
expect(state.content).toBe('Robotic arms 7x24 high throughput screening.');
|
|
expect(state.images).toContain('https://cdn.omnicard.ai/video/poster.jpg');
|
|
expect(state.kpis).toEqual([{ label: 'Speedup', value: '4.2x' }]);
|
|
});
|
|
|
|
it('6.3 无 metaJson.videoUrl 时,能回退从 block.linkUrl 解析为 videoUrl', () => {
|
|
const { createCaseDetailState, applyCaseDetailOptions, applyPortalCase } =
|
|
loadUseCaseDetail();
|
|
const card = buildMockPortal();
|
|
card.bentoBlocks[3].metaJson = {};
|
|
card.bentoBlocks[3].linkUrl = 'https://cdn.omnicard.ai/sample/lab.mp4';
|
|
|
|
const state = createCaseDetailState();
|
|
applyCaseDetailOptions(state, { cardId: 'card-101', blockId: '4' });
|
|
applyPortalCase(state, card);
|
|
|
|
expect((state as any).videoUrl).toBe('https://cdn.omnicard.ai/sample/lab.mp4');
|
|
});
|
|
|
|
it('6.4 当视频链接为 YouTube 时,能正确解析为 youtubeUrl', () => {
|
|
const { createCaseDetailState, applyCaseDetailOptions, applyPortalCase } =
|
|
loadUseCaseDetail();
|
|
const card = buildMockPortal();
|
|
card.bentoBlocks[3].metaJson = {
|
|
youtubeUrl: 'https://www.youtube.com/watch?v=xyz789',
|
|
};
|
|
card.bentoBlocks[3].linkUrl = '';
|
|
|
|
const state = createCaseDetailState();
|
|
applyCaseDetailOptions(state, { cardId: 'card-101', blockId: '4' });
|
|
applyPortalCase(state, card);
|
|
|
|
expect(state.youtubeUrl).toBe('https://www.youtube.com/watch?v=xyz789');
|
|
});
|
|
|
|
it('6.5 loadCaseDetail 针对 video 块能异步正常加载且 empty=false', async () => {
|
|
const { createCaseDetailState, applyCaseDetailOptions, loadCaseDetail } =
|
|
loadUseCaseDetail();
|
|
|
|
const state = createCaseDetailState();
|
|
applyCaseDetailOptions(state, { cardId: 'card-101', blockId: '4' });
|
|
const found = await loadCaseDetail(state);
|
|
|
|
expect(found).toBe(true);
|
|
expect(state.empty).toBe(false);
|
|
expect((state as any).videoUrl).toBe('https://cdn.omnicard.ai/video/demo.mp4');
|
|
expect(state.title).toBe('Automation Screening Lab Video Demo');
|
|
});
|
|
});
|
|
});
|