package viral import ( "context" "errors" "testing" "haixun-backend/internal/library/placement" ) func TestRunDiscover_skipsFailedKeyword(t *testing.T) { calls := 0 crawler := func(ctx context.Context, m placement.MemberContext, keyword string, limit int) ([]placement.DiscoverPost, error) { calls++ if keyword == "bad" { return nil, errors.New("api timeout") } return []placement.DiscoverPost{{ Text: "轉職面試技巧分享心得", Author: "ok_user", LikeCount: 30, ReplyCount: 4, Permalink: "https://www.threads.net/@ok_user/post/1", Source: placement.DiscoverCrawler, }}, nil } member := placement.MemberContext{ AllowsCrawler: true, BrowserConnected: true, SearchSourceMode: placement.SearchSourceCrawler, } out, err := RunDiscover(context.Background(), DiscoverInput{ Keywords: []string{"bad", "轉職"}, Member: member, Crawler: crawler, MissionScan: true, }, nil) if err != nil { t.Fatalf("expected partial success, got err: %v", err) } if len(out) != 1 { t.Fatalf("expected 1 candidate, got %d", len(out)) } if calls != 2 { t.Fatalf("expected 2 keyword attempts, got %d", calls) } } func TestRunDiscover_missionRelaxedFallbackWithoutVerified(t *testing.T) { crawler := func(ctx context.Context, m placement.MemberContext, keyword string, limit int) ([]placement.DiscoverPost, error) { return []placement.DiscoverPost{{ Text: "轉職心得分享", Author: "plain_user", LikeCount: 12, ReplyCount: 2, Permalink: "https://www.threads.net/@plain_user/post/2", Source: placement.DiscoverThreadsAPI, }}, nil } member := placement.MemberContext{ AllowsCrawler: true, BrowserConnected: true, SearchSourceMode: placement.SearchSourceCrawler, } out, err := RunDiscover(context.Background(), DiscoverInput{ Keywords: []string{"轉職"}, Member: member, Crawler: crawler, MissionScan: true, }, nil) if err != nil { t.Fatalf("unexpected err: %v", err) } if len(out) != 1 { t.Fatalf("expected relaxed fallback candidate, got %d", len(out)) } if out[0].AuthorVerified { t.Fatal("verified should remain false when API omits it") } }