import { expect, Page, test } from '@playwright/test'; import path from 'node:path'; declare global { interface Window { __seedIpOperatorScenario?: (scenario: 'ready') => unknown; } } const scenarioSeedPath = path.resolve(__dirname, '../scripts/validation/ip-operator-scenario-seed.js'); const planKey = 'tiktok.ipOperator.plan.ip_plan_e2e_ready.local-guest'; const viralAnalysisKey = 'videoWorkflow.viralAnalyses.items'; async function seedP2Scenario(page: Page) { await page.addInitScript({ path: scenarioSeedPath }); await page.addInitScript(([nextPlanKey, nextViralAnalysisKey]) => { const now = new Date().toISOString(); window.__seedIpOperatorScenario?.('ready'); localStorage.setItem('tiktok.currentTab', 'ip-operator'); const raw = localStorage.getItem(nextPlanKey); if (!raw) return; const plan = JSON.parse(raw); plan.benchmarkEvidence = [{ id: 'ip_evidence_e2e_existing', planId: plan.id, profileId: plan.profileId, benchmarkId: 'benchmark_e2e_1', source: 'viral_analysis', sourceId: 'analysis_e2e_existing', awemeId: '7123456789012345678', inputUrl: 'https://www.douyin.com/video/7123456789012345678', title: 'E2E benchmark comment evidence', authorName: 'Benchmark Owner Account', summary: 'Users reacted to the account because it named the trust problem before selling.', hookPattern: 'Question hook + hard contrast', reusableFrame: 'Name the hidden trust problem, then replace the case with this IP assets.', commentPainPoints: ['Looks like an ad account', 'No real case proof', 'Unsure whether the owner understands my problem'], migrationSuggestion: 'Use the comment pain to build a trust-diagnosis opportunity, then rewrite topics and scripts around one real owner scenario.', nonCopyableRisk: 'Do not copy the benchmark title, exact wording, claimed result, or industry-specific case.', evidenceRefs: ['comment: Looks like an ad account', 'comment: No real case proof'], confidence: 'high', createdAt: now, }]; plan.evidenceFetchJobs = []; plan.evidenceSuggestions = []; localStorage.setItem(nextPlanKey, JSON.stringify(plan)); localStorage.setItem(nextViralAnalysisKey, JSON.stringify([{ id: 'analysis_e2e_saved', userId: 'local-guest', awemeId: '7987654321098765432', source: 'manual', videoSnapshot: { awemeId: '7987654321098765432', desc: 'E2E saved viral analysis', authorName: 'Saved Benchmark', diggCount: 12000, commentCount: 800, shareCount: 450, }, commentsSnapshot: [ { id: 'c1', text: 'This feels useful because it does not sell first.', likeCount: 99 }, { id: 'c2', text: 'I want to see a real before-after case.', likeCount: 80 }, ], confidence: 'medium', analysis: { summary: 'Saved analysis highlights trust-first owner content.', hookType: 'pain question', openingPattern: 'Ask why users distrust owner accounts', contentRhythm: 'hook-proof-action', conflict: 'selling first vs earning trust first', proofPoint: 'real case detail', audienceEmotion: 'skeptical but interested', commentTrigger: 'asks for before-after examples', reusableFrame: 'replace the case with this IP own client story', reusableAngles: ['trust diagnosis', 'case proof'], riskNotes: ['avoid copying exact claim'], evidenceRefs: ['c1', 'c2'], }, savedTopicIds: [], createdAt: now, updatedAt: now, }])); }, [planKey, viralAnalysisKey]); } test('P2 core links benchmark evidence back to opportunities, topics, scripts, and production', async ({ page }) => { await seedP2Scenario(page); await page.goto('/'); await expect(page.locator('.ip-operator-page')).toBeVisible(); await expect(page.locator('.ip-quality-audit')).toBeVisible(); await expect(page.locator('.ip-evidence-panel')).toBeVisible(); await expect(page.getByText('E2E benchmark comment evidence')).toBeVisible(); await page.locator('.ip-evidence-grid section').first().locator('article button').first().click(); await expect(page.locator('.ip-evidence-suggestions article')).toHaveCount(3); await page.locator('.ip-evidence-suggestions article .btn-primary').first().click(); await expect.poll(async () => page.evaluate((nextPlanKey) => { const plan = JSON.parse(localStorage.getItem(nextPlanKey) || '{}'); return Boolean( plan.evidenceSuggestions?.some((item: { status?: string }) => item.status === 'applied') && plan.opportunityMap?.some((item: { type?: string; reason?: string }) => ( item.type === '评论痛点迁移' && String(item.reason || '').includes('Looks like an ad account') )) ); }, planKey)).toBe(true); await page.locator('.ip-evidence-form').first().locator('input').fill('https://v.douyin.com/short-only/'); await page.locator('.ip-evidence-form').first().locator('button').click(); await expect.poll(async () => page.evaluate((nextPlanKey) => { const plan = JSON.parse(localStorage.getItem(nextPlanKey) || '{}'); return plan.evidenceFetchJobs?.some((job: { status?: string; failureCode?: string }) => ( job.status === 'failed' && job.failureCode === 'invalid_url' )); }, planKey)).toBe(true); const savedForm = page.locator('.ip-evidence-form--saved'); await savedForm.locator('button').first().click(); await savedForm.locator('select').selectOption('analysis_e2e_saved'); await savedForm.locator('button').nth(1).click(); await expect.poll(async () => page.evaluate((nextPlanKey) => { const plan = JSON.parse(localStorage.getItem(nextPlanKey) || '{}'); return Boolean( plan.benchmarkEvidence?.some((item: { sourceId?: string }) => item.sourceId === 'analysis_e2e_saved') && plan.evidenceFetchJobs?.some((job: { analysisId?: string; status?: string }) => ( job.analysisId === 'analysis_e2e_saved' && job.status === 'completed' )) ); }, planKey)).toBe(true); await page.locator('.ip-result-tabs button').nth(1).click(); await expect(page.locator('.ip-topic-card').first()).toBeVisible(); await page.locator('.ip-result-tabs button').nth(2).click(); await expect(page.locator('.ip-script-detail').first()).toBeVisible(); await page.locator('.ip-script-detail').first().locator('.btn-primary').click(); await expect(page.locator('.dh-page')).toBeVisible(); await expect(page.locator('textarea.dh-textarea').first()).not.toHaveValue(''); });