@accounter/server
Version:
Accounter GraphQL server
160 lines (127 loc) • 5.27 kB
text/typescript
import { describe, expect, it, beforeAll, afterAll } from 'vitest';
import { qualifyTable } from './test-db-config.js';
import { ensureFinancialEntity, ensureTaxCategoryForEntity, setAdminEntity } from './seed-helpers.js';
import { EntityValidationError } from './seed-errors.js';
import { TestDatabase } from './db-setup.js';
describe('ensureTaxCategoryForEntity', () => {
let db: TestDatabase;
beforeAll(async () => {
db = new TestDatabase();
await db.connect();
});
afterAll(async () => {
await db.close();
});
it('should create tax category on first call', async () =>
db.withTransaction(async client => {
const ownerId = await setAdminEntity(client);
// Create financial entity
const { id: entityId } = await ensureFinancialEntity(client, {
name: 'VAT Category',
type: 'tax_category',
ownerId,
});
// Create tax category
await ensureTaxCategoryForEntity(client, entityId, {ownerId});
// Verify tax category exists
const result = await client.query(
`SELECT id FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
[entityId],
);
expect(result.rows).toHaveLength(1);
expect(result.rows[0].id).toBe(entityId);
}));
it('should be idempotent (no-op on repeated calls)', async () =>
db.withTransaction(async client => {
const ownerId = await setAdminEntity(client);
// Create financial entity
const { id: entityId } = await ensureFinancialEntity(client, {
name: 'Income Tax',
type: 'tax_category',
ownerId,
});
// Create tax category twice
await ensureTaxCategoryForEntity(client, entityId, {ownerId});
await ensureTaxCategoryForEntity(client, entityId, {ownerId});
// Verify only one row exists
const result = await client.query(
`SELECT COUNT(*) as count FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
[entityId],
);
expect(result.rows[0].count).toBe('1');
}));
it('should preserve existing values on subsequent calls', async () =>
db.withTransaction(async client => {
const ownerId = await setAdminEntity(client);
// Create financial entity
const { id: entityId } = await ensureFinancialEntity(client, {
name: 'Expense Category',
type: 'tax_category',
ownerId,
});
// Create tax category
await ensureTaxCategoryForEntity(client, entityId, {ownerId});
// Get initial state
const initialResult = await client.query(
`SELECT * FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
[entityId],
);
const initialRow = initialResult.rows[0];
// Call again (should not modify)
await ensureTaxCategoryForEntity(client, entityId, { sortCode: 999, ownerId });
// Verify unchanged
const finalResult = await client.query(
`SELECT * FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
[entityId],
);
const finalRow = finalResult.rows[0];
expect(finalRow).toEqual(initialRow);
}));
it('should reject invalid UUID format', async () =>
db.withTransaction(async client => {
await expect(ensureTaxCategoryForEntity(client, 'not-a-uuid')).rejects.toThrow(
EntityValidationError,
);
await expect(ensureTaxCategoryForEntity(client, '')).rejects.toThrow(
EntityValidationError,
);
await expect(ensureTaxCategoryForEntity(client, '12345')).rejects.toThrow(
EntityValidationError,
);
}));
it('should reject non-existent financial entity', async () =>
db.withTransaction(async client => {
const fakeUuid = '00000000-0000-0000-0000-000000000001';
await expect(ensureTaxCategoryForEntity(client, fakeUuid)).rejects.toThrow(
EntityValidationError,
);
}));
it('should not leak data between tests', async () =>
db.withTransaction(async client => {
// This test verifies transactional isolation by checking that data
// from previous tests is not visible
const result = await client.query(
`SELECT COUNT(*) as count FROM ${qualifyTable('tax_categories')} WHERE id IN (SELECT id FROM ${qualifyTable('financial_entities')} WHERE name LIKE 'VAT Category' OR name LIKE 'Income Tax' OR name LIKE 'Expense Category')`,
);
// Due to ROLLBACK after each test, count should be 0
expect(parseInt(result.rows[0].count)).toBe(0);
}));
it('should handle options parameter gracefully (future-proofing)', async () =>
db.withTransaction(async client => {
const ownerId = await setAdminEntity(client);
// Create financial entity
const { id: entityId } = await ensureFinancialEntity(client, {
name: 'Category with Options',
type: 'tax_category',
ownerId,
});
// Create tax category with options
await ensureTaxCategoryForEntity(client, entityId, { sortCode: 1000, ownerId });
// Verify tax category exists
const result = await client.query(
`SELECT id FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
[entityId],
);
expect(result.rows).toHaveLength(1);
}));
});