Remove DB-dependent unit tests, use api-tests for integration testing

All tests in __tests__/ were hitting the database directly. Integration
testing is handled by the api-tests/ suite instead.
This commit is contained in:
Ryan Moon
2026-03-30 08:52:01 -05:00
parent 9400828f62
commit 701e15ea6d
13 changed files with 0 additions and 2607 deletions

View File

@@ -1,240 +0,0 @@
import { describe, it, expect, beforeAll, beforeEach, afterAll } from 'bun:test'
import type { FastifyInstance } from 'fastify'
import { createTestApp, cleanDb, seedTestCompany, registerAndLogin, TEST_COMPANY_ID } from '../../src/test/helpers.js'
import { AccountService, PaymentMethodService, TaxExemptionService } from '../../src/services/account.service.js'
describe('PaymentMethodService', () => {
let app: FastifyInstance
let accountId: string
beforeAll(async () => {
app = await createTestApp()
})
beforeEach(async () => {
await cleanDb(app)
await seedTestCompany(app)
const auth = await registerAndLogin(app, { email: `pm-svc-${Date.now()}@test.com` })
const account = await AccountService.create(app.db, TEST_COMPANY_ID, { name: 'PM Test' })
accountId = account.id
})
afterAll(async () => {
await app.close()
})
it('creates a payment method', async () => {
const pm = await PaymentMethodService.create(app.db, TEST_COMPANY_ID, {
accountId,
processor: 'stripe',
processorPaymentMethodId: 'pm_abc',
cardBrand: 'visa',
lastFour: '4242',
expMonth: 12,
expYear: 2027,
isDefault: false,
})
expect(pm.processorPaymentMethodId).toBe('pm_abc')
expect(pm.isDefault).toBe(false)
})
it('unsets old default when creating a new default', async () => {
const first = await PaymentMethodService.create(app.db, TEST_COMPANY_ID, {
accountId,
processor: 'stripe',
processorPaymentMethodId: 'pm_first',
isDefault: true,
})
expect(first.isDefault).toBe(true)
const second = await PaymentMethodService.create(app.db, TEST_COMPANY_ID, {
accountId,
processor: 'stripe',
processorPaymentMethodId: 'pm_second',
isDefault: true,
})
expect(second.isDefault).toBe(true)
// First should no longer be default
const firstRefreshed = await PaymentMethodService.getById(app.db, TEST_COMPANY_ID, first.id)
expect(firstRefreshed!.isDefault).toBe(false)
})
it('unsets old default when updating to default', async () => {
const first = await PaymentMethodService.create(app.db, TEST_COMPANY_ID, {
accountId,
processor: 'stripe',
processorPaymentMethodId: 'pm_1',
isDefault: true,
})
const second = await PaymentMethodService.create(app.db, TEST_COMPANY_ID, {
accountId,
processor: 'stripe',
processorPaymentMethodId: 'pm_2',
isDefault: false,
})
await PaymentMethodService.update(app.db, TEST_COMPANY_ID, second.id, { isDefault: true })
const firstRefreshed = await PaymentMethodService.getById(app.db, TEST_COMPANY_ID, first.id)
expect(firstRefreshed!.isDefault).toBe(false)
const secondRefreshed = await PaymentMethodService.getById(app.db, TEST_COMPANY_ID, second.id)
expect(secondRefreshed!.isDefault).toBe(true)
})
it('does not affect other accounts when setting default', async () => {
const otherAccount = await AccountService.create(app.db, TEST_COMPANY_ID, { name: 'Other' })
const otherPm = await PaymentMethodService.create(app.db, TEST_COMPANY_ID, {
accountId: otherAccount.id,
processor: 'stripe',
processorPaymentMethodId: 'pm_other',
isDefault: true,
})
// Create default on our account — should not touch the other account's default
await PaymentMethodService.create(app.db, TEST_COMPANY_ID, {
accountId,
processor: 'stripe',
processorPaymentMethodId: 'pm_ours',
isDefault: true,
})
const otherRefreshed = await PaymentMethodService.getById(app.db, TEST_COMPANY_ID, otherPm.id)
expect(otherRefreshed!.isDefault).toBe(true)
})
it('lists only methods for the requested account', async () => {
const otherAccount = await AccountService.create(app.db, TEST_COMPANY_ID, { name: 'Other' })
await PaymentMethodService.create(app.db, TEST_COMPANY_ID, {
accountId,
processor: 'stripe',
processorPaymentMethodId: 'pm_a',
isDefault: false,
})
await PaymentMethodService.create(app.db, TEST_COMPANY_ID, {
accountId: otherAccount.id,
processor: 'stripe',
processorPaymentMethodId: 'pm_b',
isDefault: false,
})
const methods = await PaymentMethodService.listByAccount(app.db, TEST_COMPANY_ID, accountId)
expect(methods.length).toBe(1)
expect(methods[0].processorPaymentMethodId).toBe('pm_a')
})
it('deletes a payment method', async () => {
const pm = await PaymentMethodService.create(app.db, TEST_COMPANY_ID, {
accountId,
processor: 'stripe',
processorPaymentMethodId: 'pm_del',
isDefault: false,
})
const deleted = await PaymentMethodService.delete(app.db, TEST_COMPANY_ID, pm.id)
expect(deleted).not.toBeNull()
const fetched = await PaymentMethodService.getById(app.db, TEST_COMPANY_ID, pm.id)
expect(fetched).toBeNull()
})
})
describe('TaxExemptionService', () => {
let app: FastifyInstance
let accountId: string
let userId: string
beforeAll(async () => {
app = await createTestApp()
})
beforeEach(async () => {
await cleanDb(app)
await seedTestCompany(app)
const auth = await registerAndLogin(app, { email: `tax-svc-${Date.now()}@test.com` })
userId = (auth.user as { id: string }).id
const account = await AccountService.create(app.db, TEST_COMPANY_ID, { name: 'Tax Test' })
accountId = account.id
})
afterAll(async () => {
await app.close()
})
it('creates an exemption in pending status', async () => {
const exemption = await TaxExemptionService.create(app.db, TEST_COMPANY_ID, {
accountId,
certificateNumber: 'TX-001',
certificateType: 'resale',
issuingState: 'TX',
})
expect(exemption.status).toBe('pending')
expect(exemption.certificateNumber).toBe('TX-001')
expect(exemption.approvedBy).toBeNull()
})
it('approves a pending exemption', async () => {
const exemption = await TaxExemptionService.create(app.db, TEST_COMPANY_ID, {
accountId,
certificateNumber: 'TX-002',
})
const approved = await TaxExemptionService.approve(app.db, TEST_COMPANY_ID, exemption.id, userId)
expect(approved!.status).toBe('approved')
expect(approved!.approvedBy).toBe(userId)
expect(approved!.approvedAt).toBeTruthy()
})
it('revokes an exemption with reason', async () => {
const exemption = await TaxExemptionService.create(app.db, TEST_COMPANY_ID, {
accountId,
certificateNumber: 'TX-003',
})
await TaxExemptionService.approve(app.db, TEST_COMPANY_ID, exemption.id, userId)
const revoked = await TaxExemptionService.revoke(app.db, TEST_COMPANY_ID, exemption.id, userId, 'Expired')
expect(revoked!.status).toBe('none')
expect(revoked!.revokedBy).toBe(userId)
expect(revoked!.revokedReason).toBe('Expired')
expect(revoked!.revokedAt).toBeTruthy()
})
it('lists exemptions for an account', async () => {
await TaxExemptionService.create(app.db, TEST_COMPANY_ID, {
accountId,
certificateNumber: 'CERT-A',
})
await TaxExemptionService.create(app.db, TEST_COMPANY_ID, {
accountId,
certificateNumber: 'CERT-B',
})
const list = await TaxExemptionService.listByAccount(app.db, TEST_COMPANY_ID, accountId)
expect(list.length).toBe(2)
})
it('updates exemption details', async () => {
const exemption = await TaxExemptionService.create(app.db, TEST_COMPANY_ID, {
accountId,
certificateNumber: 'OLD',
})
const updated = await TaxExemptionService.update(app.db, TEST_COMPANY_ID, exemption.id, {
certificateNumber: 'NEW',
issuingState: 'CA',
})
expect(updated!.certificateNumber).toBe('NEW')
expect(updated!.issuingState).toBe('CA')
})
it('returns null for nonexistent exemption', async () => {
const result = await TaxExemptionService.getById(app.db, TEST_COMPANY_ID, '00000000-0000-0000-0000-000000000000')
expect(result).toBeNull()
})
})

View File

@@ -1,152 +0,0 @@
import { describe, it, expect, beforeAll, beforeEach, afterAll } from 'bun:test'
import type { FastifyInstance } from 'fastify'
import { createTestApp, cleanDb, seedTestCompany, TEST_COMPANY_ID } from '../../src/test/helpers.js'
import { UnitStatusService, ItemConditionService } from '../../src/services/lookup.service.js'
describe('UnitStatusService', () => {
let app: FastifyInstance
beforeAll(async () => {
app = await createTestApp()
})
beforeEach(async () => {
await cleanDb(app)
await seedTestCompany(app)
})
afterAll(async () => {
await app.close()
})
describe('seedForCompany', () => {
it('seeds system statuses on first call', async () => {
const statuses = await UnitStatusService.list(app.db, TEST_COMPANY_ID)
expect(statuses.length).toBeGreaterThanOrEqual(8)
expect(statuses.every((s) => s.isSystem)).toBe(true)
})
it('is idempotent — second seed does not duplicate', async () => {
await UnitStatusService.seedForCompany(app.db, TEST_COMPANY_ID)
const statuses = await UnitStatusService.list(app.db, TEST_COMPANY_ID)
const slugs = statuses.map((s) => s.slug)
const uniqueSlugs = new Set(slugs)
expect(slugs.length).toBe(uniqueSlugs.size)
})
})
describe('getBySlug', () => {
it('returns a system status by slug', async () => {
const status = await UnitStatusService.getBySlug(app.db, TEST_COMPANY_ID, 'available')
expect(status).not.toBeNull()
expect(status!.slug).toBe('available')
expect(status!.isSystem).toBe(true)
})
it('returns null for nonexistent slug', async () => {
const status = await UnitStatusService.getBySlug(app.db, TEST_COMPANY_ID, 'nonexistent')
expect(status).toBeNull()
})
})
describe('validateSlug', () => {
it('returns true for valid active slug', async () => {
expect(await UnitStatusService.validateSlug(app.db, TEST_COMPANY_ID, 'sold')).toBe(true)
})
it('returns false for nonexistent slug', async () => {
expect(await UnitStatusService.validateSlug(app.db, TEST_COMPANY_ID, 'bogus')).toBe(false)
})
})
describe('create', () => {
it('creates a custom (non-system) status', async () => {
const custom = await UnitStatusService.create(app.db, TEST_COMPANY_ID, {
name: 'In Transit',
slug: 'in_transit',
description: 'Being shipped between locations',
sortOrder: 99,
})
expect(custom.slug).toBe('in_transit')
expect(custom.isSystem).toBe(false)
})
})
describe('delete', () => {
it('throws when deleting a system status', async () => {
const system = await UnitStatusService.getBySlug(app.db, TEST_COMPANY_ID, 'available')
expect(system).not.toBeNull()
expect(() => UnitStatusService.delete(app.db, TEST_COMPANY_ID, system!.id)).toThrow('system')
})
it('deletes a custom status', async () => {
const custom = await UnitStatusService.create(app.db, TEST_COMPANY_ID, {
name: 'Temp',
slug: 'temp',
sortOrder: 0,
})
const deleted = await UnitStatusService.delete(app.db, TEST_COMPANY_ID, custom.id)
expect(deleted).not.toBeNull()
expect(deleted!.slug).toBe('temp')
})
it('returns null for nonexistent id', async () => {
const result = await UnitStatusService.delete(app.db, TEST_COMPANY_ID, '00000000-0000-0000-0000-000000000000')
expect(result).toBeNull()
})
})
describe('update', () => {
it('throws when deactivating a system status', async () => {
const system = await UnitStatusService.getBySlug(app.db, TEST_COMPANY_ID, 'sold')
expect(() => UnitStatusService.update(app.db, TEST_COMPANY_ID, system!.id, { isActive: false })).toThrow('system')
})
it('allows renaming a custom status', async () => {
const custom = await UnitStatusService.create(app.db, TEST_COMPANY_ID, {
name: 'Old Name',
slug: 'custom_rename',
sortOrder: 0,
})
const updated = await UnitStatusService.update(app.db, TEST_COMPANY_ID, custom.id, { name: 'New Name' })
expect(updated!.name).toBe('New Name')
})
})
})
describe('ItemConditionService', () => {
let app: FastifyInstance
beforeAll(async () => {
app = await createTestApp()
})
beforeEach(async () => {
await cleanDb(app)
await seedTestCompany(app)
})
afterAll(async () => {
await app.close()
})
it('seeds system conditions', async () => {
const conditions = await ItemConditionService.list(app.db, TEST_COMPANY_ID)
const slugs = conditions.map((c) => c.slug)
expect(slugs).toContain('new')
expect(slugs).toContain('excellent')
expect(slugs).toContain('good')
expect(slugs).toContain('fair')
expect(slugs).toContain('poor')
})
it('creates a custom condition', async () => {
const custom = await ItemConditionService.create(app.db, TEST_COMPANY_ID, {
name: 'Refurbished',
slug: 'refurbished',
sortOrder: 10,
})
expect(custom.isSystem).toBe(false)
expect(await ItemConditionService.validateSlug(app.db, TEST_COMPANY_ID, 'refurbished')).toBe(true)
})
})