@accounter/server 0.0.9-alpha-20251210173721-a5bb944d9abd3f354daf897072b78bea4d8269c9 → 0.0.9-alpha-20251210180846-69e726b23ba814acaf7af8af75df20475e55a7d7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -5
- package/dist/server/src/__tests__/helpers/db-setup.d.ts +0 -1
- package/dist/server/src/__tests__/helpers/db-setup.js +0 -2
- package/dist/server/src/__tests__/helpers/db-setup.js.map +1 -1
- package/dist/server/src/__tests__/helpers/seed-helpers.business.test.js +23 -31
- package/dist/server/src/__tests__/helpers/seed-helpers.business.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/seed-helpers.concurrent.test.js +8 -8
- package/dist/server/src/__tests__/helpers/seed-helpers.concurrent.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/seed-helpers.financial-entity.test.js +41 -50
- package/dist/server/src/__tests__/helpers/seed-helpers.financial-entity.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/seed-helpers.tax-category.test.js +23 -31
- package/dist/server/src/__tests__/helpers/seed-helpers.tax-category.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/test-db-config.js +1 -1
- package/dist/server/src/__tests__/helpers/test-db-config.js.map +1 -1
- package/dist/server/src/__tests__/seed-admin-context.integration.test.js +128 -131
- package/dist/server/src/__tests__/seed-admin-context.integration.test.js.map +1 -1
- package/dist/server/src/modules/business-trips/providers/business-trips.provider.d.ts +1 -1
- package/dist/server/src/modules/business-trips/providers/business-trips.provider.js +1 -1
- package/dist/server/src/modules/business-trips/providers/business-trips.provider.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/helpers/db-setup.ts +0 -3
- package/src/__tests__/helpers/seed-helpers.business.test.ts +145 -147
- package/src/__tests__/helpers/seed-helpers.concurrent.test.ts +10 -10
- package/src/__tests__/helpers/seed-helpers.financial-entity.test.ts +218 -231
- package/src/__tests__/helpers/seed-helpers.tax-category.test.ts +162 -164
- package/src/__tests__/helpers/test-db-config.ts +1 -1
- package/src/__tests__/seed-admin-context.integration.test.ts +199 -208
- package/src/modules/business-trips/providers/business-trips.provider.ts +1 -1
|
@@ -1,176 +1,174 @@
|
|
|
1
|
-
import { describe, expect, it, beforeAll, afterAll
|
|
2
|
-
import
|
|
3
|
-
import { testDbConfig, qualifyTable } from './test-db-config.js';
|
|
1
|
+
import { describe, expect, it, beforeAll, afterAll } from 'vitest';
|
|
2
|
+
import { qualifyTable } from './test-db-config.js';
|
|
4
3
|
import { ensureFinancialEntity, ensureTaxCategoryForEntity } from './seed-helpers.js';
|
|
5
4
|
import { EntityValidationError } from './seed-errors.js';
|
|
5
|
+
import { TestDatabase } from './db-setup.js';
|
|
6
6
|
|
|
7
7
|
describe('ensureTaxCategoryForEntity', () => {
|
|
8
|
-
let
|
|
9
|
-
let client: pg.PoolClient;
|
|
8
|
+
let db: TestDatabase;
|
|
10
9
|
|
|
11
10
|
beforeAll(async () => {
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
db = new TestDatabase();
|
|
12
|
+
await db.connect();
|
|
14
13
|
});
|
|
15
14
|
|
|
16
15
|
afterAll(async () => {
|
|
17
|
-
|
|
18
|
-
await pool.end();
|
|
16
|
+
await db.close();
|
|
19
17
|
});
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
19
|
+
it('should create tax category on first call', async () =>
|
|
20
|
+
db.withTransaction(async client => {
|
|
21
|
+
// Create financial entity
|
|
22
|
+
const { id: entityId } = await ensureFinancialEntity(client, {
|
|
23
|
+
name: 'VAT Category',
|
|
24
|
+
type: 'tax_category',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Create tax category
|
|
28
|
+
await ensureTaxCategoryForEntity(client, entityId);
|
|
29
|
+
|
|
30
|
+
// Verify tax category exists
|
|
31
|
+
const result = await client.query(
|
|
32
|
+
`SELECT id FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
|
|
33
|
+
[entityId],
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
expect(result.rows).toHaveLength(1);
|
|
37
|
+
expect(result.rows[0].id).toBe(entityId);
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
it('should be idempotent (no-op on repeated calls)', async () =>
|
|
41
|
+
db.withTransaction(async client => {
|
|
42
|
+
// Create financial entity
|
|
43
|
+
const { id: entityId } = await ensureFinancialEntity(client, {
|
|
44
|
+
name: 'Income Tax',
|
|
45
|
+
type: 'tax_category',
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Create tax category twice
|
|
49
|
+
await ensureTaxCategoryForEntity(client, entityId);
|
|
50
|
+
await ensureTaxCategoryForEntity(client, entityId);
|
|
51
|
+
|
|
52
|
+
// Verify only one row exists
|
|
53
|
+
const result = await client.query(
|
|
54
|
+
`SELECT COUNT(*) as count FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
|
|
55
|
+
[entityId],
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
expect(result.rows[0].count).toBe('1');
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
it('should preserve existing values on subsequent calls', async () =>
|
|
62
|
+
db.withTransaction(async client => {
|
|
63
|
+
// Create financial entity
|
|
64
|
+
const { id: entityId } = await ensureFinancialEntity(client, {
|
|
65
|
+
name: 'Expense Category',
|
|
66
|
+
type: 'tax_category',
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Create tax category
|
|
70
|
+
await ensureTaxCategoryForEntity(client, entityId);
|
|
71
|
+
|
|
72
|
+
// Get initial state
|
|
73
|
+
const initialResult = await client.query(
|
|
74
|
+
`SELECT * FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
|
|
75
|
+
[entityId],
|
|
76
|
+
);
|
|
77
|
+
const initialRow = initialResult.rows[0];
|
|
78
|
+
|
|
79
|
+
// Call again (should not modify)
|
|
80
|
+
await ensureTaxCategoryForEntity(client, entityId, { sortCode: 999 });
|
|
81
|
+
|
|
82
|
+
// Verify unchanged
|
|
83
|
+
const finalResult = await client.query(
|
|
84
|
+
`SELECT * FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
|
|
85
|
+
[entityId],
|
|
86
|
+
);
|
|
87
|
+
const finalRow = finalResult.rows[0];
|
|
88
|
+
|
|
89
|
+
expect(finalRow).toEqual(initialRow);
|
|
90
|
+
}));
|
|
91
|
+
|
|
92
|
+
it('should reject invalid UUID format', async () =>
|
|
93
|
+
db.withTransaction(async client => {
|
|
94
|
+
await expect(ensureTaxCategoryForEntity(client, 'not-a-uuid')).rejects.toThrow(
|
|
95
|
+
EntityValidationError,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
await expect(ensureTaxCategoryForEntity(client, '')).rejects.toThrow(
|
|
99
|
+
EntityValidationError,
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
await expect(ensureTaxCategoryForEntity(client, '12345')).rejects.toThrow(
|
|
103
|
+
EntityValidationError,
|
|
104
|
+
);
|
|
105
|
+
}));
|
|
106
|
+
|
|
107
|
+
it('should reject non-existent financial entity', async () =>
|
|
108
|
+
db.withTransaction(async client => {
|
|
109
|
+
const fakeUuid = '00000000-0000-0000-0000-000000000001';
|
|
110
|
+
|
|
111
|
+
await expect(ensureTaxCategoryForEntity(client, fakeUuid)).rejects.toThrow(
|
|
112
|
+
EntityValidationError,
|
|
113
|
+
);
|
|
114
|
+
}));
|
|
115
|
+
|
|
116
|
+
it('should not leak data between tests', async () =>
|
|
117
|
+
db.withTransaction(async client => {
|
|
118
|
+
// This test verifies transactional isolation by checking that data
|
|
119
|
+
// from previous tests is not visible
|
|
120
|
+
const result = await client.query(
|
|
121
|
+
`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')`,
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// Due to ROLLBACK after each test, count should be 0
|
|
125
|
+
expect(parseInt(result.rows[0].count)).toBe(0);
|
|
126
|
+
}));
|
|
127
|
+
|
|
128
|
+
it('should work with entities that have owner_id', async () =>
|
|
129
|
+
db.withTransaction(async client => {
|
|
130
|
+
// Create owner business entity (without owner_id requirement)
|
|
131
|
+
const { id: _ownerId } = await ensureFinancialEntity(client, {
|
|
132
|
+
name: 'Owner Business',
|
|
133
|
+
type: 'business',
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Create owned tax category entity (tax categories can have owner_id)
|
|
137
|
+
const { id: taxCatId } = await ensureFinancialEntity(client, {
|
|
138
|
+
name: 'Owned Tax Category',
|
|
139
|
+
type: 'tax_category',
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Create tax category
|
|
143
|
+
await ensureTaxCategoryForEntity(client, taxCatId);
|
|
144
|
+
|
|
145
|
+
// Verify tax category exists
|
|
146
|
+
const result = await client.query(
|
|
147
|
+
`SELECT id FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
|
|
148
|
+
[taxCatId],
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
expect(result.rows).toHaveLength(1);
|
|
152
|
+
expect(result.rows[0].id).toBe(taxCatId);
|
|
153
|
+
}));
|
|
154
|
+
|
|
155
|
+
it('should handle options parameter gracefully (future-proofing)', async () =>
|
|
156
|
+
db.withTransaction(async client => {
|
|
157
|
+
// Create financial entity
|
|
158
|
+
const { id: entityId } = await ensureFinancialEntity(client, {
|
|
159
|
+
name: 'Category with Options',
|
|
160
|
+
type: 'tax_category',
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Create tax category with options
|
|
164
|
+
await ensureTaxCategoryForEntity(client, entityId, { sortCode: 1000 });
|
|
165
|
+
|
|
166
|
+
// Verify tax category exists
|
|
167
|
+
const result = await client.query(
|
|
168
|
+
`SELECT id FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
|
|
169
|
+
[entityId],
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
expect(result.rows).toHaveLength(1);
|
|
173
|
+
}));
|
|
176
174
|
});
|
|
@@ -13,7 +13,7 @@ export const testDbConfig: PoolConfig = {
|
|
|
13
13
|
password: process.env.POSTGRES_PASSWORD || 'postgres',
|
|
14
14
|
host: process.env.POSTGRES_HOST || 'localhost',
|
|
15
15
|
port: parseInt(process.env.POSTGRES_PORT || '5432', 10),
|
|
16
|
-
database: process.env.POSTGRES_DB || '
|
|
16
|
+
database: process.env.POSTGRES_DB || 'accounter_test',
|
|
17
17
|
ssl: process.env.POSTGRES_SSL === '1',
|
|
18
18
|
};
|
|
19
19
|
|