import assert from 'node:assert/strict'; import test from 'node:test'; import { createListingService } from '../../src/modules/listings/services/listing-service.js'; test('creates a draft listing only after the listing publish requirements are met', async () => { const created = []; const service = createListingService({ listingRepository: { async create(listing) { const record = { id: 'listing-1', ...listing }; created.push(record); return record; }, }, inventoryImageRepository: { async countByInventoryItemId() { return 2; }, }, }); const listing = await service.create({ inventoryItemId: 'inventory-item-id', productName: ' Charizard ex ', categoryId: 'category-id', conditionId: 'condition-id', askingPriceMinor: 2499, imageCount: 2, notes: ' Near mint ', }); assert.deepEqual(listing, { id: 'listing-1', inventoryItemId: 'inventory-item-id', productName: 'Charizard ex', categoryId: 'category-id', conditionId: 'condition-id', askingPriceMinor: 2499, imageCount: 2, status: 'DRAFT', notes: 'Near mint', }); await assert.rejects( () => service.create({ inventoryItemId: 'inventory-item-id', productName: 'Charizard ex', categoryId: 'category-id', conditionId: 'condition-id', askingPriceMinor: 0, imageCount: 2, }), (error) => error.code === 'LISTING_REQUIREMENTS_NOT_MET', ); assert.equal(created.length, 1); }); test('publishes an owned draft only when its persisted requirements are met', async () => { const updated = []; const service = createListingService({ listingRepository: { async findByIdForSeller() { return { id: 'listing-1', inventoryItemId: 'inventory-item-id', productName: 'Charizard ex', categoryId: 'category-id', conditionId: 'condition-id', askingPriceMinor: 2499, imageCount: 2, status: 'DRAFT', }; }, async updateStatus(id, status) { updated.push({ id, status }); return { id, status }; }, }, }); assert.deepEqual( await service.transition({ listingId: 'listing-1', sellerId: 'seller-1', nextStatus: 'AVAILABLE', }), { id: 'listing-1', status: 'AVAILABLE' }, ); assert.deepEqual(updated, [{ id: 'listing-1', status: 'AVAILABLE' }]); }); test('does not transition a listing owned by another seller', async () => { const service = createListingService({ listingRepository: { async findByIdForSeller() { return null; }, }, }); await assert.rejects( () => service.transition({ listingId: 'listing-1', sellerId: 'seller-2', nextStatus: 'AVAILABLE' }), (error) => error.code === 'LISTING_NOT_FOUND' && error.statusCode === 404, ); }); test('does not publish a listing for sold or archived inventory', async () => { for (const inventoryStatus of ['SOLD', 'ARCHIVED']) { const service = createListingService({ listingRepository: { async findByIdForSeller() { return { id: 'listing-1', inventoryItemId: 'inventory-item-id', productName: 'Charizard ex', categoryId: 'category-id', conditionId: 'condition-id', askingPriceMinor: 2499, imageCount: 2, inventoryStatus, status: 'DRAFT', }; }, async updateStatus() { throw new Error('A blocked listing must not be updated.'); }, }, }); await assert.rejects( () => service.transition({ listingId: 'listing-1', sellerId: 'seller-1', nextStatus: 'AVAILABLE' }), (error) => error.code === 'LISTING_INVENTORY_UNAVAILABLE' && error.statusCode === 409, ); } }); test('lists and retrieves only seller-owned listings', async () => { const ownedListing = { id: 'listing-1', status: 'DRAFT' }; const service = createListingService({ listingRepository: { async listBySellerId(sellerId) { assert.equal(sellerId, 'seller-1'); return [ownedListing]; }, async findByIdForSeller(listingId, sellerId) { assert.equal(listingId, 'listing-1'); assert.equal(sellerId, 'seller-1'); return ownedListing; }, }, }); assert.deepEqual(await service.list({ sellerId: 'seller-1' }), [ownedListing]); assert.deepEqual(await service.get({ listingId: 'listing-1', sellerId: 'seller-1' }), ownedListing); });