test(security): add and refactor api security/idor coverage
Test Suite / test (24.15.0) (push) Has been cancelled

This commit is contained in:
Nils-Johan Gynther
2026-05-11 16:40:16 +02:00
parent 9b468d9a13
commit 1db30c9b6f
12 changed files with 1025 additions and 23 deletions
+125
View File
@@ -0,0 +1,125 @@
import { NotFoundException } from '@nestjs/common';
import { PantryService } from './pantry.service';
describe('PantryService IDOR security', () => {
const makeCreatePantryDto = (overrides: Partial<{ productId: number; userId: number }> = {}) => ({
productId: 1,
...overrides,
});
const prismaMock = {
pantryItem: {
findMany: jest.fn(),
findUnique: jest.fn(),
findFirst: jest.fn(),
create: jest.fn(),
update: jest.fn(),
delete: jest.fn(),
},
product: {
findUnique: jest.fn(),
},
user: {
findUnique: jest.fn(),
},
inventoryItem: {
create: jest.fn(),
},
$transaction: jest.fn(),
};
const service = new PantryService(prismaMock as any);
beforeEach(() => {
jest.clearAllMocks();
});
const mockPantryFindManyEmpty = () => {
prismaMock.pantryItem.findMany.mockResolvedValue([]);
};
it('scopar findAll till userId', async () => {
mockPantryFindManyEmpty();
await service.findAll(42);
expect(prismaMock.pantryItem.findMany).toHaveBeenCalledWith(
expect.objectContaining({
where: expect.objectContaining({ userId: 42 }),
}),
);
});
it('findAllAdmin kan filtrera per userId', async () => {
mockPantryFindManyEmpty();
await service.findAllAdmin({ userId: 99 });
expect(prismaMock.pantryItem.findMany).toHaveBeenCalledWith(
expect.objectContaining({
where: expect.objectContaining({ userId: 99 }),
}),
);
});
it('findAllAdmin returnerar alla items om userId inte specificeras', async () => {
mockPantryFindManyEmpty();
await service.findAllAdmin({});
expect(prismaMock.pantryItem.findMany).toHaveBeenCalledWith(
expect.objectContaining({
where: {},
}),
);
});
it('create sätter userId på nya pantry-items', async () => {
prismaMock.product.findUnique.mockResolvedValue({ id: 1 });
prismaMock.pantryItem.create.mockResolvedValue({ id: 1, userId: 42 });
await service.create(42, makeCreatePantryDto() as any);
expect(prismaMock.pantryItem.create).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({ userId: 42, productId: 1 }),
}),
);
});
it('createAdmin kan skapa pantry-item för explicit userId', async () => {
prismaMock.user.findUnique.mockResolvedValue({ id: 99 });
prismaMock.product.findUnique.mockResolvedValue({ id: 1 });
prismaMock.pantryItem.create.mockResolvedValue({ id: 1, userId: 99 });
await service.createAdmin(1, makeCreatePantryDto({ userId: 99 }) as any, 99);
expect(prismaMock.pantryItem.create).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({ userId: 99, productId: 1 }),
}),
);
});
it('createAdmin throws NotFoundException om target user saknas', async () => {
prismaMock.user.findUnique.mockResolvedValue(null);
await expect(service.createAdmin(1, makeCreatePantryDto({ userId: 999 }) as any, 999)).rejects.toThrow(
NotFoundException,
);
});
it('remove nekar icke-owner', async () => {
// Simulera att item inte hittas (userId matchar inte)
prismaMock.pantryItem.findFirst.mockResolvedValue(null);
await expect(service.remove(42, 1)).rejects.toThrow(NotFoundException);
});
it('moveToInventory nekar icke-owner', async () => {
// Simulera att item inte hittas (userId matchar inte)
prismaMock.pantryItem.findFirst.mockResolvedValue(null);
await expect(service.moveToInventory(42, 1, {} as any)).rejects.toThrow(NotFoundException);
});
});