| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- 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('');
- });
|