Files
pokemon-inventory/apps/api/tests/application/inventory-item-service.test.js
T
fragginwagon 12eced8b19
Quality / test (push) Canceled after 0s
feat: add seller-scoped bulk archive
Add the first bulk inventory operation through a validated, CSRF-protected API route with lifecycle and ownership enforcement, tests, and implementation-status documentation.
2026-09-09 23:11:48 -04:00

97 lines
3.1 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { createInventoryItemService } from '../../src/modules/inventory/services/inventory-item-service.js';
function createService({ product, condition }) {
return createInventoryItemService({
productRepository: { async findById() { return product; } },
conditionRepository: { async findById() { return condition; } },
inventoryItemRepository: {
async create(inventoryItem) { return inventoryItem; },
async listBySellerId() { return []; },
async archiveByIdsForSeller(inventoryItemIds) {
return inventoryItemIds.map((id) => ({ id, status: 'ARCHIVED' }));
},
},
});
}
test('creates an inventory item when its condition belongs to the product category', async () => {
const service = createService({
product: { id: 'product-id', sellerId: 'seller-id', categoryId: 'cards' },
condition: { id: 'condition-id', categoryId: 'cards' },
});
const inventoryItem = await service.create({
productId: 'product-id',
conditionId: 'condition-id',
sellerId: 'seller-id',
notes: ' Near mint ',
});
assert.deepEqual(inventoryItem, {
productId: 'product-id',
conditionId: 'condition-id',
notes: 'Near mint',
});
});
test('archives owned active inventory items in bulk', async () => {
const service = createInventoryItemService({
productRepository: { async findById() { return null; } },
conditionRepository: { async findById() { return null; } },
inventoryItemRepository: {
async listBySellerId() {
return [
{ id: 'item-1', status: 'ACTIVE' },
{ id: 'item-2', status: 'ACTIVE' },
];
},
async archiveByIdsForSeller(ids) {
return ids.map((id) => ({ id, status: 'ARCHIVED' }));
},
},
});
assert.deepEqual(
await service.archiveMany({ inventoryItemIds: ['item-1', 'item-2'], sellerId: 'seller-id' }),
[
{ id: 'item-1', status: 'ARCHIVED' },
{ id: 'item-2', status: 'ARCHIVED' },
],
);
});
test('does not archive sold inventory items', async () => {
const service = createInventoryItemService({
productRepository: { async findById() { return null; } },
conditionRepository: { async findById() { return null; } },
inventoryItemRepository: {
async listBySellerId() { return [{ id: 'item-1', status: 'SOLD' }]; },
async archiveByIdsForSeller() { throw new Error('should not update'); },
},
});
await assert.rejects(
() => service.archiveMany({ inventoryItemIds: ['item-1'], sellerId: 'seller-id' }),
/Inventory status cannot transition from SOLD to ARCHIVED/,
);
});
test('rejects conditions from another category', async () => {
const service = createService({
product: { id: 'product-id', sellerId: 'seller-id', categoryId: 'cards' },
condition: { id: 'condition-id', categoryId: 'merchandise' },
});
await assert.rejects(
() =>
service.create({
productId: 'product-id',
conditionId: 'condition-id',
sellerId: 'seller-id',
}),
(error) => error.code === 'CONDITION_CATEGORY_MISMATCH',
);
});