清理标签筛选里的「Upd {ts}-v2」空分组与原产品库树里的
「Tree Cat {ts}」垃圾分类——两者均为集成测试夹具残留:
- tag-groups spec「改名」用例把分组改成 -v2 后缀,afterAll 按原名
删除永远漏掉它(累积 31 个空分组);修复:改名前把 v2 名一并登记
- origin-goods spec getTree 用例的 finally 先删 good,被
goodOriginGood 外键限制挡住且错误被 .catch 吞掉,分类/商品/国家/
链接全部残留;修复:先删引用行再删 good
- 已清库:31 个 Upd 空分组、Tree Cat 分类 + Tree Good 商品 +
Tree Country 国家 + 2 条 tree-a/b 链接;复跑两 spec 复核零残留
左树一族一行徽标文案按用户反馈去掉「N 条链接」,仅显示「M 个配置」
(memberCount 字段保留在 DTO,悬浮弹层行为不变)
验证:tag-groups + origin-goods spec 13/13 绿且零残留;admin
vue-tsc 干净 + vitest 22/22
165 lines
6.1 KiB
TypeScript
165 lines
6.1 KiB
TypeScript
import { Test } from '@nestjs/testing';
|
|
import { OriginGoodsService } from './origin-goods.service';
|
|
import { FamilyRecomputeService } from '../product-families/family-recompute.service';
|
|
import { ProductFamiliesService } from '../product-families/product-families.service';
|
|
import { OrganizeService } from '../product-families/organize.service';
|
|
import { PrismaService } from '../prisma/prisma.service';
|
|
|
|
describe('OriginGoodsService', () => {
|
|
let service: OriginGoodsService;
|
|
let prisma: PrismaService;
|
|
const stamp = Date.now();
|
|
const createdSds: string[] = [];
|
|
|
|
beforeAll(async () => {
|
|
const moduleRef = await Test.createTestingModule({
|
|
providers: [OriginGoodsService, FamilyRecomputeService, ProductFamiliesService, OrganizeService, PrismaService],
|
|
}).compile();
|
|
service = moduleRef.get(OriginGoodsService);
|
|
prisma = moduleRef.get(PrismaService);
|
|
await prisma.onModuleInit();
|
|
|
|
// Seed 25 rows with sequential goodNames so we can paginate/filter.
|
|
const rows = Array.from({ length: 25 }).map((_, i) => ({
|
|
sdsGoodId: `sds-${stamp}-${i}`,
|
|
goodName: `Origin Good ${stamp} ${i.toString().padStart(2, '0')}`,
|
|
sdsCategoryId: `cat-${stamp}-${i % 3}`,
|
|
}));
|
|
await prisma.originGood.createMany({ data: rows });
|
|
createdSds.push(...rows.map((r) => r.sdsGoodId));
|
|
});
|
|
|
|
afterAll(async () => {
|
|
if (createdSds.length) {
|
|
await prisma.originGood.deleteMany({
|
|
where: { sdsGoodId: { in: createdSds } },
|
|
});
|
|
}
|
|
await prisma.onModuleDestroy();
|
|
});
|
|
|
|
it('should be defined', () => {
|
|
expect(service).toBeDefined();
|
|
});
|
|
|
|
it('findOne returns og with detail/variants payload', async () => {
|
|
const og = await prisma.originGood.findFirstOrThrow({
|
|
where: { sdsGoodId: `sds-${stamp}-3` },
|
|
});
|
|
const result = await service.findOne(og.id);
|
|
expect(result.id).toBe(og.id.toString());
|
|
expect(result.sdsGoodId).toBe(`sds-${stamp}-3`);
|
|
expect(result.variantCount).toBe(0);
|
|
expect(result.hasDetail).toBe(false);
|
|
expect(result.detail).toBeNull();
|
|
expect(result.variants).toEqual([]);
|
|
await expect(service.findOne(og.id + 10_000_000n)).rejects.toThrow();
|
|
});
|
|
|
|
it('returns paginated results', async () => {
|
|
const page1 = await service.findAll({
|
|
page: 1,
|
|
pageSize: 10,
|
|
keyword: `Origin Good ${stamp}`,
|
|
});
|
|
expect(page1.total).toBe(25);
|
|
expect(page1.items.length).toBe(10);
|
|
expect(page1.page).toBe(1);
|
|
expect(page1.pageSize).toBe(10);
|
|
|
|
const page3 = await service.findAll({
|
|
page: 3,
|
|
pageSize: 10,
|
|
keyword: `Origin Good ${stamp}`,
|
|
});
|
|
expect(page3.items.length).toBe(5);
|
|
});
|
|
|
|
it('searches by keyword (case insensitive)', async () => {
|
|
const result = await service.findAll({
|
|
page: 1,
|
|
pageSize: 5,
|
|
keyword: `origin good ${stamp} 05`,
|
|
});
|
|
expect(result.items.length).toBe(1);
|
|
expect(result.items[0].goodName).toContain('05');
|
|
});
|
|
|
|
it('returns empty page when no matches', async () => {
|
|
const result = await service.findAll({
|
|
page: 1,
|
|
pageSize: 5,
|
|
keyword: 'definitely-does-not-exist',
|
|
});
|
|
expect(result.total).toBe(0);
|
|
expect(result.items.length).toBe(0);
|
|
});
|
|
|
|
describe('getTree merged references', () => {
|
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
function findOgNode(
|
|
treeResponse: { tree: any[] },
|
|
ogId: string,
|
|
): { configuredCount: number; configuredCountries: string[] } {
|
|
let found: { configuredCount: number; configuredCountries: string[] } | null = null;
|
|
const walk = (nodes: any[]) => {
|
|
for (const n of nodes) {
|
|
const hit = (n.originGoods ?? []).find((o: any) => o.id === ogId);
|
|
if (hit) {
|
|
found = hit;
|
|
return;
|
|
}
|
|
if (n.children?.length) walk(n.children);
|
|
}
|
|
};
|
|
walk(treeResponse.tree);
|
|
if (!found) throw new Error(`og node ${ogId} not found in tree`);
|
|
return found;
|
|
}
|
|
|
|
it('counts secondary references as configured', async () => {
|
|
const sdsCat = `tree-cat-${stamp}`;
|
|
await prisma.originGood.createMany({
|
|
data: [
|
|
{ sdsGoodId: `tree-a-${stamp}`, goodName: `Tree A ${stamp}`, sdsCategoryId: sdsCat },
|
|
{ sdsGoodId: `tree-b-${stamp}`, goodName: `Tree B ${stamp}`, sdsCategoryId: sdsCat },
|
|
],
|
|
});
|
|
createdSds.push(`tree-a-${stamp}`, `tree-b-${stamp}`);
|
|
const originA = await prisma.originGood.findUniqueOrThrow({ where: { sdsGoodId: `tree-a-${stamp}` } });
|
|
const originB = await prisma.originGood.findUniqueOrThrow({ where: { sdsGoodId: `tree-b-${stamp}` } });
|
|
|
|
const cat = await prisma.category.create({
|
|
data: { categoryName: `Tree Cat ${stamp}`, sdsCategoryId: sdsCat },
|
|
});
|
|
const country = await prisma.country.create({
|
|
data: { countryName: `Tree Country ${stamp}` },
|
|
});
|
|
const good = await prisma.good.create({
|
|
data: {
|
|
goodName: `Tree Good ${stamp}`,
|
|
originGoodId: originA.id,
|
|
countryId: country.id,
|
|
categoryId: cat.id,
|
|
},
|
|
});
|
|
await prisma.goodOriginGood.create({
|
|
data: { goodId: good.id, originGoodId: originB.id },
|
|
});
|
|
|
|
try {
|
|
const tree = await service.getTree();
|
|
const nodeB = findOgNode(tree, originB.id.toString());
|
|
expect(nodeB.configuredCount).toBeGreaterThanOrEqual(1);
|
|
expect(nodeB.configuredCountries).toContain(`Tree Country ${stamp}`);
|
|
} finally {
|
|
// 先删引用行,否则 good.delete 被外键限制挡住(错误被吞后分类/商品/国家全残留)
|
|
await prisma.goodOriginGood.deleteMany({ where: { goodId: good.id } }).catch(() => undefined);
|
|
await prisma.good.delete({ where: { id: good.id } }).catch(() => undefined);
|
|
await prisma.country.delete({ where: { id: country.id } }).catch(() => undefined);
|
|
await prisma.category.delete({ where: { id: cat.id } }).catch(() => undefined);
|
|
}
|
|
});
|
|
});
|
|
});
|