@accounter/server 0.0.9-alpha-20251210173458-9f3d75bb8729ec6038c777f7dbf9a1b5fa727888 → 0.0.9-alpha-20251210173721-a5bb944d9abd3f354daf897072b78bea4d8269c9

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.
Files changed (28) hide show
  1. package/CHANGELOG.md +5 -21
  2. package/dist/server/src/__tests__/helpers/db-setup.d.ts +1 -0
  3. package/dist/server/src/__tests__/helpers/db-setup.js +2 -0
  4. package/dist/server/src/__tests__/helpers/db-setup.js.map +1 -1
  5. package/dist/server/src/__tests__/helpers/seed-helpers.business.test.js +31 -23
  6. package/dist/server/src/__tests__/helpers/seed-helpers.business.test.js.map +1 -1
  7. package/dist/server/src/__tests__/helpers/seed-helpers.concurrent.test.js +8 -8
  8. package/dist/server/src/__tests__/helpers/seed-helpers.concurrent.test.js.map +1 -1
  9. package/dist/server/src/__tests__/helpers/seed-helpers.financial-entity.test.js +50 -41
  10. package/dist/server/src/__tests__/helpers/seed-helpers.financial-entity.test.js.map +1 -1
  11. package/dist/server/src/__tests__/helpers/seed-helpers.tax-category.test.js +31 -23
  12. package/dist/server/src/__tests__/helpers/seed-helpers.tax-category.test.js.map +1 -1
  13. package/dist/server/src/__tests__/helpers/test-db-config.js +1 -1
  14. package/dist/server/src/__tests__/helpers/test-db-config.js.map +1 -1
  15. package/dist/server/src/__tests__/seed-admin-context.integration.test.js +131 -128
  16. package/dist/server/src/__tests__/seed-admin-context.integration.test.js.map +1 -1
  17. package/dist/server/src/modules/business-trips/providers/business-trips.provider.d.ts +1 -1
  18. package/dist/server/src/modules/business-trips/providers/business-trips.provider.js +1 -1
  19. package/dist/server/src/modules/business-trips/providers/business-trips.provider.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/__tests__/helpers/db-setup.ts +3 -0
  22. package/src/__tests__/helpers/seed-helpers.business.test.ts +147 -145
  23. package/src/__tests__/helpers/seed-helpers.concurrent.test.ts +10 -10
  24. package/src/__tests__/helpers/seed-helpers.financial-entity.test.ts +231 -218
  25. package/src/__tests__/helpers/seed-helpers.tax-category.test.ts +164 -162
  26. package/src/__tests__/helpers/test-db-config.ts +1 -1
  27. package/src/__tests__/seed-admin-context.integration.test.ts +208 -199
  28. package/src/modules/business-trips/providers/business-trips.provider.ts +1 -1
@@ -1,245 +1,258 @@
1
- import { describe, it, expect, beforeAll, afterAll } from 'vitest';
1
+ import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from 'vitest';
2
+ import pg from 'pg';
2
3
  import { ensureFinancialEntity } from './seed-helpers.js';
3
- import { qualifyTable } from './test-db-config.js';
4
+ import { testDbConfig, qualifyTable } from './test-db-config.js';
4
5
  import { EntityValidationError } from './seed-errors.js';
5
- import { TestDatabase } from './db-setup.js';
6
6
 
7
7
  describe('ensureFinancialEntity', () => {
8
- let db: TestDatabase;
8
+ let pool: pg.Pool;
9
+ let client: pg.PoolClient;
9
10
 
10
11
  beforeAll(async () => {
11
- db = new TestDatabase();
12
- await db.connect();
12
+ // Create connection pool with shared config
13
+ pool = new pg.Pool(testDbConfig);
14
+
15
+ // Get a client for transactions
16
+ client = await pool.connect();
13
17
  });
14
18
 
15
19
  afterAll(async () => {
16
- await db.close();
20
+ // Release client and close pool
21
+ if (client) {
22
+ client.release();
23
+ }
24
+ if (pool) {
25
+ await pool.end();
26
+ }
17
27
  });
18
28
 
19
- it('should create a new financial entity when it does not exist', async () =>
20
- db.withTransaction(async client => {
21
- const result = await ensureFinancialEntity(client, {
22
- name: 'Test Entity',
23
- type: 'business',
24
- });
25
-
26
- expect(result).toHaveProperty('id');
27
- expect(typeof result.id).toBe('string');
28
-
29
- // Verify it was inserted
30
- const checkResult = await client.query(
31
- `SELECT id, name, type, owner_id FROM ${qualifyTable('financial_entities')} WHERE id = $1`,
32
- [result.id],
33
- );
34
-
35
- expect(checkResult.rows.length).toBe(1);
36
- expect(checkResult.rows[0].name).toBe('Test Entity');
37
- expect(checkResult.rows[0].type).toBe('business');
38
- expect(checkResult.rows[0].owner_id).toBeNull();
39
- }));
40
-
41
- it('should return existing entity when called twice with same parameters', async () =>
42
- db.withTransaction(async client => {
43
- const firstResult = await ensureFinancialEntity(client, {
44
- name: 'Duplicate Test',
45
- type: 'tax_category',
46
- });
47
-
48
- const secondResult = await ensureFinancialEntity(client, {
49
- name: 'Duplicate Test',
50
- type: 'tax_category',
51
- });
52
-
53
- expect(firstResult.id).toBe(secondResult.id);
54
-
55
- // Verify only one row exists
56
- const countResult = await client.query(
57
- `SELECT COUNT(*) FROM ${qualifyTable('financial_entities')} WHERE name = $1 AND type = $2`,
58
- ['Duplicate Test', 'tax_category'],
59
- );
60
-
61
- expect(parseInt(countResult.rows[0].count)).toBe(1);
62
- }));
63
-
64
- it('should handle entities with owner_id', async () =>
65
- db.withTransaction(async client => {
66
- // First create an owner entity (business)
67
- const ownerEntityResult = await ensureFinancialEntity(client, {
68
- name: 'Owner Entity',
69
- type: 'business',
70
- });
71
-
72
- // Create corresponding business record (required for foreign key)
73
- await client.query(`INSERT INTO ${qualifyTable('businesses')} (id) VALUES ($1)`, [
74
- ownerEntityResult.id,
75
- ]);
76
-
77
- // Create owned entity (tax_category)
78
- const result = await ensureFinancialEntity(client, {
79
- name: 'Owned Entity',
80
- type: 'tax_category',
81
- ownerId: ownerEntityResult.id,
82
- });
83
-
84
- expect(result).toHaveProperty('id');
85
-
86
- // Verify owner_id is set correctly
87
- const checkResult = await client.query(
88
- `SELECT owner_id FROM ${qualifyTable('financial_entities')} WHERE id = $1`,
89
- [result.id],
90
- );
91
-
92
- expect(checkResult.rows[0].owner_id).toBe(ownerEntityResult.id);
93
- }));
94
-
95
- it('should be idempotent for entities with owner_id', async () =>
96
- db.withTransaction(async client => {
97
- const ownerEntityResult = await ensureFinancialEntity(client, {
98
- name: 'Owner Business',
99
- type: 'business',
100
- });
101
-
102
- // Create corresponding business record
103
- await client.query(`INSERT INTO ${qualifyTable('businesses')} (id) VALUES ($1)`, [
104
- ownerEntityResult.id,
105
- ]);
106
-
107
- const firstResult = await ensureFinancialEntity(client, {
108
- name: 'Child Entity',
109
- type: 'tax_category',
110
- ownerId: ownerEntityResult.id,
111
- });
112
-
113
- const secondResult = await ensureFinancialEntity(client, {
114
- name: 'Child Entity',
115
- type: 'tax_category',
116
- ownerId: ownerEntityResult.id,
117
- });
118
-
119
- expect(firstResult.id).toBe(secondResult.id);
120
-
121
- // Verify only one row
122
- const countResult = await client.query(
123
- `SELECT COUNT(*) FROM ${qualifyTable('financial_entities')}
29
+ beforeEach(async () => {
30
+ // Start transaction before each test
31
+ await client.query('BEGIN');
32
+ });
33
+
34
+ afterEach(async () => {
35
+ // Rollback transaction after each test to clean up
36
+ await client.query('ROLLBACK');
37
+ });
38
+
39
+ it('should create a new financial entity when it does not exist', async () => {
40
+ const result = await ensureFinancialEntity(client, {
41
+ name: 'Test Entity',
42
+ type: 'business',
43
+ });
44
+
45
+ expect(result).toHaveProperty('id');
46
+ expect(typeof result.id).toBe('string');
47
+
48
+ // Verify it was inserted
49
+ const checkResult = await client.query(
50
+ `SELECT id, name, type, owner_id FROM ${qualifyTable('financial_entities')} WHERE id = $1`,
51
+ [result.id],
52
+ );
53
+
54
+ expect(checkResult.rows.length).toBe(1);
55
+ expect(checkResult.rows[0].name).toBe('Test Entity');
56
+ expect(checkResult.rows[0].type).toBe('business');
57
+ expect(checkResult.rows[0].owner_id).toBeNull();
58
+ });
59
+
60
+ it('should return existing entity when called twice with same parameters', async () => {
61
+ const firstResult = await ensureFinancialEntity(client, {
62
+ name: 'Duplicate Test',
63
+ type: 'tax_category',
64
+ });
65
+
66
+ const secondResult = await ensureFinancialEntity(client, {
67
+ name: 'Duplicate Test',
68
+ type: 'tax_category',
69
+ });
70
+
71
+ expect(firstResult.id).toBe(secondResult.id);
72
+
73
+ // Verify only one row exists
74
+ const countResult = await client.query(
75
+ `SELECT COUNT(*) FROM ${qualifyTable('financial_entities')} WHERE name = $1 AND type = $2`,
76
+ ['Duplicate Test', 'tax_category'],
77
+ );
78
+
79
+ expect(parseInt(countResult.rows[0].count)).toBe(1);
80
+ });
81
+
82
+ it('should handle entities with owner_id', async () => {
83
+ // First create an owner entity (business)
84
+ const ownerEntityResult = await ensureFinancialEntity(client, {
85
+ name: 'Owner Entity',
86
+ type: 'business',
87
+ });
88
+
89
+ // Create corresponding business record (required for foreign key)
90
+ await client.query(
91
+ `INSERT INTO ${qualifyTable('businesses')} (id) VALUES ($1)`,
92
+ [ownerEntityResult.id],
93
+ );
94
+
95
+ // Create owned entity (tax_category)
96
+ const result = await ensureFinancialEntity(client, {
97
+ name: 'Owned Entity',
98
+ type: 'tax_category',
99
+ ownerId: ownerEntityResult.id,
100
+ });
101
+
102
+ expect(result).toHaveProperty('id');
103
+
104
+ // Verify owner_id is set correctly
105
+ const checkResult = await client.query(
106
+ `SELECT owner_id FROM ${qualifyTable('financial_entities')} WHERE id = $1`,
107
+ [result.id],
108
+ );
109
+
110
+ expect(checkResult.rows[0].owner_id).toBe(ownerEntityResult.id);
111
+ });
112
+
113
+ it('should be idempotent for entities with owner_id', async () => {
114
+ const ownerEntityResult = await ensureFinancialEntity(client, {
115
+ name: 'Owner Business',
116
+ type: 'business',
117
+ });
118
+
119
+ // Create corresponding business record
120
+ await client.query(
121
+ `INSERT INTO ${qualifyTable('businesses')} (id) VALUES ($1)`,
122
+ [ownerEntityResult.id],
123
+ );
124
+
125
+ const firstResult = await ensureFinancialEntity(client, {
126
+ name: 'Child Entity',
127
+ type: 'tax_category',
128
+ ownerId: ownerEntityResult.id,
129
+ });
130
+
131
+ const secondResult = await ensureFinancialEntity(client, {
132
+ name: 'Child Entity',
133
+ type: 'tax_category',
134
+ ownerId: ownerEntityResult.id,
135
+ });
136
+
137
+ expect(firstResult.id).toBe(secondResult.id);
138
+
139
+ // Verify only one row
140
+ const countResult = await client.query(
141
+ `SELECT COUNT(*) FROM ${qualifyTable('financial_entities')}
124
142
  WHERE name = $1 AND type = $2 AND owner_id = $3`,
125
- ['Child Entity', 'tax_category', ownerEntityResult.id],
126
- );
143
+ ['Child Entity', 'tax_category', ownerEntityResult.id],
144
+ );
127
145
 
128
- expect(parseInt(countResult.rows[0].count)).toBe(1);
129
- }));
146
+ expect(parseInt(countResult.rows[0].count)).toBe(1);
147
+ });
130
148
 
131
- it('should distinguish entities by type', async () =>
132
- db.withTransaction(async client => {
133
- const businessResult = await ensureFinancialEntity(client, {
134
- name: 'Same Name',
135
- type: 'business',
136
- });
149
+ it('should distinguish entities by type', async () => {
150
+ const businessResult = await ensureFinancialEntity(client, {
151
+ name: 'Same Name',
152
+ type: 'business',
153
+ });
137
154
 
138
- const taxCategoryResult = await ensureFinancialEntity(client, {
139
- name: 'Same Name',
140
- type: 'tax_category',
141
- });
155
+ const taxCategoryResult = await ensureFinancialEntity(client, {
156
+ name: 'Same Name',
157
+ type: 'tax_category',
158
+ });
142
159
 
143
- expect(businessResult.id).not.toBe(taxCategoryResult.id);
144
- }));
160
+ expect(businessResult.id).not.toBe(taxCategoryResult.id);
161
+ });
145
162
 
146
- it('should distinguish entities by owner_id', async () =>
147
- db.withTransaction(async client => {
148
- const owner1Entity = await ensureFinancialEntity(client, {
149
- name: 'Owner 1',
150
- type: 'business',
151
- });
152
- await client.query(`INSERT INTO ${qualifyTable('businesses')} (id) VALUES ($1)`, [
153
- owner1Entity.id,
154
- ]);
163
+ it('should distinguish entities by owner_id', async () => {
164
+ const owner1Entity = await ensureFinancialEntity(client, {
165
+ name: 'Owner 1',
166
+ type: 'business',
167
+ });
168
+ await client.query(
169
+ `INSERT INTO ${qualifyTable('businesses')} (id) VALUES ($1)`,
170
+ [owner1Entity.id],
171
+ );
172
+
173
+ const owner2Entity = await ensureFinancialEntity(client, {
174
+ name: 'Owner 2',
175
+ type: 'business',
176
+ });
177
+ await client.query(
178
+ `INSERT INTO ${qualifyTable('businesses')} (id) VALUES ($1)`,
179
+ [owner2Entity.id],
180
+ );
181
+
182
+ const entity1 = await ensureFinancialEntity(client, {
183
+ name: 'Same Child',
184
+ type: 'tax_category',
185
+ ownerId: owner1Entity.id,
186
+ });
187
+
188
+ const entity2 = await ensureFinancialEntity(client, {
189
+ name: 'Same Child',
190
+ type: 'tax_category',
191
+ ownerId: owner2Entity.id,
192
+ });
193
+
194
+ expect(entity1.id).not.toBe(entity2.id);
195
+ });
155
196
 
156
- const owner2Entity = await ensureFinancialEntity(client, {
157
- name: 'Owner 2',
158
- type: 'business',
159
- });
160
- await client.query(`INSERT INTO ${qualifyTable('businesses')} (id) VALUES ($1)`, [
161
- owner2Entity.id,
162
- ]);
163
-
164
- const entity1 = await ensureFinancialEntity(client, {
165
- name: 'Same Child',
166
- type: 'tax_category',
167
- ownerId: owner1Entity.id,
168
- });
169
-
170
- const entity2 = await ensureFinancialEntity(client, {
171
- name: 'Same Child',
172
- type: 'tax_category',
173
- ownerId: owner2Entity.id,
174
- });
175
-
176
- expect(entity1.id).not.toBe(entity2.id);
177
- }));
178
-
179
- it('should handle null vs undefined owner_id consistently', async () =>
180
- db.withTransaction(async client => {
181
- const result1 = await ensureFinancialEntity(client, {
182
- name: 'No Owner Entity',
183
- type: 'business',
184
- ownerId: undefined,
185
- });
197
+ it('should handle null vs undefined owner_id consistently', async () => {
198
+ const result1 = await ensureFinancialEntity(client, {
199
+ name: 'No Owner Entity',
200
+ type: 'business',
201
+ ownerId: undefined,
202
+ });
186
203
 
187
- const result2 = await ensureFinancialEntity(client, {
188
- name: 'No Owner Entity',
189
- type: 'business',
190
- });
204
+ const result2 = await ensureFinancialEntity(client, {
205
+ name: 'No Owner Entity',
206
+ type: 'business',
207
+ });
191
208
 
192
- expect(result1.id).toBe(result2.id);
193
- }));
209
+ expect(result1.id).toBe(result2.id);
210
+ });
194
211
 
195
- it('should not leak data between tests', async () =>
196
- db.withTransaction(async client => {
197
- // This test verifies that ROLLBACK works correctly
198
- // Create an entity in this test
199
- await ensureFinancialEntity(client, {
200
- name: 'Transient Entity',
201
- type: 'business',
202
- });
212
+ it('should not leak data between tests', async () => {
213
+ // This test verifies that ROLLBACK works correctly
214
+ // Create an entity in this test
215
+ await ensureFinancialEntity(client, {
216
+ name: 'Transient Entity',
217
+ type: 'business',
218
+ });
203
219
 
204
- // The entity should exist within this transaction
205
- const checkInTransaction = await client.query(
206
- `SELECT COUNT(*) FROM ${qualifyTable('financial_entities')} WHERE name = $1`,
207
- ['Transient Entity'],
208
- );
220
+ // The entity should exist within this transaction
221
+ const checkInTransaction = await client.query(
222
+ `SELECT COUNT(*) FROM ${qualifyTable('financial_entities')} WHERE name = $1`,
223
+ ['Transient Entity'],
224
+ );
209
225
 
210
- expect(parseInt(checkInTransaction.rows[0].count)).toBe(1);
226
+ expect(parseInt(checkInTransaction.rows[0].count)).toBe(1);
211
227
 
212
- // After ROLLBACK in afterEach, this data won't be visible in next test
213
- }));
228
+ // After ROLLBACK in afterEach, this data won't be visible in next test
229
+ });
214
230
 
215
231
  // Validation tests
216
- it('should reject empty entity name', async () =>
217
- db.withTransaction(async client => {
218
- await expect(
219
- ensureFinancialEntity(client, {
220
- name: '',
221
- type: 'business',
222
- }),
223
- ).rejects.toThrow(EntityValidationError);
224
- }));
225
-
226
- it('should reject invalid entity type', async () =>
227
- db.withTransaction(async client => {
228
- await expect(
229
- ensureFinancialEntity(client, {
230
- name: 'Test Entity',
231
- type: 'invalid_type' as any,
232
- }),
233
- ).rejects.toThrow(EntityValidationError);
234
- }));
235
-
236
- it('should reject whitespace-only name', async () =>
237
- db.withTransaction(async client => {
238
- await expect(
239
- ensureFinancialEntity(client, {
240
- name: ' ',
241
- type: 'business',
242
- }),
243
- ).rejects.toThrow(EntityValidationError);
244
- }));
232
+ it('should reject empty entity name', async () => {
233
+ await expect(
234
+ ensureFinancialEntity(client, {
235
+ name: '',
236
+ type: 'business',
237
+ }),
238
+ ).rejects.toThrow(EntityValidationError);
239
+ });
240
+
241
+ it('should reject invalid entity type', async () => {
242
+ await expect(
243
+ ensureFinancialEntity(client, {
244
+ name: 'Test Entity',
245
+ type: 'invalid_type' as any,
246
+ }),
247
+ ).rejects.toThrow(EntityValidationError);
248
+ });
249
+
250
+ it('should reject whitespace-only name', async () => {
251
+ await expect(
252
+ ensureFinancialEntity(client, {
253
+ name: ' ',
254
+ type: 'business',
255
+ }),
256
+ ).rejects.toThrow(EntityValidationError);
257
+ });
245
258
  });