import { describe, expect, it } from 'vitest'; import { IpAccountSnapshot, IpAccountStrategyEvidenceRef, } from '../models/ip-operator.model'; import { IpAccountWorkReportService } from './ip-account-work-report.service'; describe('IpAccountWorkReportService', () => { const service = new IpAccountWorkReportService(); it('builds work bundles with comments as supporting evidence only', () => { const bundles = service.buildWorkEvidenceBundles(snapshotFixture(), rawRefsFixture()); expect(bundles).toHaveLength(1); expect(bundles[0].workId).toBe('work-1'); expect(bundles[0].workEvidenceRefId).toBe('ev_work_1'); expect(bundles[0].transcriptText).toContain('新手先判断任务'); expect(bundles[0].commentEvidenceRefs.map((item) => item.id)).toEqual(['ev_comment_1', 'ev_comment_2']); }); it('does not build work bundles when a work has no transcript', () => { const snapshot = snapshotFixture(); delete snapshot.works[0].transcript; const bundles = service.buildWorkEvidenceBundles(snapshot, rawRefsFixture()); const reports = service.buildLocalFallbackWorkReports({ now: '2026-07-01T00:00:00.000Z', bundles, }); expect(bundles).toEqual([]); expect(reports).toEqual([]); expect(service.missingTranscriptWorkIds(snapshot)).toEqual(['work-1']); }); it('converts parsed work reports into analyzed work report evidence refs', () => { const reports = service.normalizeParsedWorkReports({ now: '2026-07-01T00:00:00.000Z', sourceMode: 'llm', parsedReports: [{ workId: 'work-1', reports: [{ kind: 'operation', headline: '新手真实卡点集中', summary: '评论集中在工具安装顺序和选择成本。', evidenceSignals: ['收藏高', '评论多为安装问题'], strategyJudgment: '适合做新手避坑和工具选择栏目。', supportingEvidenceIds: ['ev_comment_1', 'ev_comment_2'], confidence: 'high', gaps: [], }], }], bundles: service.buildWorkEvidenceBundles(snapshotFixture(), rawRefsFixture()), }); const evidenceRefs = service.toWorkReportEvidenceRefs(reports); expect(reports[0].id).toBe('work_report_work-1'); expect(evidenceRefs[0]).toMatchObject({ id: 'work_report_work-1', sourceType: 'owned_work', sourceId: 'work-1', analyzed: true, stage: 'work_report', }); expect(evidenceRefs[0].reason).toContain('适合做新手避坑'); }); it('builds local fallback work reports without pretending they are LLM analysis', () => { const reports = service.buildLocalFallbackWorkReports({ now: '2026-07-01T00:00:00.000Z', bundles: service.buildWorkEvidenceBundles(snapshotFixture(), rawRefsFixture()), }); const evidenceRefs = service.toWorkReportEvidenceRefs(reports); expect(reports[0].sourceMode).toBe('local_fallback'); expect(evidenceRefs[0].analyzed).toBe(false); expect(evidenceRefs[0].reason).toContain('未经过 LLM 独立判断'); }); }); function snapshotFixture(): IpAccountSnapshot { return { id: 'snapshot-1', accountId: 'account-1', capturedAt: '2026-07-01T00:00:00.000Z', dataMode: 'data_diagnosis', warnings: [], evidenceItemIds: [], profile: { nickname: 'FredTalk', signature: 'Vibe Coding 实操', followerCount: 1000, followingCount: 10, totalFavorited: 2000, awemeCount: 10, }, works: [{ id: 'work-1', accountId: 'account-1', awemeId: 'aweme-1', title: '新手小白安装这六个 Skills 就行够了', desc: '工具安装顺序和选择建议', publishTime: '2026-06-30T00:00:00.000Z', transcript: { text: '新手先判断任务,再选择对应工具。视频逐步讲了安装顺序、常见误区和每个工具的使用边界。', source: 'asr', confidence: 'high', capturedAt: '2026-07-01T00:00:00.000Z', }, metrics: { playCount: 0, likeCount: 58850, commentCount: 1036, collectCount: 61773, shareCount: 9581 }, interactionScore: 120, isDeepSampled: true, structure: { hook: '新手安装清单', topic: '工具选择', style: '教程', cta: '收藏' }, comments: [ { id: 'comment-1', workId: 'work-1', text: '刚开始不知道先用哪个工具', likeCount: 20, capturedAt: '2026-06-30T01:00:00.000Z' }, { id: 'comment-2', workId: 'work-1', text: '安装了很多但是不知道流程', likeCount: 12, capturedAt: '2026-06-30T02:00:00.000Z' }, ], capturedAt: '2026-07-01T00:00:00.000Z', }], }; } function rawRefsFixture(): IpAccountStrategyEvidenceRef[] { return [ { id: 'ev_work_1', sourceType: 'owned_work', sourceId: 'work-1', label: '高互动作品 1', quote: '新手小白安装这六个 Skills 就行够了', reason: '互动分 120,赞 58850,评 1036', stage: 'raw_context', analyzed: false, }, { id: 'ev_comment_1', sourceType: 'owned_comment', sourceId: 'comment-1', label: '重点评论', quote: '刚开始不知道先用哪个工具', reason: '原始评论样本', stage: 'raw_context', analyzed: false, }, { id: 'ev_comment_2', sourceType: 'owned_comment', sourceId: 'comment-2', label: '重点评论', quote: '安装了很多但是不知道流程', reason: '原始评论样本', stage: 'raw_context', analyzed: false, }, ]; }