Files
cmautobuy/admin/service/shopee_list_test.go
T

253 lines
8.7 KiB
Go
Raw Normal View History

package service
import (
"database/sql"
"testing"
"cmautobuy/admin/repository"
)
// seedShopeeProduct 建一个蝦皮商品,goods_id / title 之外不填别的。
func seedShopeeProduct(t *testing.T, db *sql.DB, goodsID, title string) {
t.Helper()
if err := repository.UpsertShopeeProduct(db, goodsID, title, "正常", "货号"+goodsID); err != nil {
t.Fatalf("建蝦皮商品 %s 失败: %v", goodsID, err)
}
}
// seedShopeeSKU 建一条蝦皮 SKU。specRaw 只在 parseOK=false 时用于校验回显。
func seedShopeeSKU(t *testing.T, db *sql.DB, skuID, goodsID, specRaw, color, size, advice string, parseOK bool) {
t.Helper()
if err := repository.UpsertShopeeSKU(db, skuID, goodsID, specRaw, color, size, advice, parseOK, "sku-"+skuID); err != nil {
t.Fatalf("建蝦皮 SKU %s 失败: %v", skuID, err)
}
}
// setShopeePddLink 直接写 shopee_products.pdd_goods_url / pdd_goods_id,
// 模拟"已经填过 PDD 链接"。ShopeeSave 本工单不实现,测试直接写库代替。
func setShopeePddLink(t *testing.T, db *sql.DB, goodsID, pddGoodsID, pddURL string) {
t.Helper()
_, err := db.Exec(
`UPDATE shopee_products SET pdd_goods_id = ?, pdd_goods_url = ? WHERE goods_id = ?`,
pddGoodsID, pddURL, goodsID)
if err != nil {
t.Fatalf("写蝦皮商品 %s 的 PDD 链接失败: %v", goodsID, err)
}
}
// ── 列表:商品级聚合 ──────────────────────────────────
func TestListShopeeProducts_商品级一行(t *testing.T) {
db := newTestDB(t)
// 商品 24420648774 在真实样本里有 62 个 SKU,这里用 3 个模拟同样的
// "一个商品多个 SKU 但只应该出现一行"的场景,见工单 #41。
seedShopeeProduct(t, db, "24420648774", "吊帶背心")
seedShopeeSKU(t, db, "sku-1", "24420648774", "", "黑色", "M", "40-50公斤", true)
seedShopeeSKU(t, db, "sku-2", "24420648774", "", "黑色", "L", "50-60公斤", true)
seedShopeeSKU(t, db, "sku-3", "24420648774", "", "白色", "M", "40-50公斤", true)
result, err := ListShopeeProducts(db, "")
if err != nil {
t.Fatalf("查询失败: %v", err)
}
if len(result.Rows) != 1 {
t.Fatalf("行数 = %d,想要 1(商品级一行,不是 SKU 级)", len(result.Rows))
}
row := result.Rows[0]
if row.SKUCount != 3 {
t.Errorf("SKUCount = %d,想要 3", row.SKUCount)
}
if row.ColorCount != 2 {
t.Errorf("ColorCount = %d,想要 2(黑/白)", row.ColorCount)
}
if row.SizeCount != 2 {
t.Errorf("SizeCount = %d,想要 2(M/L)", row.SizeCount)
}
if row.PendingCount != 0 {
t.Errorf("PendingCount = %d,想要 0", row.PendingCount)
}
}
func TestListShopeeProducts_颜色尺码只统计parse_ok(t *testing.T) {
db := newTestDB(t)
// 模拟工单里 26886533818 的情形:颜色数 × 尺码数会大于实际 SKU 数,
// 而且有一部分 SKU 解析失败——它们不能被算进颜色/尺码的 DISTINCT。
seedShopeeProduct(t, db, "26886533818", "測試商品")
seedShopeeSKU(t, db, "s1", "26886533818", "", "咖啡色", "2XL", "", true)
seedShopeeSKU(t, db, "s2", "26886533818", "", "咖啡色", "3XL", "", true)
seedShopeeSKU(t, db, "s3", "26886533818", "", "紅色", "M", "", true)
// 解析失败的两条:spec_raw 保留,color/size 为空,不该被 DISTINCT 算进去。
seedShopeeSKU(t, db, "s4", "26886533818", "紅色,3XL建議80-90公斤】", "", "", "", false)
seedShopeeSKU(t, db, "s5", "26886533818", "粉色,3XL【寬鬆版 82.5-92.5kg", "", "", "", false)
result, err := ListShopeeProducts(db, "")
if err != nil {
t.Fatalf("查询失败: %v", err)
}
if len(result.Rows) != 1 {
t.Fatalf("行数 = %d,想要 1", len(result.Rows))
}
row := result.Rows[0]
if row.SKUCount != 5 {
t.Errorf("SKUCount = %d,想要 5(含 2 条解析失败的)", row.SKUCount)
}
if row.ColorCount != 2 {
t.Errorf("ColorCount = %d,想要 2(咖啡色/紅色,不含解析失败的空颜色)", row.ColorCount)
}
if row.SizeCount != 3 {
t.Errorf("SizeCount = %d,想要 3(2XL/3XL/M,不含解析失败的空尺码)", row.SizeCount)
}
if row.PendingCount != 2 {
t.Errorf("PendingCount = %d,想要 2", row.PendingCount)
}
}
func TestListShopeeProducts_待补大于0整行标黄(t *testing.T) {
db := newTestDB(t)
seedShopeeProduct(t, db, "1001", "商品A")
seedShopeeSKU(t, db, "s1", "1001", "坏数据", "", "", "", false)
result, err := ListShopeeProducts(db, "")
if err != nil {
t.Fatalf("查询失败: %v", err)
}
if result.Rows[0].PendingCount != 1 {
t.Fatalf("PendingCount = %d,想要 1", result.Rows[0].PendingCount)
}
// 整行标黄由模板按 PendingCount > 0 判断,这里只验证数据源正确。
}
func TestListShopeeProducts_PDD链接未填写(t *testing.T) {
db := newTestDB(t)
seedShopeeProduct(t, db, "1001", "商品A")
result, err := ListShopeeProducts(db, "")
if err != nil {
t.Fatalf("查询失败: %v", err)
}
row := result.Rows[0]
if !row.PddMissing || row.PddURL != "未填写" {
t.Errorf("PddMissing/PddURL = %v/%q,想要 true/\"未填写\"", row.PddMissing, row.PddURL)
}
if row.StatusText != "未填链接" {
t.Errorf("StatusText = %q,想要 \"未填链接\"", row.StatusText)
}
}
func TestListShopeeProducts_采集状态联查(t *testing.T) {
db := newTestDB(t)
seedShopeeProduct(t, db, "1001", "商品A")
if _, err := repository.EnsurePddProduct(db, "9001", "https://mobile.yangkeduo.com/goods.html?goods_id=9001"); err != nil {
t.Fatalf("建 PDD 商品失败: %v", err)
}
if err := repository.SetCollectResult(db, "9001", "PDD标题", "店铺", "{}"); err != nil {
t.Fatalf("设置采集结果失败: %v", err)
}
setShopeePddLink(t, db, "1001", "9001", "https://mobile.yangkeduo.com/goods.html?goods_id=9001")
result, err := ListShopeeProducts(db, "")
if err != nil {
t.Fatalf("查询失败: %v", err)
}
row := result.Rows[0]
if row.PddMissing {
t.Error("已填链接,PddMissing 应为 false")
}
if row.StatusText != "已采集" {
t.Errorf("StatusText = %q,想要 \"已采集\"", row.StatusText)
}
}
func TestListShopeeProducts_关键字匹配商品ID和名称_不匹配颜色尺码(t *testing.T) {
db := newTestDB(t)
seedShopeeProduct(t, db, "1001", "吊帶背心")
seedShopeeProduct(t, db, "1002", "短袖T恤")
seedShopeeSKU(t, db, "s1", "1001", "", "黑色", "M", "", true)
// 按商品 ID 匹配
result, err := ListShopeeProducts(db, "1001")
if err != nil {
t.Fatalf("查询失败: %v", err)
}
if len(result.Rows) != 1 || result.Rows[0].GoodsID != "1001" {
t.Fatalf("按商品 ID 搜索结果不对: %+v", result.Rows)
}
// 按商品名称匹配
result, err = ListShopeeProducts(db, "背心")
if err != nil {
t.Fatalf("查询失败: %v", err)
}
if len(result.Rows) != 1 || result.Rows[0].GoodsID != "1001" {
t.Fatalf("按商品名称搜索结果不对: %+v", result.Rows)
}
// 颜色/尺码不参与匹配:搜"黑色"应该搜不到任何商品。
result, err = ListShopeeProducts(db, "黑色")
if err != nil {
t.Fatalf("查询失败: %v", err)
}
if len(result.Rows) != 0 {
t.Fatalf("关键字不应匹配颜色,得到 %+v", result.Rows)
}
}
// ── 弹窗详情 ──────────────────────────────────
func TestGetShopeeProductDetail_待补行显示原文(t *testing.T) {
db := newTestDB(t)
seedShopeeProduct(t, db, "1001", "商品A")
seedShopeeSKU(t, db, "s1", "1001", "", "黑色", "M", "40-50公斤", true)
seedShopeeSKU(t, db, "s2", "1001", "紅色,3XL建議80-90公斤】", "", "", "", false)
detail, err := GetShopeeProductDetail(db, "1001")
if err != nil {
t.Fatalf("查询失败: %v", err)
}
if detail == nil {
t.Fatal("详情为 nil")
}
if len(detail.SKUs) != 2 {
t.Fatalf("SKUs 数量 = %d,想要 2(含解析失败的)", len(detail.SKUs))
}
if detail.PendingCount != 1 {
t.Errorf("PendingCount = %d,想要 1", detail.PendingCount)
}
var pending *ShopeeSpecView
for i := range detail.SKUs {
if detail.SKUs[i].Pending {
pending = &detail.SKUs[i]
}
}
if pending == nil {
t.Fatal("没有找到待补的那一行")
}
if pending.SpecRaw != "紅色,3XL建議80-90公斤】" {
t.Errorf("SpecRaw = %q,想要显示原文", pending.SpecRaw)
}
if pending.StatusText != "待补" {
t.Errorf("StatusText = %q,想要 \"待补\"", pending.StatusText)
}
for _, s := range detail.SKUs {
if !s.Pending && s.StatusText != "✓" {
t.Errorf("解析成功的行 StatusText = %q,想要 \"✓\"", s.StatusText)
}
}
}
func TestGetShopeeProductDetail_商品不存在返回nil(t *testing.T) {
db := newTestDB(t)
detail, err := GetShopeeProductDetail(db, "not-exist")
if err != nil {
t.Fatalf("不应该报错: %v", err)
}
if detail != nil {
t.Fatalf("不存在的商品应该返回 nil,得到 %+v", detail)
}
}