@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,356 +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 { IntegrationBase } = require('../integrations/integration-base');
9
- const { IntegrationEventDispatcher } = require('./integration-event-dispatcher');
10
- const { QueuerUtil } = require('../queues');
11
-
12
- // Mock AWS SQS
13
- jest.mock('aws-sdk', () => {
14
- const mockSQS = {
15
- sendMessage: jest.fn((params, callback) => {
16
- callback(null, { MessageId: 'mock-message-id-123' });
17
- }),
18
- };
19
- return {
20
- SQS: jest.fn(() => mockSQS),
21
- config: { update: jest.fn() },
22
- };
23
- });
24
-
25
- class WebhookTestIntegration extends IntegrationBase {
26
- static Definition = {
27
- name: 'webhook-test',
28
- version: '1.0.0',
29
- modules: {},
30
- webhooks: true,
31
- };
32
-
33
- constructor(params) {
34
- super(params);
35
- this.webhookData = null;
36
- }
37
-
38
- // Override for custom signature verification
39
- async onWebhookReceived({ req, res }) {
40
- const signature = req.headers['x-custom-signature'];
41
-
42
- if (signature && signature !== 'valid-signature-123') {
43
- return res.status(401).json({ error: 'Invalid signature' });
44
- }
45
-
46
- await this.queueWebhook({
47
- integrationId: req.params.integrationId,
48
- body: req.body,
49
- headers: req.headers,
50
- query: req.query,
51
- });
52
-
53
- res.status(200).json({ received: true, verified: !!signature });
54
- }
55
-
56
- // Override for webhook processing
57
- async onWebhook({ data }) {
58
- this.webhookData = data;
59
- return { processed: true, webhookData: data };
60
- }
61
- }
62
-
63
- describe('Webhook Flow Integration Test', () => {
64
- describe('End-to-End Webhook Flow', () => {
65
- beforeEach(() => {
66
- jest.clearAllMocks();
67
- process.env.WEBHOOK_TEST_QUEUE_URL = 'https://sqs.us-east-1.amazonaws.com/123456789/test-queue';
68
- });
69
-
70
- it('should complete full webhook flow: HTTP → Queue → Worker', async () => {
71
- // Step 1: Simulate HTTP webhook received
72
- const integration = new WebhookTestIntegration();
73
- const dispatcher = new IntegrationEventDispatcher(integration);
74
-
75
- const req = {
76
- body: { event: 'item.created', itemId: '12345' },
77
- params: { integrationId: 'int-789' },
78
- headers: { 'content-type': 'application/json' },
79
- query: {},
80
- };
81
- const res = {
82
- status: jest.fn().mockReturnThis(),
83
- json: jest.fn(),
84
- };
85
-
86
- // Execute WEBHOOK_RECEIVED
87
- await dispatcher.dispatchHttp({
88
- event: 'WEBHOOK_RECEIVED',
89
- req,
90
- res,
91
- next: jest.fn(),
92
- });
93
-
94
- // Verify HTTP response
95
- expect(res.status).toHaveBeenCalledWith(200);
96
- expect(res.json).toHaveBeenCalledWith({ received: true, verified: false });
97
-
98
- // Verify message was queued
99
- const AWS = require('aws-sdk');
100
- const mockSQS = new AWS.SQS();
101
- expect(mockSQS.sendMessage).toHaveBeenCalled();
102
-
103
- const queueCall = mockSQS.sendMessage.mock.calls[0][0];
104
- expect(queueCall.QueueUrl).toBe(process.env.WEBHOOK_TEST_QUEUE_URL);
105
-
106
- const queuedMessage = JSON.parse(queueCall.MessageBody);
107
- expect(queuedMessage.event).toBe('ON_WEBHOOK');
108
- expect(queuedMessage.data.integrationId).toBe('int-789');
109
- expect(queuedMessage.data.body).toEqual({ event: 'item.created', itemId: '12345' });
110
-
111
- // Step 2: Simulate worker processing from queue
112
- const workerIntegration = new WebhookTestIntegration();
113
- const workerDispatcher = new IntegrationEventDispatcher(workerIntegration);
114
-
115
- const result = await workerDispatcher.dispatchJob({
116
- event: 'ON_WEBHOOK',
117
- data: queuedMessage.data,
118
- context: {},
119
- });
120
-
121
- // Verify processing result
122
- expect(result.processed).toBe(true);
123
- expect(result.webhookData).toEqual(queuedMessage.data);
124
- expect(workerIntegration.webhookData).not.toBeNull();
125
- });
126
-
127
- it('should support custom signature verification', async () => {
128
- const integration = new WebhookTestIntegration();
129
- const dispatcher = new IntegrationEventDispatcher(integration);
130
-
131
- const reqInvalid = {
132
- body: { event: 'test' },
133
- params: {},
134
- headers: { 'x-custom-signature': 'invalid-sig' },
135
- query: {},
136
- };
137
- const resInvalid = {
138
- status: jest.fn().mockReturnThis(),
139
- json: jest.fn(),
140
- };
141
-
142
- // Test invalid signature
143
- await dispatcher.dispatchHttp({
144
- event: 'WEBHOOK_RECEIVED',
145
- req: reqInvalid,
146
- res: resInvalid,
147
- next: jest.fn(),
148
- });
149
-
150
- expect(resInvalid.status).toHaveBeenCalledWith(401);
151
- expect(resInvalid.json).toHaveBeenCalledWith({ error: 'Invalid signature' });
152
-
153
- // Test valid signature
154
- const reqValid = {
155
- body: { event: 'test' },
156
- params: {},
157
- headers: { 'x-custom-signature': 'valid-signature-123' },
158
- query: {},
159
- };
160
- const resValid = {
161
- status: jest.fn().mockReturnThis(),
162
- json: jest.fn(),
163
- };
164
-
165
- await dispatcher.dispatchHttp({
166
- event: 'WEBHOOK_RECEIVED',
167
- req: reqValid,
168
- res: resValid,
169
- next: jest.fn(),
170
- });
171
-
172
- expect(resValid.status).toHaveBeenCalledWith(200);
173
- expect(resValid.json).toHaveBeenCalledWith({ received: true, verified: true });
174
- });
175
-
176
- it('should handle webhooks without integration ID', async () => {
177
- const integration = new WebhookTestIntegration();
178
- const dispatcher = new IntegrationEventDispatcher(integration);
179
-
180
- const req = {
181
- body: { event: 'system.event' },
182
- params: {}, // No integrationId
183
- headers: {},
184
- query: {},
185
- };
186
- const res = {
187
- status: jest.fn().mockReturnThis(),
188
- json: jest.fn(),
189
- };
190
-
191
- await dispatcher.dispatchHttp({
192
- event: 'WEBHOOK_RECEIVED',
193
- req,
194
- res,
195
- next: jest.fn(),
196
- });
197
-
198
- // Should queue with integrationId: null
199
- const AWS = require('aws-sdk');
200
- const mockSQS = new AWS.SQS();
201
- const queuedMessage = JSON.parse(mockSQS.sendMessage.mock.calls[0][0].MessageBody);
202
-
203
- expect(queuedMessage.data.integrationId).toBeNull();
204
- });
205
-
206
- it('should preserve webhook headers and query params', async () => {
207
- const integration = new WebhookTestIntegration();
208
- const dispatcher = new IntegrationEventDispatcher(integration);
209
-
210
- const req = {
211
- body: { event: 'test' },
212
- params: { integrationId: 'int-456' },
213
- headers: {
214
- 'x-webhook-id': 'webhook-123',
215
- 'x-custom-header': 'value',
216
- },
217
- query: { timestamp: '2025-10-15', version: '2' },
218
- };
219
- const res = {
220
- status: jest.fn().mockReturnThis(),
221
- json: jest.fn(),
222
- };
223
-
224
- await dispatcher.dispatchHttp({
225
- event: 'WEBHOOK_RECEIVED',
226
- req,
227
- res,
228
- next: jest.fn(),
229
- });
230
-
231
- const AWS = require('aws-sdk');
232
- const mockSQS = new AWS.SQS();
233
- const queuedMessage = JSON.parse(mockSQS.sendMessage.mock.calls[0][0].MessageBody);
234
-
235
- expect(queuedMessage.data.headers).toEqual(req.headers);
236
- expect(queuedMessage.data.query).toEqual(req.query);
237
- });
238
- });
239
-
240
- describe('Default Webhook Handlers', () => {
241
- it('should use default WEBHOOK_RECEIVED handler if not overridden', async () => {
242
- // Integration without custom handler
243
- class DefaultWebhookIntegration extends IntegrationBase {
244
- static Definition = {
245
- name: 'default-webhook',
246
- version: '1.0.0',
247
- modules: {},
248
- webhooks: true,
249
- };
250
- }
251
-
252
- process.env.DEFAULT_WEBHOOK_QUEUE_URL = 'https://sqs.us-east-1.amazonaws.com/123456789/default-queue';
253
-
254
- const integration = new DefaultWebhookIntegration();
255
- const dispatcher = new IntegrationEventDispatcher(integration);
256
-
257
- const req = {
258
- body: { test: 'data' },
259
- params: {},
260
- headers: {},
261
- query: {},
262
- };
263
- const res = {
264
- status: jest.fn().mockReturnThis(),
265
- json: jest.fn(),
266
- };
267
-
268
- await dispatcher.dispatchHttp({
269
- event: 'WEBHOOK_RECEIVED',
270
- req,
271
- res,
272
- next: jest.fn(),
273
- });
274
-
275
- // Should use default handler
276
- expect(res.status).toHaveBeenCalledWith(200);
277
- expect(res.json).toHaveBeenCalledWith({ received: true });
278
- });
279
-
280
- it('should use default ON_WEBHOOK handler if not overridden', async () => {
281
- const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
282
-
283
- class DefaultWebhookIntegration extends IntegrationBase {
284
- static Definition = {
285
- name: 'default-webhook-worker',
286
- version: '1.0.0',
287
- modules: {},
288
- webhooks: true,
289
- };
290
- }
291
-
292
- const integration = new DefaultWebhookIntegration();
293
- const dispatcher = new IntegrationEventDispatcher(integration);
294
-
295
- const webhookData = { body: { test: 'data' } };
296
-
297
- await dispatcher.dispatchJob({
298
- event: 'ON_WEBHOOK',
299
- data: webhookData,
300
- context: {},
301
- });
302
-
303
- // Default handler logs the data
304
- expect(consoleSpy).toHaveBeenCalledWith('Webhook received:', webhookData);
305
-
306
- consoleSpy.mockRestore();
307
- });
308
- });
309
-
310
- describe('Error Handling', () => {
311
- it('should handle queueing errors gracefully', async () => {
312
- const AWS = require('aws-sdk');
313
- const mockSQS = new AWS.SQS();
314
- mockSQS.sendMessage.mockImplementation((params, callback) => {
315
- callback(new Error('Queue is full'), null);
316
- });
317
-
318
- process.env.WEBHOOK_TEST_QUEUE_URL = 'https://sqs.us-east-1.amazonaws.com/123456789/test-queue';
319
-
320
- const integration = new WebhookTestIntegration();
321
- const dispatcher = new IntegrationEventDispatcher(integration);
322
-
323
- const req = {
324
- body: { event: 'test' },
325
- params: {},
326
- headers: {},
327
- query: {},
328
- };
329
- const res = {
330
- status: jest.fn().mockReturnThis(),
331
- json: jest.fn(),
332
- };
333
-
334
- // Should throw error when queueing fails
335
- await expect(
336
- dispatcher.dispatchHttp({
337
- event: 'WEBHOOK_RECEIVED',
338
- req,
339
- res,
340
- next: jest.fn(),
341
- })
342
- ).rejects.toThrow('Queue is full');
343
- });
344
-
345
- it('should throw error if queue URL not configured', async () => {
346
- delete process.env.WEBHOOK_TEST_QUEUE_URL;
347
-
348
- const integration = new WebhookTestIntegration();
349
-
350
- await expect(
351
- integration.queueWebhook({ test: 'data' })
352
- ).rejects.toThrow('Queue URL not found for WEBHOOK_TEST_QUEUE_URL');
353
- });
354
- });
355
- });
356
-
@@ -1,50 +0,0 @@
1
- /**
2
- * Adapter Layer Tests - Database Migration Worker
3
- *
4
- * CRITICAL TEST: Verify handler loads without app definition
5
- *
6
- * Business logic is tested in:
7
- * - database/use-cases/run-database-migration-use-case.test.js (22 tests)
8
- *
9
- * Following hexagonal architecture principles:
10
- * - Handlers are thin adapters (SQS → Use Case → Response)
11
- * - Use cases contain all business logic (fully tested)
12
- * - Repositories are infrastructure adapters (tested separately)
13
- */
14
-
15
- process.env.DATABASE_URL = 'postgresql://test:test@localhost:5432/test';
16
- process.env.STAGE = 'test';
17
-
18
- // Mock infrastructure dependencies to prevent app definition loading
19
- jest.mock('../../integrations/repositories/process-repository-postgres', () => ({
20
- ProcessRepositoryPostgres: jest.fn(() => ({
21
- create: jest.fn(),
22
- findById: jest.fn(),
23
- updateState: jest.fn(),
24
- })),
25
- }));
26
-
27
- jest.mock('../../integrations/use-cases/update-process-state', () => ({
28
- UpdateProcessState: jest.fn(() => ({ execute: jest.fn() })),
29
- }));
30
-
31
- jest.mock('../../database/utils/prisma-runner', () => ({
32
- runMigration: jest.fn(),
33
- deployMigration: jest.fn(),
34
- }));
35
-
36
- describe('Database Migration Worker - Adapter Layer', () => {
37
- it('should load without requiring app definition (critical bug fix)', () => {
38
- // Before fix: createProcessRepository() → getDatabaseType() → loads app definition → requires integrations → CRASH
39
- // After fix: ProcessRepositoryPostgres instantiated directly → no app definition → SUCCESS
40
-
41
- expect(() => {
42
- require('./db-migration');
43
- }).not.toThrow();
44
- });
45
-
46
- it('should export handler function', () => {
47
- const { handler } = require('./db-migration');
48
- expect(typeof handler).toBe('function');
49
- });
50
- });
@@ -1,184 +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 { createQueueWorker } = require('../backend-utils');
9
- const { IntegrationBase } = require('../../integrations/integration-base');
10
- const { IntegrationEventDispatcher } = require('../integration-event-dispatcher');
11
-
12
- class TestWebhookIntegration extends IntegrationBase {
13
- static Definition = {
14
- name: 'test-webhook',
15
- version: '1.0.0',
16
- modules: {},
17
- webhooks: true,
18
- };
19
-
20
- constructor(params) {
21
- super(params);
22
- this.onWebhookCalled = false;
23
- this.receivedData = null;
24
- }
25
-
26
- async onWebhook({ data }) {
27
- this.onWebhookCalled = true;
28
- this.receivedData = data;
29
- return { processed: true, data };
30
- }
31
- }
32
-
33
- describe('Webhook Queue Worker', () => {
34
- describe('ON_WEBHOOK event processing', () => {
35
- it('should process ON_WEBHOOK event without integration ID (unhydrated)', async () => {
36
- const QueueWorker = createQueueWorker(TestWebhookIntegration);
37
- const worker = new QueueWorker();
38
-
39
- const params = {
40
- event: 'ON_WEBHOOK',
41
- data: {
42
- body: { webhookEvent: 'created', entityId: '123' },
43
- headers: { 'content-type': 'application/json' },
44
- },
45
- };
46
-
47
- const sqsEvent = {
48
- Records: [{ body: JSON.stringify(params) }],
49
- };
50
-
51
- // Should work with unhydrated instance without throwing
52
- await expect(worker.run(sqsEvent, {})).resolves.not.toThrow();
53
- });
54
-
55
- it('should call ON_WEBHOOK handler with webhook data', async () => {
56
- const QueueWorker = createQueueWorker(TestWebhookIntegration);
57
- const worker = new QueueWorker();
58
-
59
- const webhookData = {
60
- body: { webhookEvent: 'created', entityId: '123' },
61
- headers: { 'content-type': 'application/json' },
62
- query: {},
63
- };
64
-
65
- const params = {
66
- event: 'ON_WEBHOOK',
67
- data: webhookData,
68
- };
69
-
70
- const sqsEvent = {
71
- Records: [{ body: JSON.stringify(params) }],
72
- };
73
-
74
- await worker.run(sqsEvent, {});
75
-
76
- // The handler should have been called
77
- });
78
-
79
- it('should handle multiple webhook messages in batch', async () => {
80
- const QueueWorker = createQueueWorker(TestWebhookIntegration);
81
- const worker = new QueueWorker();
82
-
83
- const message1 = {
84
- event: 'ON_WEBHOOK',
85
- data: { body: { event: '1' } },
86
- };
87
- const message2 = {
88
- event: 'ON_WEBHOOK',
89
- data: { body: { event: '2' } },
90
- };
91
-
92
- const sqsEvent = {
93
- Records: [
94
- { body: JSON.stringify(message1) },
95
- { body: JSON.stringify(message2) },
96
- ],
97
- };
98
-
99
- await worker.run(sqsEvent, {});
100
-
101
- // Should process both messages without error
102
- });
103
- });
104
-
105
- describe('Error Handling', () => {
106
- it('should throw error if ON_WEBHOOK handler fails', async () => {
107
- const FailingIntegration = class extends TestWebhookIntegration {
108
- async onWebhook({ data }) {
109
- throw new Error('Processing failed');
110
- }
111
- };
112
-
113
- const FailingWorker = createQueueWorker(FailingIntegration);
114
- const failingWorker = new FailingWorker();
115
-
116
- const params = {
117
- event: 'ON_WEBHOOK',
118
- data: { body: { invalid: 'data' } },
119
- };
120
-
121
- const sqsEvent = {
122
- Records: [{ body: JSON.stringify(params) }],
123
- };
124
-
125
- await expect(failingWorker.run(sqsEvent, {})).rejects.toThrow('Processing failed');
126
- });
127
-
128
- it('should log errors with integration context', async () => {
129
- const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
130
-
131
- const FailingIntegration = class extends TestWebhookIntegration {
132
- async onWebhook({ data }) {
133
- throw new Error('Test error');
134
- }
135
- };
136
-
137
- const FailingWorker = createQueueWorker(FailingIntegration);
138
- const failingWorker = new FailingWorker();
139
-
140
- const params = {
141
- event: 'ON_WEBHOOK',
142
- data: { body: {} },
143
- };
144
-
145
- const sqsEvent = {
146
- Records: [{ body: JSON.stringify(params) }],
147
- };
148
-
149
- await expect(failingWorker.run(sqsEvent, {})).rejects.toThrow();
150
- expect(consoleSpy).toHaveBeenCalledWith(
151
- expect.stringContaining('Error in ON_WEBHOOK for test-webhook'),
152
- expect.any(Error)
153
- );
154
-
155
- consoleSpy.mockRestore();
156
- });
157
- });
158
-
159
- describe('Integration Hydration for webhooks with integrationId', () => {
160
- it('should attempt to load integration when integrationId present', async () => {
161
- // This test verifies the logic path - full integration test
162
- // will verify actual DB loading with mocked repositories
163
- const QueueWorker = createQueueWorker(TestWebhookIntegration);
164
- const worker = new QueueWorker();
165
-
166
- const params = {
167
- event: 'ON_WEBHOOK',
168
- data: {
169
- integrationId: 'integration-456',
170
- body: { webhookEvent: 'updated' },
171
- },
172
- };
173
-
174
- const sqsEvent = {
175
- Records: [{ body: JSON.stringify(params) }],
176
- };
177
-
178
- // This will fail trying to load the integration from DB
179
- // but it proves the code path is attempted
180
- await expect(worker.run(sqsEvent, {})).rejects.toThrow();
181
- });
182
- });
183
- });
184
-