feat(seo): generate slugs for brands, categories and products, add GET /sitemap and the Postman collection

This commit is contained in:
MastersGame
2026-11-14 11:08:51 +01:00
parent d07c4df52d
commit 657e8a6b30
26 changed files with 750 additions and 12 deletions

View File

@@ -12,7 +12,13 @@ describe('AppController (e2e)', () => {
const hiboutikService = { startSync: jest.fn() };
// Rate limiting counters (ThrottlerDatabaseStorage): the database answers "not blocked" unless a test says otherwise
const notBlocked = { totalHits: 1, timeToExpire: 60, isBlocked: false, timeToBlockExpire: 0 };
const prisma = { $queryRaw: jest.fn(), throttlerRecord: { deleteMany: jest.fn().mockResolvedValue({ count: 0 }) } };
const prisma = {
$queryRaw: jest.fn(),
throttlerRecord: { deleteMany: jest.fn().mockResolvedValue({ count: 0 }) },
brand: { findMany: jest.fn() },
category: { findMany: jest.fn() },
product: { findMany: jest.fn() },
};
beforeEach(async () => {
hiboutikService.startSync.mockReset();
@@ -47,6 +53,28 @@ describe('AppController (e2e)', () => {
expect(hiboutikService.startSync).not.toHaveBeenCalled();
});
it('GET /sitemap lists the public pages', async () => {
prisma.brand.findMany.mockResolvedValue([{ slug: 'bts', updatedAt: new Date('2026-11-01T10:00:00Z') }]);
prisma.category.findMany.mockResolvedValue([{ slug: 'albums', updatedAt: new Date('2026-10-01T10:00:00Z') }]);
prisma.product.findMany.mockResolvedValue([{ slug: 'bts-proof', updatedAt: new Date('2026-11-05T08:00:00Z') }]);
await request(app.getHttpServer())
.get('/sitemap')
.expect(200)
.expect('Cache-Control', 'public, max-age=600')
.expect({
brands: [{ slug: 'bts', updatedAt: '2026-11-01T10:00:00.000Z' }],
categories: [{ slug: 'albums', updatedAt: '2026-10-01T10:00:00.000Z' }],
products: [{ slug: 'bts-proof', updatedAt: '2026-11-05T08:00:00.000Z' }],
});
// only public rows with a slug are read
expect(prisma.brand.findMany).toHaveBeenCalledWith(expect.objectContaining({ where: { slug: { not: null }, enabled: true } }));
expect(prisma.category.findMany).toHaveBeenCalledWith(expect.objectContaining({ where: { slug: { not: null }, webEnabled: true } }));
expect(prisma.product.findMany).toHaveBeenCalledWith(
expect.objectContaining({ where: { slug: { not: null }, enabled: true, archived: false } }),
);
});
afterEach(async () => {
await app.close();
});