Move tests to __tests__ folders, add unit tests for shared utils and services

Restructure tests into __tests__/ directories at package root so they can
be excluded from production builds. Add unit tests for dates, currency,
lookup service, payment method default logic, and tax exemption state
transitions.
This commit is contained in:
Ryan Moon
2026-03-27 21:14:42 -05:00
parent 0a2d6e23af
commit 01d6ff3fa3
10 changed files with 545 additions and 6 deletions

View File

@@ -0,0 +1,193 @@
import { describe, it, expect, beforeAll, beforeEach, afterAll } from 'bun:test'
import type { FastifyInstance } from 'fastify'
import {
createTestApp,
cleanDb,
seedTestCompany,
registerAndLogin,
} from '../../../src/test/helpers.js'
describe('Category routes', () => {
let app: FastifyInstance
let token: string
beforeAll(async () => {
app = await createTestApp()
})
beforeEach(async () => {
await cleanDb(app)
await seedTestCompany(app)
const auth = await registerAndLogin(app)
token = auth.token
})
afterAll(async () => {
await app.close()
})
it('creates a category', async () => {
const response = await app.inject({
method: 'POST',
url: '/v1/categories',
headers: { authorization: `Bearer ${token}` },
payload: { name: 'Guitars', description: 'All guitars', sortOrder: 1 },
})
expect(response.statusCode).toBe(201)
expect(response.json().name).toBe('Guitars')
expect(response.json().sortOrder).toBe(1)
})
it('creates a child category', async () => {
const parentRes = await app.inject({
method: 'POST',
url: '/v1/categories',
headers: { authorization: `Bearer ${token}` },
payload: { name: 'Instruments' },
})
const parentId = parentRes.json().id
const childRes = await app.inject({
method: 'POST',
url: '/v1/categories',
headers: { authorization: `Bearer ${token}` },
payload: { name: 'Brass', parentId },
})
expect(childRes.statusCode).toBe(201)
expect(childRes.json().parentId).toBe(parentId)
})
it('lists categories sorted by sortOrder', async () => {
await app.inject({
method: 'POST',
url: '/v1/categories',
headers: { authorization: `Bearer ${token}` },
payload: { name: 'Zzz Last', sortOrder: 99 },
})
await app.inject({
method: 'POST',
url: '/v1/categories',
headers: { authorization: `Bearer ${token}` },
payload: { name: 'Aaa First', sortOrder: 1 },
})
const response = await app.inject({
method: 'GET',
url: '/v1/categories',
headers: { authorization: `Bearer ${token}` },
})
expect(response.statusCode).toBe(200)
const body = response.json()
expect(body.data.length).toBe(2)
expect(body.data[0].name).toBe('Aaa First')
})
it('soft-deletes a category', async () => {
const createRes = await app.inject({
method: 'POST',
url: '/v1/categories',
headers: { authorization: `Bearer ${token}` },
payload: { name: 'To Delete' },
})
const delRes = await app.inject({
method: 'DELETE',
url: `/v1/categories/${createRes.json().id}`,
headers: { authorization: `Bearer ${token}` },
})
expect(delRes.json().isActive).toBe(false)
const listRes = await app.inject({
method: 'GET',
url: '/v1/categories',
headers: { authorization: `Bearer ${token}` },
})
expect(listRes.json().data.length).toBe(0)
})
})
describe('Supplier routes', () => {
let app: FastifyInstance
let token: string
beforeAll(async () => {
app = await createTestApp()
})
beforeEach(async () => {
await cleanDb(app)
await seedTestCompany(app)
const auth = await registerAndLogin(app, { email: `supplier-${Date.now()}@test.com` })
token = auth.token
})
afterAll(async () => {
await app.close()
})
it('creates a supplier', async () => {
const response = await app.inject({
method: 'POST',
url: '/v1/suppliers',
headers: { authorization: `Bearer ${token}` },
payload: {
name: 'RS Musical',
contactName: 'Bob Smith',
email: 'bob@rsmusical.com',
paymentTerms: 'Net 30',
},
})
expect(response.statusCode).toBe(201)
expect(response.json().name).toBe('RS Musical')
expect(response.json().paymentTerms).toBe('Net 30')
})
it('searches suppliers by name', async () => {
await app.inject({
method: 'POST',
url: '/v1/suppliers',
headers: { authorization: `Bearer ${token}` },
payload: { name: "Ferree's Tools" },
})
await app.inject({
method: 'POST',
url: '/v1/suppliers',
headers: { authorization: `Bearer ${token}` },
payload: { name: 'Allied Supply' },
})
const response = await app.inject({
method: 'GET',
url: '/v1/suppliers?q=ferree',
headers: { authorization: `Bearer ${token}` },
})
expect(response.statusCode).toBe(200)
expect(response.json().data.length).toBe(1)
expect(response.json().data[0].name).toBe("Ferree's Tools")
})
it('updates a supplier', async () => {
const createRes = await app.inject({
method: 'POST',
url: '/v1/suppliers',
headers: { authorization: `Bearer ${token}` },
payload: { name: 'Old Name' },
})
const updateRes = await app.inject({
method: 'PATCH',
url: `/v1/suppliers/${createRes.json().id}`,
headers: { authorization: `Bearer ${token}` },
payload: { name: 'New Name', paymentTerms: 'COD' },
})
expect(updateRes.statusCode).toBe(200)
expect(updateRes.json().name).toBe('New Name')
expect(updateRes.json().paymentTerms).toBe('COD')
})
})