A community based topic aggregation platform built on atproto

test(community): add comprehensive list endpoint tests

Add comprehensive test coverage for social.coves.community.list
endpoint with all parameter combinations.

**New Test Cases:**
- List with sort=popular (default)
- List with sort=active
- List with sort=new
- List with sort=alphabetical (validates actual ordering)
- List with invalid sort value (expects 400)
- List with visibility filter
- List with default sort (no parameter)
- List with limit bounds validation

**Test Cleanup:**
- Remove deprecated "total" field from response structs
- Add "cursor" field to all list response structs
- Update repository tests for new List() signature

All tests passing ✅

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

+187 -7
+185 -1
tests/integration/community_e2e_test.go
··· 535 535 536 536 var listResp struct { 537 537 Communities []communities.Community `json:"communities"` 538 - Total int `json:"total"` 538 + Cursor string `json:"cursor"` 539 539 } 540 540 541 541 if err := json.NewDecoder(resp.Body).Decode(&listResp); err != nil { ··· 547 547 if len(listResp.Communities) < 3 { 548 548 t.Errorf("Expected at least 3 communities, got %d", len(listResp.Communities)) 549 549 } 550 + }) 551 + 552 + t.Run("List with sort=popular (default)", func(t *testing.T) { 553 + resp, err := http.Get(fmt.Sprintf("%s/xrpc/social.coves.community.list?sort=popular&limit=10", 554 + httpServer.URL)) 555 + if err != nil { 556 + t.Fatalf("Failed to GET list with sort=popular: %v", err) 557 + } 558 + defer func() { _ = resp.Body.Close() }() 559 + 560 + if resp.StatusCode != http.StatusOK { 561 + body, _ := io.ReadAll(resp.Body) 562 + t.Fatalf("Expected 200, got %d: %s", resp.StatusCode, string(body)) 563 + } 564 + 565 + var listResp struct { 566 + Communities []communities.Community `json:"communities"` 567 + Cursor string `json:"cursor"` 568 + } 569 + if err := json.NewDecoder(resp.Body).Decode(&listResp); err != nil { 570 + t.Fatalf("Failed to decode response: %v", err) 571 + } 572 + 573 + t.Logf("✅ Listed %d communities sorted by popular (subscriber_count DESC)", len(listResp.Communities)) 574 + }) 575 + 576 + t.Run("List with sort=active", func(t *testing.T) { 577 + resp, err := http.Get(fmt.Sprintf("%s/xrpc/social.coves.community.list?sort=active&limit=10", 578 + httpServer.URL)) 579 + if err != nil { 580 + t.Fatalf("Failed to GET list with sort=active: %v", err) 581 + } 582 + defer func() { _ = resp.Body.Close() }() 583 + 584 + if resp.StatusCode != http.StatusOK { 585 + body, _ := io.ReadAll(resp.Body) 586 + t.Fatalf("Expected 200, got %d: %s", resp.StatusCode, string(body)) 587 + } 588 + 589 + t.Logf("✅ Listed communities sorted by active (post_count DESC)") 590 + }) 591 + 592 + t.Run("List with sort=new", func(t *testing.T) { 593 + resp, err := http.Get(fmt.Sprintf("%s/xrpc/social.coves.community.list?sort=new&limit=10", 594 + httpServer.URL)) 595 + if err != nil { 596 + t.Fatalf("Failed to GET list with sort=new: %v", err) 597 + } 598 + defer func() { _ = resp.Body.Close() }() 599 + 600 + if resp.StatusCode != http.StatusOK { 601 + body, _ := io.ReadAll(resp.Body) 602 + t.Fatalf("Expected 200, got %d: %s", resp.StatusCode, string(body)) 603 + } 604 + 605 + t.Logf("✅ Listed communities sorted by new (created_at DESC)") 606 + }) 607 + 608 + t.Run("List with sort=alphabetical", func(t *testing.T) { 609 + resp, err := http.Get(fmt.Sprintf("%s/xrpc/social.coves.community.list?sort=alphabetical&limit=10", 610 + httpServer.URL)) 611 + if err != nil { 612 + t.Fatalf("Failed to GET list with sort=alphabetical: %v", err) 613 + } 614 + defer func() { _ = resp.Body.Close() }() 615 + 616 + if resp.StatusCode != http.StatusOK { 617 + body, _ := io.ReadAll(resp.Body) 618 + t.Fatalf("Expected 200, got %d: %s", resp.StatusCode, string(body)) 619 + } 620 + 621 + var listResp struct { 622 + Communities []communities.Community `json:"communities"` 623 + Cursor string `json:"cursor"` 624 + } 625 + if err := json.NewDecoder(resp.Body).Decode(&listResp); err != nil { 626 + t.Fatalf("Failed to decode response: %v", err) 627 + } 628 + 629 + // Verify alphabetical ordering 630 + if len(listResp.Communities) > 1 { 631 + for i := 0; i < len(listResp.Communities)-1; i++ { 632 + if listResp.Communities[i].Name > listResp.Communities[i+1].Name { 633 + t.Errorf("Communities not in alphabetical order: %s > %s", 634 + listResp.Communities[i].Name, listResp.Communities[i+1].Name) 635 + } 636 + } 637 + } 638 + 639 + t.Logf("✅ Listed communities sorted alphabetically (name ASC)") 640 + }) 641 + 642 + t.Run("List with invalid sort value", func(t *testing.T) { 643 + resp, err := http.Get(fmt.Sprintf("%s/xrpc/social.coves.community.list?sort=invalid&limit=10", 644 + httpServer.URL)) 645 + if err != nil { 646 + t.Fatalf("Failed to GET list with invalid sort: %v", err) 647 + } 648 + defer func() { _ = resp.Body.Close() }() 649 + 650 + if resp.StatusCode != http.StatusBadRequest { 651 + body, _ := io.ReadAll(resp.Body) 652 + t.Fatalf("Expected 400 for invalid sort, got %d: %s", resp.StatusCode, string(body)) 653 + } 654 + 655 + t.Logf("✅ Rejected invalid sort value with 400") 656 + }) 657 + 658 + t.Run("List with visibility filter", func(t *testing.T) { 659 + resp, err := http.Get(fmt.Sprintf("%s/xrpc/social.coves.community.list?visibility=public&limit=10", 660 + httpServer.URL)) 661 + if err != nil { 662 + t.Fatalf("Failed to GET list with visibility filter: %v", err) 663 + } 664 + defer func() { _ = resp.Body.Close() }() 665 + 666 + if resp.StatusCode != http.StatusOK { 667 + body, _ := io.ReadAll(resp.Body) 668 + t.Fatalf("Expected 200, got %d: %s", resp.StatusCode, string(body)) 669 + } 670 + 671 + var listResp struct { 672 + Communities []communities.Community `json:"communities"` 673 + Cursor string `json:"cursor"` 674 + } 675 + if err := json.NewDecoder(resp.Body).Decode(&listResp); err != nil { 676 + t.Fatalf("Failed to decode response: %v", err) 677 + } 678 + 679 + // Verify all communities have public visibility 680 + for _, comm := range listResp.Communities { 681 + if comm.Visibility != "public" { 682 + t.Errorf("Expected all communities to have visibility=public, got %s for %s", 683 + comm.Visibility, comm.DID) 684 + } 685 + } 686 + 687 + t.Logf("✅ Listed %d public communities", len(listResp.Communities)) 688 + }) 689 + 690 + t.Run("List with default sort (no parameter)", func(t *testing.T) { 691 + // Should default to sort=popular 692 + resp, err := http.Get(fmt.Sprintf("%s/xrpc/social.coves.community.list?limit=10", 693 + httpServer.URL)) 694 + if err != nil { 695 + t.Fatalf("Failed to GET list with default sort: %v", err) 696 + } 697 + defer func() { _ = resp.Body.Close() }() 698 + 699 + if resp.StatusCode != http.StatusOK { 700 + body, _ := io.ReadAll(resp.Body) 701 + t.Fatalf("Expected 200, got %d: %s", resp.StatusCode, string(body)) 702 + } 703 + 704 + t.Logf("✅ List defaults to popular sort when no sort parameter provided") 705 + }) 706 + 707 + t.Run("List with limit bounds validation", func(t *testing.T) { 708 + // Test limit > 100 (should clamp to 100) 709 + resp, err := http.Get(fmt.Sprintf("%s/xrpc/social.coves.community.list?limit=500", 710 + httpServer.URL)) 711 + if err != nil { 712 + t.Fatalf("Failed to GET list with limit=500: %v", err) 713 + } 714 + defer func() { _ = resp.Body.Close() }() 715 + 716 + if resp.StatusCode != http.StatusOK { 717 + body, _ := io.ReadAll(resp.Body) 718 + t.Fatalf("Expected 200 (clamped limit), got %d: %s", resp.StatusCode, string(body)) 719 + } 720 + 721 + var listResp struct { 722 + Communities []communities.Community `json:"communities"` 723 + Cursor string `json:"cursor"` 724 + } 725 + if err := json.NewDecoder(resp.Body).Decode(&listResp); err != nil { 726 + t.Fatalf("Failed to decode response: %v", err) 727 + } 728 + 729 + if len(listResp.Communities) > 100 { 730 + t.Errorf("Expected max 100 communities, got %d", len(listResp.Communities)) 731 + } 732 + 733 + t.Logf("✅ Limit bounds validated (clamped to 100)") 550 734 }) 551 735 552 736 t.Run("Subscribe via XRPC endpoint", func(t *testing.T) {
+2 -6
tests/integration/community_repo_test.go
··· 358 358 Offset: 0, 359 359 } 360 360 361 - results, total, err := repo.List(ctx, req) 361 + results, err := repo.List(ctx, req) 362 362 if err != nil { 363 363 t.Fatalf("Failed to list communities: %v", err) 364 364 } 365 365 366 366 if len(results) != 3 { 367 367 t.Errorf("Expected 3 communities, got %d", len(results)) 368 - } 369 - 370 - if total < 5 { 371 - t.Errorf("Expected total >= 5, got %d", total) 372 368 } 373 369 }) 374 370 ··· 399 395 Visibility: "public", 400 396 } 401 397 402 - results, _, err := repo.List(ctx, req) 398 + results, err := repo.List(ctx, req) 403 399 if err != nil { 404 400 t.Fatalf("Failed to list public communities: %v", err) 405 401 }