73 lines
3.1 KiB
TypeScript
73 lines
3.1 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
vi.mock('./offer.repo', () => ({
|
|
findMany: vi.fn(),
|
|
findByIdOrThrow: vi.fn(),
|
|
create: vi.fn(),
|
|
findFirst: vi.fn(),
|
|
update: vi.fn(),
|
|
deleteMany: vi.fn(),
|
|
setActive: vi.fn(),
|
|
getStats: vi.fn(),
|
|
}))
|
|
|
|
import { NotFoundError } from '../../http/errors'
|
|
import * as repo from './offer.repo'
|
|
import { createOffer, deleteOffer, getOffer, getOfferStats, listOffers, setOfferActive, updateOffer } from './offer.service'
|
|
|
|
describe('offer.service', () => {
|
|
beforeEach(() => vi.clearAllMocks())
|
|
|
|
it('keeps listing filters tenant-scoped and delegates them unchanged to the repository', async () => {
|
|
vi.mocked(repo.findMany).mockResolvedValue([{ id: 'offer_1' }] as never)
|
|
|
|
const result = await listOffers('company_1', { active: 'true', public: 'false' })
|
|
|
|
expect(repo.findMany).toHaveBeenCalledWith('company_1', { active: 'true', public: 'false' })
|
|
expect(result).toEqual([{ id: 'offer_1' }])
|
|
})
|
|
|
|
it('creates offers with separate offer data and vehicle assignment ids', async () => {
|
|
vi.mocked(repo.create).mockResolvedValue({ id: 'offer_1' } as never)
|
|
|
|
const payload = { title: 'Weekend deal', type: 'PERCENTAGE', discountValue: 15 }
|
|
await createOffer('company_1', payload, ['vehicle_1', 'vehicle_2'])
|
|
|
|
expect(repo.create).toHaveBeenCalledWith('company_1', payload, ['vehicle_1', 'vehicle_2'])
|
|
})
|
|
|
|
it('throws NotFoundError before updating an offer outside the tenant boundary', async () => {
|
|
vi.mocked(repo.findFirst).mockResolvedValue(null as never)
|
|
|
|
await expect(updateOffer('offer_1', 'company_1', { title: 'Nope' })).rejects.toBeInstanceOf(NotFoundError)
|
|
expect(repo.update).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('updates an existing offer and preserves explicit vehicle assignment updates', async () => {
|
|
vi.mocked(repo.findFirst).mockResolvedValue({ id: 'offer_1' } as never)
|
|
vi.mocked(repo.update).mockResolvedValue({ id: 'offer_1', title: 'Summer' } as never)
|
|
|
|
const result = await updateOffer('offer_1', 'company_1', { title: 'Summer' }, [])
|
|
|
|
expect(repo.update).toHaveBeenCalledWith('offer_1', { title: 'Summer' }, [])
|
|
expect(result).toEqual({ id: 'offer_1', title: 'Summer' })
|
|
})
|
|
|
|
it('activates, deactivates, deletes, and reads stats through tenant-scoped repository methods', async () => {
|
|
vi.mocked(repo.setActive).mockResolvedValue({ id: 'offer_1', isActive: true } as never)
|
|
vi.mocked(repo.deleteMany).mockResolvedValue({ count: 1 } as never)
|
|
vi.mocked(repo.getStats).mockResolvedValue({ redemptions: 3 } as never)
|
|
vi.mocked(repo.findByIdOrThrow).mockResolvedValue({ id: 'offer_1' } as never)
|
|
|
|
await getOffer('offer_1', 'company_1')
|
|
await setOfferActive('offer_1', 'company_1', true)
|
|
await deleteOffer('offer_1', 'company_1')
|
|
await getOfferStats('offer_1', 'company_1')
|
|
|
|
expect(repo.findByIdOrThrow).toHaveBeenCalledWith('offer_1', 'company_1')
|
|
expect(repo.setActive).toHaveBeenCalledWith('offer_1', 'company_1', true)
|
|
expect(repo.deleteMany).toHaveBeenCalledWith('offer_1', 'company_1')
|
|
expect(repo.getStats).toHaveBeenCalledWith('offer_1', 'company_1')
|
|
})
|
|
})
|