import { Test } from '@nestjs/testing'; import { NotFoundException } from '@nestjs/common'; import { PublicService } from './public.service'; import { PrismaService } from '../prisma/prisma.service'; describe('PublicService', () => { let service: PublicService; let prisma: PrismaService; const stamp = Date.now(); let countryId: bigint; let categoryId: bigint; let childCategoryId: bigint; let otherCategoryId: bigint; let tagId: bigint; let originGoodId: bigint; let goodIds: bigint[] = []; beforeAll(async () => { const moduleRef = await Test.createTestingModule({ providers: [PublicService, PrismaService], }).compile(); service = moduleRef.get(PublicService); prisma = moduleRef.get(PrismaService); await prisma.onModuleInit(); const country = await prisma.country.create({ data: { countryName: `Pub Country ${stamp}` }, }); countryId = country.id; const cat = await prisma.category.create({ data: { categoryName: `Pub Cat ${stamp}` }, }); categoryId = cat.id; const child = await prisma.category.create({ data: { categoryName: `Pub Child ${stamp}`, parentCategoryId: cat.id }, }); childCategoryId = child.id; const otherCat = await prisma.category.create({ data: { categoryName: `Pub Other ${stamp}` }, }); otherCategoryId = otherCat.id; const tag = await prisma.tag.create({ data: { tagName: `Pub Tag ${stamp}`, tagColor: '#0000FF' }, }); tagId = tag.id; const og = await prisma.originGood.create({ data: { sdsGoodId: `pub-sds-${stamp}`, goodName: `Origin ${stamp}`, goodImage: 'http://img', }, }); originGoodId = og.id; // Seed 3 goods: // high priority + position.indexVal=1 // mid priority + position.indexVal=5 // no priority + no position (falls back to createdAt) const pos1 = await prisma.position.create({ data: { indexVal: 1, countryId, categoryId }, }); const pos2 = await prisma.position.create({ data: { indexVal: 5, countryId, categoryId }, }); const g1 = await prisma.good.create({ data: { goodName: `Pub High ${stamp}`, originGoodId, countryId, categoryId, goodPriority: 10, positionId: pos1.id, }, }); const g2 = await prisma.good.create({ data: { goodName: `Pub Mid ${stamp}`, originGoodId, countryId, categoryId, goodPriority: 5, positionId: pos2.id, }, }); const g3 = await prisma.good.create({ data: { goodName: `Pub NoPos ${stamp}`, originGoodId, countryId, categoryId, tagId, goodPriority: 1, }, }); goodIds = [g1.id, g2.id, g3.id]; // Seed a good in `otherCategory` so the "onlyHaveGoods" filter // returns more than one category. await prisma.good.create({ data: { goodName: `Pub Other ${stamp}`, originGoodId, countryId, categoryId: otherCategoryId, goodPriority: 1, }, }); // And seed a good in the *child* category, to verify categoryId // recursion. await prisma.good.create({ data: { goodName: `Pub ChildGood ${stamp}`, originGoodId, countryId, categoryId: childCategoryId, goodPriority: 0, }, }); }); afterAll(async () => { if (goodIds.length) { await prisma.good.deleteMany({ where: { id: { in: goodIds } } }); } await prisma.good.deleteMany({ where: { goodName: { contains: `Pub ` } }, }); await prisma.position.deleteMany({ where: { countryId }, }); await prisma.tag.delete({ where: { id: tagId } }); await prisma.originGood.delete({ where: { id: originGoodId } }); // Delete children before parent (FK self-relation is RESTRICT). await prisma.category.delete({ where: { id: childCategoryId } }); await prisma.category.delete({ where: { id: otherCategoryId } }); await prisma.category.delete({ where: { id: categoryId } }); await prisma.country.delete({ where: { id: countryId } }); await prisma.onModuleDestroy(); }); it('should be defined', () => { expect(service).toBeDefined(); }); it('getCategoriesTree returns only categories that have goods', async () => { const tree = await service.getCategoriesTree(); const allIds = new Set(); const walk = (list: Array<{ id: string; children: Array<{ id: string }> }>) => { for (const n of list) { allIds.add(n.id); walk(n.children as any); } }; walk(tree as any); // We seeded goods in `categoryId`, `childCategoryId`, `otherCategoryId`. expect(allIds.has(categoryId.toString())).toBe(true); expect(allIds.has(childCategoryId.toString())).toBe(true); expect(allIds.has(otherCategoryId.toString())).toBe(true); }); it('getCountries returns only countries that have goods', async () => { const countries = await service.getCountries(); expect(countries.find((c) => c.id === countryId.toString())).toBeDefined(); }); it('filters by countryId, tagId, keyword and categoryId (recursively)', async () => { const filtered = await service.getGoods({ page: 1, pageSize: 50, countryId: Number(countryId), categoryId: Number(categoryId), // includes child keyword: `Pub `, }); expect(filtered.total).toBeGreaterThanOrEqual(4); // High, Mid, NoPos, ChildGood expect(filtered.items.every((g) => g.country.id === countryId.toString())).toBe(true); }); it('sorts by priority DESC, position.indexVal ASC, createdAt DESC', async () => { const result = await service.getGoods({ page: 1, pageSize: 50, countryId: Number(countryId), keyword: `Pub `, }); const priorities = result.items.map((g) => g.goodPriority); // First verify primary descending priority. const sorted = [...priorities].sort((a, b) => b - a); expect(priorities).toEqual(sorted); }); it('getGood returns detail and 404 for unknown id', async () => { const first = await service.getGoods({ page: 1, pageSize: 1, countryId: Number(countryId), keyword: `Pub `, }); expect(first.items.length).toBe(1); const detail = await service.getGood(BigInt(first.items[0].id)); expect(detail.id).toBe(first.items[0].id); await expect(service.getGood(BigInt(99999999))).rejects.toBeInstanceOf( NotFoundException, ); }); it('getTags returns tags with their group info, sorted by group then order', async () => { const tags = await service.getTags(); expect(tags.length).toBeGreaterThan(0); // Each tag in our seed (包邮/不包邮/...) should have a group const grouped = tags.find((t) => t.tagName === '包邮'); if (grouped) { expect(grouped.group).not.toBeNull(); expect(grouped.group!.groupName).toBe('物流渠道'); } }); it('getTagGroups returns only groups that have goods', async () => { const groups = await service.getTagGroups(); expect(groups.length).toBeGreaterThan(0); const names = groups.map((g) => g.groupName); expect(names).toContain('物流渠道'); expect(names).toContain('印刷位置'); expect(names).toContain('印刷工艺'); // Sorted by sortOrder const sortOrders = groups.map((g) => g.sortOrder); expect([...sortOrders].sort((a, b) => a - b)).toEqual(sortOrders); }); });