@friggframework/core 2.0.0--canary.461.61382d8.0 → 2.0.0--canary.461.3d6d8ad.0

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 (120) hide show
  1. package/database/use-cases/check-migration-status-use-case.js +81 -0
  2. package/generated/prisma-mongodb/client.d.ts +1 -0
  3. package/generated/prisma-mongodb/client.js +4 -0
  4. package/generated/prisma-mongodb/default.d.ts +1 -0
  5. package/generated/prisma-mongodb/default.js +4 -0
  6. package/generated/prisma-mongodb/edge.d.ts +1 -0
  7. package/generated/prisma-mongodb/edge.js +336 -0
  8. package/generated/prisma-mongodb/index-browser.js +318 -0
  9. package/generated/prisma-mongodb/index.d.ts +22993 -0
  10. package/generated/prisma-mongodb/index.js +361 -0
  11. package/generated/prisma-mongodb/package.json +183 -0
  12. package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
  13. package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
  14. package/generated/prisma-mongodb/runtime/binary.d.ts +1 -0
  15. package/generated/prisma-mongodb/runtime/binary.js +289 -0
  16. package/generated/prisma-mongodb/runtime/edge-esm.js +34 -0
  17. package/generated/prisma-mongodb/runtime/edge.js +34 -0
  18. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  19. package/generated/prisma-mongodb/runtime/index-browser.js +16 -0
  20. package/generated/prisma-mongodb/runtime/library.d.ts +3977 -0
  21. package/generated/prisma-mongodb/runtime/react-native.js +83 -0
  22. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +84 -0
  23. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +36 -0
  24. package/generated/prisma-mongodb/schema.prisma +364 -0
  25. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +4 -0
  26. package/generated/prisma-mongodb/wasm-worker-loader.mjs +4 -0
  27. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  28. package/generated/prisma-mongodb/wasm.js +343 -0
  29. package/generated/prisma-postgresql/client.d.ts +1 -0
  30. package/generated/prisma-postgresql/client.js +4 -0
  31. package/generated/prisma-postgresql/default.d.ts +1 -0
  32. package/generated/prisma-postgresql/default.js +4 -0
  33. package/generated/prisma-postgresql/edge.d.ts +1 -0
  34. package/generated/prisma-postgresql/edge.js +358 -0
  35. package/generated/prisma-postgresql/index-browser.js +340 -0
  36. package/generated/prisma-postgresql/index.d.ts +25171 -0
  37. package/generated/prisma-postgresql/index.js +383 -0
  38. package/generated/prisma-postgresql/package.json +183 -0
  39. package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
  40. package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -0
  41. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  42. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  43. package/generated/prisma-postgresql/runtime/binary.d.ts +1 -0
  44. package/generated/prisma-postgresql/runtime/binary.js +289 -0
  45. package/generated/prisma-postgresql/runtime/edge-esm.js +34 -0
  46. package/generated/prisma-postgresql/runtime/edge.js +34 -0
  47. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  48. package/generated/prisma-postgresql/runtime/index-browser.js +16 -0
  49. package/generated/prisma-postgresql/runtime/library.d.ts +3977 -0
  50. package/generated/prisma-postgresql/runtime/react-native.js +83 -0
  51. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +84 -0
  52. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +36 -0
  53. package/generated/prisma-postgresql/schema.prisma +347 -0
  54. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +4 -0
  55. package/generated/prisma-postgresql/wasm-worker-loader.mjs +4 -0
  56. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  57. package/generated/prisma-postgresql/wasm.js +365 -0
  58. package/handlers/routers/db-migration.js +52 -0
  59. package/package.json +5 -5
  60. package/application/commands/integration-commands.test.js +0 -123
  61. package/core/Worker.test.js +0 -159
  62. package/database/encryption/encryption-integration.test.js +0 -553
  63. package/database/encryption/encryption-schema-registry.test.js +0 -392
  64. package/database/encryption/field-encryption-service.test.js +0 -525
  65. package/database/encryption/mongo-decryption-fix-verification.test.js +0 -348
  66. package/database/encryption/postgres-decryption-fix-verification.test.js +0 -371
  67. package/database/encryption/postgres-relation-decryption.test.js +0 -245
  68. package/database/encryption/prisma-encryption-extension.test.js +0 -439
  69. package/database/repositories/migration-status-repository-s3.test.js +0 -158
  70. package/database/use-cases/check-encryption-health-use-case.test.js +0 -192
  71. package/database/use-cases/get-migration-status-use-case.test.js +0 -171
  72. package/database/use-cases/run-database-migration-use-case.test.js +0 -310
  73. package/database/use-cases/trigger-database-migration-use-case.test.js +0 -250
  74. package/database/utils/prisma-runner.test.js +0 -486
  75. package/encrypt/Cryptor.test.js +0 -144
  76. package/errors/base-error.test.js +0 -32
  77. package/errors/fetch-error.test.js +0 -79
  78. package/errors/halt-error.test.js +0 -11
  79. package/errors/validation-errors.test.js +0 -120
  80. package/handlers/auth-flow.integration.test.js +0 -147
  81. package/handlers/integration-event-dispatcher.test.js +0 -209
  82. package/handlers/routers/db-migration.test.js +0 -51
  83. package/handlers/routers/health.test.js +0 -210
  84. package/handlers/routers/integration-webhook-routers.test.js +0 -126
  85. package/handlers/use-cases/check-integrations-health-use-case.test.js +0 -125
  86. package/handlers/webhook-flow.integration.test.js +0 -356
  87. package/handlers/workers/db-migration.test.js +0 -50
  88. package/handlers/workers/integration-defined-workers.test.js +0 -184
  89. package/integrations/tests/integration-router-multi-auth.test.js +0 -369
  90. package/integrations/tests/use-cases/create-integration.test.js +0 -131
  91. package/integrations/tests/use-cases/delete-integration-for-user.test.js +0 -150
  92. package/integrations/tests/use-cases/find-integration-context-by-external-entity-id.test.js +0 -92
  93. package/integrations/tests/use-cases/get-integration-for-user.test.js +0 -150
  94. package/integrations/tests/use-cases/get-integration-instance.test.js +0 -176
  95. package/integrations/tests/use-cases/get-integrations-for-user.test.js +0 -176
  96. package/integrations/tests/use-cases/get-possible-integrations.test.js +0 -188
  97. package/integrations/tests/use-cases/update-integration-messages.test.js +0 -142
  98. package/integrations/tests/use-cases/update-integration-status.test.js +0 -103
  99. package/integrations/tests/use-cases/update-integration.test.js +0 -141
  100. package/integrations/use-cases/create-process.test.js +0 -178
  101. package/integrations/use-cases/get-process.test.js +0 -190
  102. package/integrations/use-cases/load-integration-context-full.test.js +0 -329
  103. package/integrations/use-cases/load-integration-context.test.js +0 -114
  104. package/integrations/use-cases/update-process-metrics.test.js +0 -308
  105. package/integrations/use-cases/update-process-state.test.js +0 -256
  106. package/lambda/TimeoutCatcher.test.js +0 -68
  107. package/logs/logger.test.js +0 -76
  108. package/modules/module-hydration.test.js +0 -205
  109. package/modules/requester/requester.test.js +0 -28
  110. package/queues/queuer-util.test.js +0 -132
  111. package/user/tests/use-cases/create-individual-user.test.js +0 -24
  112. package/user/tests/use-cases/create-organization-user.test.js +0 -28
  113. package/user/tests/use-cases/create-token-for-user-id.test.js +0 -19
  114. package/user/tests/use-cases/get-user-from-adopter-jwt.test.js +0 -113
  115. package/user/tests/use-cases/get-user-from-bearer-token.test.js +0 -64
  116. package/user/tests/use-cases/get-user-from-x-frigg-headers.test.js +0 -346
  117. package/user/tests/use-cases/login-user.test.js +0 -220
  118. package/user/tests/user-password-encryption-isolation.test.js +0 -237
  119. package/user/tests/user-password-hashing.test.js +0 -235
  120. package/websocket/repositories/websocket-connection-repository.test.js +0 -227
@@ -1,369 +0,0 @@
1
- const { AuthenticateUser } = require('../../user/use-cases/authenticate-user');
2
- const { GetUserFromBearerToken } = require('../../user/use-cases/get-user-from-bearer-token');
3
- const { GetUserFromXFriggHeaders } = require('../../user/use-cases/get-user-from-x-frigg-headers');
4
- const { GetUserFromAdopterJwt } = require('../../user/use-cases/get-user-from-adopter-jwt');
5
- const { User } = require('../../user/user');
6
- const Boom = require('@hapi/boom');
7
-
8
- describe('AuthenticateUser - Multi-Mode Authentication', () => {
9
- let authenticateUser;
10
- let mockGetUserFromBearerToken;
11
- let mockGetUserFromXFriggHeaders;
12
- let mockGetUserFromAdopterJwt;
13
- let mockUserConfig;
14
- let mockUser;
15
-
16
- beforeEach(() => {
17
- mockUser = new User(
18
- { id: 'user-123', username: 'testuser' },
19
- null,
20
- false,
21
- 'individual',
22
- true,
23
- false
24
- );
25
-
26
- mockGetUserFromBearerToken = {
27
- execute: jest.fn().mockResolvedValue(mockUser),
28
- };
29
-
30
- mockGetUserFromXFriggHeaders = {
31
- execute: jest.fn().mockResolvedValue(mockUser),
32
- };
33
-
34
- mockGetUserFromAdopterJwt = {
35
- execute: jest.fn().mockResolvedValue(mockUser),
36
- };
37
-
38
- mockUserConfig = {
39
- authModes: {
40
- friggToken: true,
41
- xFriggHeaders: true,
42
- adopterJwt: false,
43
- },
44
- };
45
-
46
- authenticateUser = new AuthenticateUser({
47
- getUserFromBearerToken: mockGetUserFromBearerToken,
48
- getUserFromXFriggHeaders: mockGetUserFromXFriggHeaders,
49
- getUserFromAdopterJwt: mockGetUserFromAdopterJwt,
50
- userConfig: mockUserConfig,
51
- });
52
- });
53
-
54
- describe('Priority 1: X-Frigg Headers (Backend-to-Backend)', () => {
55
- it('should authenticate with x-frigg-appUserId header', async () => {
56
- const mockReq = {
57
- headers: {
58
- 'x-frigg-appuserid': 'app-user-123',
59
- },
60
- };
61
-
62
- const result = await authenticateUser.execute(mockReq);
63
-
64
- expect(result).toBe(mockUser);
65
- expect(mockGetUserFromXFriggHeaders.execute).toHaveBeenCalledWith(
66
- 'app-user-123',
67
- undefined
68
- );
69
- expect(mockGetUserFromBearerToken.execute).not.toHaveBeenCalled();
70
- });
71
-
72
- it('should authenticate with x-frigg-appOrgId header', async () => {
73
- const mockReq = {
74
- headers: {
75
- 'x-frigg-apporgid': 'app-org-456',
76
- },
77
- };
78
-
79
- const result = await authenticateUser.execute(mockReq);
80
-
81
- expect(result).toBe(mockUser);
82
- expect(mockGetUserFromXFriggHeaders.execute).toHaveBeenCalledWith(
83
- undefined,
84
- 'app-org-456'
85
- );
86
- expect(mockGetUserFromBearerToken.execute).not.toHaveBeenCalled();
87
- });
88
-
89
- it('should authenticate with both x-frigg headers when they match', async () => {
90
- const mockReq = {
91
- headers: {
92
- 'x-frigg-appuserid': 'app-user-123',
93
- 'x-frigg-apporgid': 'app-org-456',
94
- },
95
- };
96
-
97
- const result = await authenticateUser.execute(mockReq);
98
-
99
- expect(result).toBe(mockUser);
100
- expect(mockGetUserFromXFriggHeaders.execute).toHaveBeenCalledWith(
101
- 'app-user-123',
102
- 'app-org-456'
103
- );
104
- });
105
-
106
- it('should reject conflicting x-frigg headers (delegated to use case)', async () => {
107
- const mockReq = {
108
- headers: {
109
- 'x-frigg-appuserid': 'app-user-123',
110
- 'x-frigg-apporgid': 'app-org-999',
111
- },
112
- };
113
-
114
- const conflictError = Boom.badRequest('User ID mismatch');
115
- mockGetUserFromXFriggHeaders.execute.mockRejectedValue(conflictError);
116
-
117
- await expect(authenticateUser.execute(mockReq)).rejects.toThrow(
118
- conflictError
119
- );
120
- });
121
-
122
- it('should skip x-frigg headers when authModes.xFriggHeaders is false', async () => {
123
- mockUserConfig.authModes.xFriggHeaders = false;
124
-
125
- const mockReq = {
126
- headers: {
127
- 'x-frigg-appuserid': 'app-user-123',
128
- authorization: 'Bearer frigg-token-xyz',
129
- },
130
- };
131
-
132
- await authenticateUser.execute(mockReq);
133
-
134
- expect(mockGetUserFromXFriggHeaders.execute).not.toHaveBeenCalled();
135
- expect(mockGetUserFromBearerToken.execute).toHaveBeenCalledWith(
136
- 'Bearer frigg-token-xyz'
137
- );
138
- });
139
- });
140
-
141
- describe('Priority 2: Adopter JWT', () => {
142
- beforeEach(() => {
143
- mockUserConfig.authModes.adopterJwt = true;
144
- });
145
-
146
- it('should try JWT when enabled and Bearer token is 3-part format', async () => {
147
- const mockReq = {
148
- headers: {
149
- authorization: 'Bearer eyJhbGci.eyJzdWIi.signature',
150
- },
151
- };
152
-
153
- await authenticateUser.execute(mockReq);
154
-
155
- expect(mockGetUserFromAdopterJwt.execute).toHaveBeenCalledWith(
156
- 'eyJhbGci.eyJzdWIi.signature'
157
- );
158
- expect(mockGetUserFromBearerToken.execute).not.toHaveBeenCalled();
159
- });
160
-
161
- it('should fall back to Frigg token when Bearer token is not JWT format', async () => {
162
- const mockReq = {
163
- headers: {
164
- authorization: 'Bearer simple-token',
165
- },
166
- };
167
-
168
- await authenticateUser.execute(mockReq);
169
-
170
- expect(mockGetUserFromAdopterJwt.execute).not.toHaveBeenCalled();
171
- expect(mockGetUserFromBearerToken.execute).toHaveBeenCalledWith(
172
- 'Bearer simple-token'
173
- );
174
- });
175
-
176
- it('should not try JWT when authModes.adopterJwt is false', async () => {
177
- mockUserConfig.authModes.adopterJwt = false;
178
-
179
- const mockReq = {
180
- headers: {
181
- authorization: 'Bearer eyJhbGci.eyJzdWIi.signature',
182
- },
183
- };
184
-
185
- await authenticateUser.execute(mockReq);
186
-
187
- expect(mockGetUserFromAdopterJwt.execute).not.toHaveBeenCalled();
188
- expect(mockGetUserFromBearerToken.execute).toHaveBeenCalledWith(
189
- 'Bearer eyJhbGci.eyJzdWIi.signature'
190
- );
191
- });
192
- });
193
-
194
- describe('Priority 3: Frigg Native Token (Fallback)', () => {
195
- it('should fall back to Frigg token when no x-frigg headers', async () => {
196
- const mockReq = {
197
- headers: {
198
- authorization: 'Bearer frigg-token-123',
199
- },
200
- };
201
-
202
- const result = await authenticateUser.execute(mockReq);
203
-
204
- expect(result).toBe(mockUser);
205
- expect(mockGetUserFromBearerToken.execute).toHaveBeenCalledWith(
206
- 'Bearer frigg-token-123'
207
- );
208
- expect(mockGetUserFromXFriggHeaders.execute).not.toHaveBeenCalled();
209
- });
210
-
211
- it('should skip Frigg token when authModes.friggToken is false', async () => {
212
- mockUserConfig.authModes.friggToken = false;
213
-
214
- const mockReq = {
215
- headers: {
216
- authorization: 'Bearer frigg-token-123',
217
- },
218
- };
219
-
220
- await expect(authenticateUser.execute(mockReq)).rejects.toThrow(
221
- Boom.unauthorized().message
222
- );
223
-
224
- expect(mockGetUserFromBearerToken.execute).not.toHaveBeenCalled();
225
- });
226
- });
227
-
228
- describe('Priority Ordering', () => {
229
- it('should prioritize x-frigg headers over bearer token', async () => {
230
- const mockReq = {
231
- headers: {
232
- 'x-frigg-appuserid': 'app-user-123',
233
- authorization: 'Bearer frigg-token-xyz',
234
- },
235
- };
236
-
237
- await authenticateUser.execute(mockReq);
238
-
239
- expect(mockGetUserFromXFriggHeaders.execute).toHaveBeenCalledWith(
240
- 'app-user-123',
241
- undefined
242
- );
243
- expect(mockGetUserFromBearerToken.execute).not.toHaveBeenCalled();
244
- });
245
-
246
- it('should try JWT before Frigg token when JWT enabled', async () => {
247
- mockUserConfig.authModes.adopterJwt = true;
248
-
249
- const mockReq = {
250
- headers: {
251
- authorization: 'Bearer part1.part2.part3',
252
- },
253
- };
254
-
255
- await authenticateUser.execute(mockReq);
256
-
257
- expect(mockGetUserFromAdopterJwt.execute).toHaveBeenCalledWith(
258
- 'part1.part2.part3'
259
- );
260
- expect(mockGetUserFromBearerToken.execute).not.toHaveBeenCalled();
261
- });
262
- });
263
-
264
- describe('Auth Mode Configuration', () => {
265
- it('should use default friggToken mode when authModes not configured', () => {
266
- const authWithDefaults = new AuthenticateUser({
267
- getUserFromBearerToken: mockGetUserFromBearerToken,
268
- getUserFromXFriggHeaders: mockGetUserFromXFriggHeaders,
269
- getUserFromAdopterJwt: mockGetUserFromAdopterJwt,
270
- userConfig: {}, // No authModes
271
- });
272
-
273
- const mockReq = {
274
- headers: {
275
- authorization: 'Bearer token',
276
- },
277
- };
278
-
279
- authWithDefaults.execute(mockReq);
280
-
281
- expect(mockGetUserFromBearerToken.execute).toHaveBeenCalled();
282
- });
283
-
284
- it('should throw unauthorized when no valid authentication provided', async () => {
285
- const mockReq = {
286
- headers: {},
287
- };
288
-
289
- await expect(authenticateUser.execute(mockReq)).rejects.toThrow(
290
- Boom.unauthorized().message
291
- );
292
-
293
- await expect(authenticateUser.execute(mockReq)).rejects.toThrow(
294
- 'No valid authentication provided'
295
- );
296
- });
297
-
298
- it('should throw unauthorized when all auth modes disabled', async () => {
299
- mockUserConfig.authModes = {
300
- friggToken: false,
301
- xFriggHeaders: false,
302
- adopterJwt: false,
303
- };
304
-
305
- const mockReq = {
306
- headers: {
307
- authorization: 'Bearer token',
308
- },
309
- };
310
-
311
- await expect(authenticateUser.execute(mockReq)).rejects.toThrow(
312
- 'No valid authentication provided'
313
- );
314
- });
315
- });
316
-
317
- describe('Error Handling', () => {
318
- it('should propagate authentication errors from x-frigg headers', async () => {
319
- const mockReq = {
320
- headers: {
321
- 'x-frigg-appuserid': 'invalid-user',
322
- },
323
- };
324
-
325
- const customError = Boom.badRequest('Invalid user ID');
326
- mockGetUserFromXFriggHeaders.execute.mockRejectedValue(customError);
327
-
328
- await expect(authenticateUser.execute(mockReq)).rejects.toThrow(
329
- customError
330
- );
331
- });
332
-
333
- it('should propagate authentication errors from bearer token', async () => {
334
- const mockReq = {
335
- headers: {
336
- authorization: 'Bearer invalid-token',
337
- },
338
- };
339
-
340
- const customError = Boom.unauthorized('Invalid token');
341
- mockGetUserFromBearerToken.execute.mockRejectedValue(customError);
342
-
343
- await expect(authenticateUser.execute(mockReq)).rejects.toThrow(
344
- customError
345
- );
346
- });
347
-
348
- it('should propagate not implemented error from JWT', async () => {
349
- mockUserConfig.authModes.adopterJwt = true;
350
-
351
- const mockReq = {
352
- headers: {
353
- authorization: 'Bearer part1.part2.part3',
354
- },
355
- };
356
-
357
- const notImplementedError = Boom.notImplemented('JWT not implemented');
358
- mockGetUserFromAdopterJwt.execute.mockRejectedValue(
359
- notImplementedError
360
- );
361
-
362
- await expect(authenticateUser.execute(mockReq)).rejects.toThrow(
363
- notImplementedError
364
- );
365
- });
366
- });
367
- });
368
-
369
-
@@ -1,131 +0,0 @@
1
- jest.mock('../../../database/config', () => ({
2
- DB_TYPE: 'mongodb',
3
- getDatabaseType: jest.fn(() => 'mongodb'),
4
- PRISMA_LOG_LEVEL: 'error,warn',
5
- PRISMA_QUERY_LOGGING: false,
6
- }));
7
-
8
- const { CreateIntegration } = require('../../use-cases/create-integration');
9
- const { TestIntegrationRepository } = require('../doubles/test-integration-repository');
10
- const { TestModuleFactory } = require('../../../modules/tests/doubles/test-module-factory');
11
- const { DummyIntegration } = require('../doubles/dummy-integration-class');
12
-
13
- describe('CreateIntegration Use-Case', () => {
14
- let integrationRepository;
15
- let moduleFactory;
16
- let useCase;
17
-
18
- beforeEach(() => {
19
- integrationRepository = new TestIntegrationRepository();
20
- moduleFactory = new TestModuleFactory();
21
- useCase = new CreateIntegration({
22
- integrationRepository,
23
- integrationClasses: [DummyIntegration],
24
- moduleFactory,
25
- });
26
- });
27
-
28
- describe('happy path', () => {
29
- it('creates an integration and returns DTO', async () => {
30
- const entities = ['entity-1'];
31
- const userId = 'user-1';
32
- const config = { type: 'dummy', foo: 'bar' };
33
-
34
- const dto = await useCase.execute(entities, userId, config);
35
-
36
- expect(dto.id).toBeDefined();
37
- expect(dto.config).toEqual(config);
38
- expect(dto.userId).toBe(userId);
39
- expect(dto.entities).toEqual(entities);
40
- expect(dto.status).toBe('NEW');
41
- });
42
-
43
- it('triggers ON_CREATE event with correct payload', async () => {
44
- const entities = ['entity-1'];
45
- const userId = 'user-1';
46
- const config = { type: 'dummy', foo: 'bar' };
47
-
48
- const dto = await useCase.execute(entities, userId, config);
49
-
50
- const record = await integrationRepository.findIntegrationById(dto.id);
51
- expect(record).toBeTruthy();
52
-
53
- const history = integrationRepository.getOperationHistory();
54
- const createOperation = history.find(op => op.operation === 'create');
55
- expect(createOperation).toEqual({
56
- operation: 'create',
57
- id: dto.id,
58
- userId,
59
- config
60
- });
61
- });
62
-
63
- it('loads modules for each entity', async () => {
64
- const entities = ['entity-1', 'entity-2'];
65
- const userId = 'user-1';
66
- const config = { type: 'dummy' };
67
-
68
- const dto = await useCase.execute(entities, userId, config);
69
-
70
- expect(dto.entities).toEqual(entities);
71
- });
72
- });
73
-
74
- describe('error cases', () => {
75
- it('throws error when integration class is not found', async () => {
76
- const entities = ['entity-1'];
77
- const userId = 'user-1';
78
- const config = { type: 'unknown-type' };
79
-
80
- await expect(useCase.execute(entities, userId, config))
81
- .rejects
82
- .toThrow('No integration class found for type: unknown-type');
83
- });
84
-
85
- it('throws error when no integration classes provided', async () => {
86
- const useCaseWithoutClasses = new CreateIntegration({
87
- integrationRepository,
88
- integrationClasses: [],
89
- moduleFactory,
90
- });
91
-
92
- const entities = ['entity-1'];
93
- const userId = 'user-1';
94
- const config = { type: 'dummy' };
95
-
96
- await expect(useCaseWithoutClasses.execute(entities, userId, config))
97
- .rejects
98
- .toThrow('No integration class found for type: dummy');
99
- });
100
- });
101
-
102
- describe('edge cases', () => {
103
- it('handles empty entities array', async () => {
104
- const entities = [];
105
- const userId = 'user-1';
106
- const config = { type: 'dummy' };
107
-
108
- const dto = await useCase.execute(entities, userId, config);
109
-
110
- expect(dto.entities).toEqual([]);
111
- expect(dto.id).toBeDefined();
112
- });
113
-
114
- it('handles complex config objects', async () => {
115
- const entities = ['entity-1'];
116
- const userId = 'user-1';
117
- const config = {
118
- type: 'dummy',
119
- nested: {
120
- value: 123,
121
- array: [1, 2, 3],
122
- bool: true
123
- }
124
- };
125
-
126
- const dto = await useCase.execute(entities, userId, config);
127
-
128
- expect(dto.config).toEqual(config);
129
- });
130
- });
131
- });
@@ -1,150 +0,0 @@
1
- jest.mock('../../../database/config', () => ({
2
- DB_TYPE: 'mongodb',
3
- getDatabaseType: jest.fn(() => 'mongodb'),
4
- PRISMA_LOG_LEVEL: 'error,warn',
5
- PRISMA_QUERY_LOGGING: false,
6
- }));
7
-
8
- const { DeleteIntegrationForUser } = require('../../use-cases/delete-integration-for-user');
9
- const { TestIntegrationRepository } = require('../doubles/test-integration-repository');
10
- const { DummyIntegration } = require('../doubles/dummy-integration-class');
11
-
12
- describe('DeleteIntegrationForUser Use-Case', () => {
13
- let integrationRepository;
14
- let useCase;
15
-
16
- beforeEach(() => {
17
- integrationRepository = new TestIntegrationRepository();
18
- useCase = new DeleteIntegrationForUser({
19
- integrationRepository,
20
- integrationClasses: [DummyIntegration],
21
- });
22
- });
23
-
24
- describe('happy path', () => {
25
- it('deletes integration successfully', async () => {
26
- const record = await integrationRepository.createIntegration(['e1'], 'user-1', { type: 'dummy' });
27
-
28
- await useCase.execute(record.id, 'user-1');
29
-
30
- const found = await integrationRepository.findIntegrationById(record.id);
31
- expect(found).toBeNull();
32
- });
33
-
34
- it('tracks delete operation', async () => {
35
- const record = await integrationRepository.createIntegration(['e1'], 'user-1', { type: 'dummy' });
36
- integrationRepository.clearHistory();
37
-
38
- await useCase.execute(record.id, 'user-1');
39
-
40
- const history = integrationRepository.getOperationHistory();
41
- const deleteOperation = history.find(op => op.operation === 'delete');
42
- expect(deleteOperation).toEqual({
43
- operation: 'delete',
44
- id: record.id,
45
- existed: true,
46
- success: true
47
- });
48
- });
49
-
50
- it('deletes integration with multiple entities', async () => {
51
- const record = await integrationRepository.createIntegration(['e1', 'e2', 'e3'], 'user-1', { type: 'dummy' });
52
-
53
- await useCase.execute(record.id, 'user-1');
54
-
55
- const found = await integrationRepository.findIntegrationById(record.id);
56
- expect(found).toBeNull();
57
- });
58
- });
59
-
60
- describe('error cases', () => {
61
- it('throws error when integration not found', async () => {
62
- const nonExistentId = 'non-existent-id';
63
-
64
- await expect(useCase.execute(nonExistentId, 'user-1'))
65
- .rejects
66
- .toThrow(`Integration with id of ${nonExistentId} does not exist`);
67
- });
68
-
69
- it('throws error when user does not own integration', async () => {
70
- const record = await integrationRepository.createIntegration(['e1'], 'user-1', { type: 'dummy' });
71
-
72
- await expect(useCase.execute(record.id, 'different-user'))
73
- .rejects
74
- .toThrow(`Integration ${record.id} does not belong to User different-user`);
75
- });
76
-
77
- it('throws error when integration class not found', async () => {
78
- const useCaseWithoutClasses = new DeleteIntegrationForUser({
79
- integrationRepository,
80
- integrationClasses: [],
81
- });
82
-
83
- const record = await integrationRepository.createIntegration(['e1'], 'user-1', { type: 'dummy' });
84
-
85
- await expect(useCaseWithoutClasses.execute(record.id, 'user-1'))
86
- .rejects
87
- .toThrow();
88
- });
89
-
90
- it('tracks failed delete operation for non-existent integration', async () => {
91
- const nonExistentId = 'non-existent-id';
92
- integrationRepository.clearHistory();
93
-
94
- try {
95
- await useCase.execute(nonExistentId, 'user-1');
96
- } catch (error) {
97
- const history = integrationRepository.getOperationHistory();
98
- const findOperation = history.find(op => op.operation === 'findById');
99
- expect(findOperation).toEqual({
100
- operation: 'findById',
101
- id: nonExistentId,
102
- found: false
103
- });
104
- }
105
- });
106
- });
107
-
108
- describe('edge cases', () => {
109
- it('handles deletion of already deleted integration', async () => {
110
- const record = await integrationRepository.createIntegration(['e1'], 'user-1', { type: 'dummy' });
111
-
112
- await useCase.execute(record.id, 'user-1');
113
-
114
- await expect(useCase.execute(record.id, 'user-1'))
115
- .rejects
116
- .toThrow(`Integration with id of ${record.id} does not exist`);
117
- });
118
-
119
- it('handles integration with complex config during deletion', async () => {
120
- const complexConfig = {
121
- type: 'dummy',
122
- settings: { nested: { deep: 'value' } },
123
- credentials: { encrypted: true }
124
- };
125
-
126
- const record = await integrationRepository.createIntegration(['e1'], 'user-1', complexConfig);
127
-
128
- await useCase.execute(record.id, 'user-1');
129
-
130
- const found = await integrationRepository.findIntegrationById(record.id);
131
- expect(found).toBeNull();
132
- });
133
-
134
- it('handles null userId gracefully', async () => {
135
- const record = await integrationRepository.createIntegration(['e1'], 'user-1', { type: 'dummy' });
136
-
137
- await expect(useCase.execute(record.id, null))
138
- .rejects
139
- .toThrow(`Integration ${record.id} does not belong to User null`);
140
- });
141
-
142
- it('handles undefined userId gracefully', async () => {
143
- const record = await integrationRepository.createIntegration(['e1'], 'user-1', { type: 'dummy' });
144
-
145
- await expect(useCase.execute(record.id, undefined))
146
- .rejects
147
- .toThrow(`Integration ${record.id} does not belong to User undefined`);
148
- });
149
- });
150
- });