package service import ( "fmt" "testing" "affiliate_dash/internal/model" ) // TestListMerchantOptionsReturnsAllActiveMerchants 卡住两个点: // 1. 下拉需要"全部商户",不能被分页的 size 上限(100,且传大值会被降级为 20)截断; // 2. 已禁用商户不应出现在可筛选列表里。 func TestListMerchantOptionsReturnsAllActiveMerchants(t *testing.T) { db := newServiceTestDB(t) svc := NewMerchantService(db, nil, NewTenantService(db)) const activeCount = 25 for i := 0; i < activeCount; i++ { merchant := model.Merchant{ Code: fmt.Sprintf("opt-merchant-%02d", i), Name: fmt.Sprintf("下拉商户 %02d", i), Status: model.MerchantStatusActive, } if err := db.Create(&merchant).Error; err != nil { t.Fatalf("create merchant: %v", err) } } disabled := model.Merchant{Code: "opt-merchant-disabled", Name: "已禁用商户", Status: model.MerchantStatusDisabled} if err := db.Create(&disabled).Error; err != nil { t.Fatalf("create disabled merchant: %v", err) } options, err := svc.ListMerchantOptions() if err != nil { t.Fatalf("ListMerchantOptions: %v", err) } // 期望值与库里实际的启用商户数一致(迁移会 seed 一个自营商户,不能写死数字)。 var activeInDB int64 if err := db.Model(&model.Merchant{}).Where("status = ?", model.MerchantStatusActive).Count(&activeInDB).Error; err != nil { t.Fatalf("count active merchants: %v", err) } if int64(len(options)) != activeInDB { t.Fatalf("期望返回全部 %d 个启用商户,实际 %d", activeInDB, len(options)) } // 分页默认上限是 20、最大 100;这里必须远超它,否则说明又被分页截断了。 if len(options) <= 20 { t.Fatalf("下拉必须返回全部商户,不能被分页上限截断,实际只有 %d 个", len(options)) } for _, option := range options { if option.ID == 0 || option.Code == "" || option.Name == "" { t.Fatalf("选项字段不应为空:%+v", option) } if option.ID == disabled.ID { t.Fatal("已禁用商户不应出现在筛选下拉里") } } } // TestListMerchantsClampsOversizedPageSize 记录上面那个接口存在的真实原因: // 分页查询会把 >100 的 size 静默降级为 20,所以"下拉要全部商户"不能靠它。 // 顺带钉住一个更隐蔽的事实:total 反映真实总数,而 list 已被截断。 func TestListMerchantsClampsOversizedPageSize(t *testing.T) { db := newServiceTestDB(t) svc := NewMerchantService(db, nil, NewTenantService(db)) const created = 25 for i := 0; i < created; i++ { merchant := model.Merchant{ Code: fmt.Sprintf("clamp-merchant-%02d", i), Name: fmt.Sprintf("截断商户 %02d", i), Status: model.MerchantStatusActive, } if err := db.Create(&merchant).Error; err != nil { t.Fatalf("create merchant: %v", err) } } list, total, err := svc.ListMerchants(1, 200) if err != nil { t.Fatalf("ListMerchants: %v", err) } if len(list) != 20 { t.Fatalf("size=200 应被降级为 20,实际返回 %d 条", len(list)) } if total <= 20 { t.Fatalf("total 应反映真实总数(会被截断),实际 %d", total) } }