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.
194 lines
5.1 KiB
TypeScript
194 lines
5.1 KiB
TypeScript
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')
|
|
})
|
|
})
|