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:
193
packages/backend/__tests__/routes/v1/inventory.test.ts
Normal file
193
packages/backend/__tests__/routes/v1/inventory.test.ts
Normal 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')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user