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,166 @@
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'
describe('Auth routes', () => {
let app: FastifyInstance
beforeAll(async () => {
app = await createTestApp()
})
beforeEach(async () => {
await cleanDb(app)
await seedTestCompany(app)
})
afterAll(async () => {
await app.close()
})
describe('POST /v1/auth/register', () => {
it('creates a user and returns token', async () => {
const response = await app.inject({
method: 'POST',
url: '/v1/auth/register',
headers: { 'x-company-id': TEST_COMPANY_ID },
payload: {
email: 'staff@musicstore.com',
password: 'securepassword',
firstName: 'Jane',
lastName: 'Doe',
role: 'staff',
},
})
expect(response.statusCode).toBe(201)
const body = response.json()
expect(body.user.email).toBe('staff@musicstore.com')
expect(body.user.firstName).toBe('Jane')
expect(body.user.role).toBe('staff')
expect(body.token).toBeDefined()
expect(body.user.passwordHash).toBeUndefined()
})
it('rejects duplicate email within same company', async () => {
await app.inject({
method: 'POST',
url: '/v1/auth/register',
headers: { 'x-company-id': TEST_COMPANY_ID },
payload: {
email: 'dupe@test.com',
password: 'password123',
firstName: 'First',
lastName: 'User',
},
})
const response = await app.inject({
method: 'POST',
url: '/v1/auth/register',
headers: { 'x-company-id': TEST_COMPANY_ID },
payload: {
email: 'dupe@test.com',
password: 'password456',
firstName: 'Second',
lastName: 'User',
},
})
expect(response.statusCode).toBe(409)
})
it('rejects invalid email', async () => {
const response = await app.inject({
method: 'POST',
url: '/v1/auth/register',
headers: { 'x-company-id': TEST_COMPANY_ID },
payload: {
email: 'not-an-email',
password: 'password123',
firstName: 'Bad',
lastName: 'Email',
},
})
expect(response.statusCode).toBe(400)
})
it('rejects short password', async () => {
const response = await app.inject({
method: 'POST',
url: '/v1/auth/register',
headers: { 'x-company-id': TEST_COMPANY_ID },
payload: {
email: 'short@test.com',
password: '123',
firstName: 'Short',
lastName: 'Pass',
},
})
expect(response.statusCode).toBe(400)
})
})
describe('POST /v1/auth/login', () => {
beforeEach(async () => {
await app.inject({
method: 'POST',
url: '/v1/auth/register',
headers: { 'x-company-id': TEST_COMPANY_ID },
payload: {
email: 'login@test.com',
password: 'correctpassword',
firstName: 'Login',
lastName: 'User',
},
})
})
it('returns token with valid credentials', async () => {
const response = await app.inject({
method: 'POST',
url: '/v1/auth/login',
headers: { 'x-company-id': TEST_COMPANY_ID },
payload: {
email: 'login@test.com',
password: 'correctpassword',
},
})
expect(response.statusCode).toBe(200)
const body = response.json()
expect(body.token).toBeDefined()
expect(body.user.email).toBe('login@test.com')
})
it('rejects wrong password', async () => {
const response = await app.inject({
method: 'POST',
url: '/v1/auth/login',
headers: { 'x-company-id': TEST_COMPANY_ID },
payload: {
email: 'login@test.com',
password: 'wrongpassword',
},
})
expect(response.statusCode).toBe(401)
})
it('rejects nonexistent email', async () => {
const response = await app.inject({
method: 'POST',
url: '/v1/auth/login',
headers: { 'x-company-id': TEST_COMPANY_ID },
payload: {
email: 'nobody@test.com',
password: 'whatever',
},
})
expect(response.statusCode).toBe(401)
})
})
})