@friggframework/core 2.0.0-next.44 → 2.0.0-next.46

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 (166) hide show
  1. package/README.md +28 -0
  2. package/application/commands/integration-commands.js +19 -0
  3. package/core/Worker.js +8 -21
  4. package/credential/repositories/credential-repository-mongo.js +14 -8
  5. package/credential/repositories/credential-repository-postgres.js +14 -8
  6. package/credential/repositories/credential-repository.js +3 -8
  7. package/database/MONGODB_TRANSACTION_FIX.md +198 -0
  8. package/database/adapters/lambda-invoker.js +97 -0
  9. package/database/config.js +11 -2
  10. package/database/models/WebsocketConnection.js +11 -10
  11. package/database/prisma.js +63 -3
  12. package/database/repositories/health-check-repository-mongodb.js +3 -0
  13. package/database/repositories/migration-status-repository-s3.js +137 -0
  14. package/database/use-cases/check-database-state-use-case.js +81 -0
  15. package/database/use-cases/check-encryption-health-use-case.js +3 -2
  16. package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
  17. package/database/use-cases/get-migration-status-use-case.js +93 -0
  18. package/database/use-cases/run-database-migration-use-case.js +137 -0
  19. package/database/use-cases/trigger-database-migration-use-case.js +157 -0
  20. package/database/utils/mongodb-collection-utils.js +91 -0
  21. package/database/utils/mongodb-schema-init.js +106 -0
  22. package/database/utils/prisma-runner.js +400 -0
  23. package/database/utils/prisma-schema-parser.js +182 -0
  24. package/encrypt/Cryptor.js +14 -16
  25. package/generated/prisma-mongodb/client.d.ts +1 -0
  26. package/generated/prisma-mongodb/client.js +4 -0
  27. package/generated/prisma-mongodb/default.d.ts +1 -0
  28. package/generated/prisma-mongodb/default.js +4 -0
  29. package/generated/prisma-mongodb/edge.d.ts +1 -0
  30. package/generated/prisma-mongodb/edge.js +334 -0
  31. package/generated/prisma-mongodb/index-browser.js +316 -0
  32. package/generated/prisma-mongodb/index.d.ts +22897 -0
  33. package/generated/prisma-mongodb/index.js +359 -0
  34. package/generated/prisma-mongodb/package.json +183 -0
  35. package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
  36. package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
  37. package/generated/prisma-mongodb/runtime/binary.d.ts +1 -0
  38. package/generated/prisma-mongodb/runtime/binary.js +289 -0
  39. package/generated/prisma-mongodb/runtime/edge-esm.js +34 -0
  40. package/generated/prisma-mongodb/runtime/edge.js +34 -0
  41. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  42. package/generated/prisma-mongodb/runtime/index-browser.js +16 -0
  43. package/generated/prisma-mongodb/runtime/library.d.ts +3977 -0
  44. package/generated/prisma-mongodb/runtime/react-native.js +83 -0
  45. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +84 -0
  46. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +36 -0
  47. package/generated/prisma-mongodb/schema.prisma +362 -0
  48. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +4 -0
  49. package/generated/prisma-mongodb/wasm-worker-loader.mjs +4 -0
  50. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  51. package/generated/prisma-mongodb/wasm.js +341 -0
  52. package/generated/prisma-postgresql/client.d.ts +1 -0
  53. package/generated/prisma-postgresql/client.js +4 -0
  54. package/generated/prisma-postgresql/default.d.ts +1 -0
  55. package/generated/prisma-postgresql/default.js +4 -0
  56. package/generated/prisma-postgresql/edge.d.ts +1 -0
  57. package/generated/prisma-postgresql/edge.js +356 -0
  58. package/generated/prisma-postgresql/index-browser.js +338 -0
  59. package/generated/prisma-postgresql/index.d.ts +25071 -0
  60. package/generated/prisma-postgresql/index.js +381 -0
  61. package/generated/prisma-postgresql/package.json +183 -0
  62. package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
  63. package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -0
  64. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  65. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  66. package/generated/prisma-postgresql/runtime/binary.d.ts +1 -0
  67. package/generated/prisma-postgresql/runtime/binary.js +289 -0
  68. package/generated/prisma-postgresql/runtime/edge-esm.js +34 -0
  69. package/generated/prisma-postgresql/runtime/edge.js +34 -0
  70. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  71. package/generated/prisma-postgresql/runtime/index-browser.js +16 -0
  72. package/generated/prisma-postgresql/runtime/library.d.ts +3977 -0
  73. package/generated/prisma-postgresql/runtime/react-native.js +83 -0
  74. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +84 -0
  75. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +36 -0
  76. package/generated/prisma-postgresql/schema.prisma +345 -0
  77. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +4 -0
  78. package/generated/prisma-postgresql/wasm-worker-loader.mjs +4 -0
  79. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  80. package/generated/prisma-postgresql/wasm.js +363 -0
  81. package/handlers/WEBHOOKS.md +653 -0
  82. package/handlers/backend-utils.js +118 -3
  83. package/handlers/database-migration-handler.js +227 -0
  84. package/handlers/routers/auth.js +1 -1
  85. package/handlers/routers/db-migration.handler.js +29 -0
  86. package/handlers/routers/db-migration.js +256 -0
  87. package/handlers/routers/health.js +41 -6
  88. package/handlers/routers/integration-webhook-routers.js +67 -0
  89. package/handlers/use-cases/check-integrations-health-use-case.js +22 -10
  90. package/handlers/workers/db-migration.js +352 -0
  91. package/index.js +28 -0
  92. package/integrations/WEBHOOK-QUICKSTART.md +151 -0
  93. package/integrations/integration-base.js +74 -3
  94. package/integrations/integration-router.js +60 -70
  95. package/integrations/repositories/integration-repository-interface.js +12 -0
  96. package/integrations/repositories/integration-repository-mongo.js +32 -0
  97. package/integrations/repositories/integration-repository-postgres.js +33 -0
  98. package/integrations/repositories/process-repository-postgres.js +43 -20
  99. package/integrations/tests/doubles/dummy-integration-class.js +1 -8
  100. package/integrations/tests/doubles/test-integration-repository.js +2 -2
  101. package/logs/logger.js +0 -4
  102. package/modules/entity.js +0 -1
  103. package/modules/repositories/module-repository-mongo.js +3 -12
  104. package/modules/repositories/module-repository-postgres.js +0 -11
  105. package/modules/repositories/module-repository.js +1 -12
  106. package/modules/use-cases/get-entity-options-by-id.js +1 -1
  107. package/modules/use-cases/get-module.js +1 -2
  108. package/modules/use-cases/refresh-entity-options.js +1 -1
  109. package/modules/use-cases/test-module-auth.js +1 -1
  110. package/package.json +82 -66
  111. package/prisma-mongodb/schema.prisma +21 -21
  112. package/prisma-postgresql/schema.prisma +15 -15
  113. package/queues/queuer-util.js +28 -15
  114. package/types/core/index.d.ts +2 -2
  115. package/types/module-plugin/index.d.ts +0 -2
  116. package/user/repositories/user-repository-mongo.js +53 -12
  117. package/user/repositories/user-repository-postgres.js +53 -14
  118. package/user/use-cases/authenticate-user.js +127 -0
  119. package/user/use-cases/authenticate-with-shared-secret.js +48 -0
  120. package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
  121. package/user/use-cases/get-user-from-x-frigg-headers.js +106 -0
  122. package/user/use-cases/login-user.js +1 -1
  123. package/user/user.js +18 -2
  124. package/websocket/repositories/websocket-connection-repository-mongo.js +11 -10
  125. package/websocket/repositories/websocket-connection-repository-postgres.js +11 -10
  126. package/websocket/repositories/websocket-connection-repository.js +11 -10
  127. package/application/commands/integration-commands.test.js +0 -123
  128. package/database/encryption/encryption-integration.test.js +0 -553
  129. package/database/encryption/encryption-schema-registry.test.js +0 -392
  130. package/database/encryption/field-encryption-service.test.js +0 -525
  131. package/database/encryption/mongo-decryption-fix-verification.test.js +0 -348
  132. package/database/encryption/postgres-decryption-fix-verification.test.js +0 -371
  133. package/database/encryption/postgres-relation-decryption.test.js +0 -245
  134. package/database/encryption/prisma-encryption-extension.test.js +0 -439
  135. package/errors/base-error.test.js +0 -32
  136. package/errors/fetch-error.test.js +0 -79
  137. package/errors/halt-error.test.js +0 -11
  138. package/errors/validation-errors.test.js +0 -120
  139. package/handlers/auth-flow.integration.test.js +0 -147
  140. package/handlers/integration-event-dispatcher.test.js +0 -141
  141. package/handlers/routers/health.test.js +0 -210
  142. package/integrations/tests/use-cases/create-integration.test.js +0 -131
  143. package/integrations/tests/use-cases/delete-integration-for-user.test.js +0 -150
  144. package/integrations/tests/use-cases/find-integration-context-by-external-entity-id.test.js +0 -92
  145. package/integrations/tests/use-cases/get-integration-for-user.test.js +0 -150
  146. package/integrations/tests/use-cases/get-integration-instance.test.js +0 -176
  147. package/integrations/tests/use-cases/get-integrations-for-user.test.js +0 -176
  148. package/integrations/tests/use-cases/get-possible-integrations.test.js +0 -188
  149. package/integrations/tests/use-cases/update-integration-messages.test.js +0 -142
  150. package/integrations/tests/use-cases/update-integration-status.test.js +0 -103
  151. package/integrations/tests/use-cases/update-integration.test.js +0 -141
  152. package/integrations/use-cases/create-process.test.js +0 -178
  153. package/integrations/use-cases/get-process.test.js +0 -190
  154. package/integrations/use-cases/load-integration-context-full.test.js +0 -329
  155. package/integrations/use-cases/load-integration-context.test.js +0 -114
  156. package/integrations/use-cases/update-process-metrics.test.js +0 -308
  157. package/integrations/use-cases/update-process-state.test.js +0 -256
  158. package/lambda/TimeoutCatcher.test.js +0 -68
  159. package/logs/logger.test.js +0 -76
  160. package/modules/module-hydration.test.js +0 -205
  161. package/modules/requester/requester.test.js +0 -28
  162. package/user/tests/use-cases/create-individual-user.test.js +0 -24
  163. package/user/tests/use-cases/create-organization-user.test.js +0 -28
  164. package/user/tests/use-cases/create-token-for-user-id.test.js +0 -19
  165. package/user/tests/use-cases/get-user-from-bearer-token.test.js +0 -64
  166. package/user/tests/use-cases/login-user.test.js +0 -140
@@ -1,76 +0,0 @@
1
- const { debug, initDebugLog, flushDebugLog } = require('./logger');
2
- const sinon = require('sinon');
3
- const {
4
- overrideEnvironment,
5
- restoreEnvironment,
6
- } = require('@friggframework/test');
7
-
8
- /* eslint-disable no-console */
9
-
10
- describe('Logger', () => {
11
- beforeEach(() => {
12
- sinon.stub(console, 'debug');
13
- sinon.stub(console, 'error');
14
- });
15
-
16
- afterEach(() => {
17
- console.debug.restore();
18
- console.error.restore();
19
- restoreEnvironment();
20
- });
21
-
22
- it('runs', () => {
23
- initDebugLog('Test Event', { test: true });
24
- debug('Add a message', 'or two', { or: 3 });
25
- flushDebugLog(new Error());
26
-
27
- expect(console.debug).toHaveProperty('callCount', 2);
28
- expect(console.error).toHaveProperty('callCount', 1);
29
- });
30
-
31
- it('logs immediately when environment variable set', () => {
32
- overrideEnvironment({ DEBUG_VERBOSE: '1' });
33
-
34
- debug('Add a message', 'or two', { or: 3 });
35
- debug('And another');
36
-
37
- expect(console.debug).toHaveProperty('callCount', 2);
38
- expect(console.error).toHaveProperty('callCount', 0);
39
- });
40
-
41
- it('is resilient to missing parameters', () => {
42
- initDebugLog();
43
- debug();
44
- flushDebugLog();
45
-
46
- expect(console.debug).toHaveProperty('callCount', 0);
47
- expect(console.error).toHaveProperty('callCount', 1);
48
- });
49
-
50
- it('outputs parent errors', () => {
51
- initDebugLog();
52
-
53
- const error = new Error();
54
- error.cause = new Error();
55
- error.cause.cause = new Error();
56
- error.cause.cause.cause = new Error();
57
-
58
- flushDebugLog(error);
59
-
60
- expect(console.debug).toHaveProperty('callCount', 0);
61
- expect(console.error).toHaveProperty('callCount', 7); // 1 + 2 for each cause
62
- });
63
-
64
- it('adds a debug message if more than 1 error encountered', () => {
65
- initDebugLog();
66
- flushDebugLog(new Error());
67
-
68
- expect(console.debug).toHaveProperty('callCount', 0);
69
- expect(console.error).toHaveProperty('callCount', 1);
70
-
71
- flushDebugLog(new Error());
72
-
73
- expect(console.debug).toHaveProperty('callCount', 1);
74
- expect(console.error).toHaveProperty('callCount', 2);
75
- });
76
- });
@@ -1,205 +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 { Module } = require('./module');
9
- const { ModuleFactory } = require('./module-factory');
10
-
11
- // Mock OAuth2Requester base class
12
- class MockOAuth2Api {
13
- constructor(params) {
14
- // Capture all params passed to API constructor
15
- this.client_id = params.client_id;
16
- this.client_secret = params.client_secret;
17
- this.redirect_uri = params.redirect_uri;
18
- this.scope = params.scope;
19
- this.access_token = params.access_token;
20
- this.refresh_token = params.refresh_token;
21
- this.domain = params.domain;
22
- this.delegate = params.delegate;
23
- }
24
-
25
- // Mock API methods
26
- async listProjects() {
27
- if (!this.access_token) {
28
- throw new Error('No access token provided');
29
- }
30
- return { projects: ['project1', 'project2'] };
31
- }
32
-
33
- async getFolders() {
34
- if (!this.access_token) {
35
- throw new Error('No access token provided');
36
- }
37
- return { folders: ['folder1', 'folder2'] };
38
- }
39
-
40
- getAuthorizationRequirements() {
41
- return { type: 'oauth2', url: 'https://example.com/oauth' };
42
- }
43
- }
44
-
45
- MockOAuth2Api.requesterType = 'oauth2';
46
-
47
- // Mock module definition
48
- const mockModuleDefinition = {
49
- moduleName: 'testmodule',
50
- modelName: 'TestModule',
51
- API: MockOAuth2Api,
52
- requiredAuthMethods: {
53
- getToken: async () => {},
54
- getEntityDetails: async () => {},
55
- getCredentialDetails: async () => {},
56
- apiPropertiesToPersist: {
57
- credential: ['access_token', 'refresh_token'],
58
- entity: ['domain'],
59
- },
60
- testAuthRequest: async () => true,
61
- },
62
- env: {
63
- client_id: 'test_client_id',
64
- client_secret: 'test_client_secret',
65
- redirect_uri: 'https://test.com/redirect',
66
- scope: 'read write',
67
- },
68
- };
69
-
70
- describe('Module Hydration', () => {
71
- describe('Module API instantiation', () => {
72
- it('should create API instance with merged env and credential params', () => {
73
- const entity = {
74
- id: 'entity-1',
75
- moduleName: 'testmodule',
76
- domain: 'test.domain.com',
77
- credential: {
78
- data: {
79
- access_token: 'test_access_token',
80
- refresh_token: 'test_refresh_token',
81
- },
82
- },
83
- };
84
-
85
- const module = new Module({
86
- definition: mockModuleDefinition,
87
- userId: 'user-1',
88
- entity,
89
- });
90
-
91
- // Verify module properties
92
- expect(module.name).toBe('testmodule');
93
- expect(module.api).toBeDefined();
94
-
95
- // Verify API was instantiated with correct params
96
- expect(module.api.client_id).toBe('test_client_id');
97
- expect(module.api.client_secret).toBe('test_client_secret');
98
- expect(module.api.redirect_uri).toBe('https://test.com/redirect');
99
- expect(module.api.scope).toBe('read write');
100
- expect(module.api.access_token).toBe('test_access_token');
101
- expect(module.api.refresh_token).toBe('test_refresh_token');
102
- expect(module.api.domain).toBe('test.domain.com');
103
- });
104
-
105
- it('should allow API methods to be called with credentials', async () => {
106
- const entity = {
107
- id: 'entity-1',
108
- moduleName: 'testmodule',
109
- credential: {
110
- data: {
111
- access_token: 'valid_token',
112
- refresh_token: 'valid_refresh_token',
113
- },
114
- },
115
- };
116
-
117
- const module = new Module({
118
- definition: mockModuleDefinition,
119
- userId: 'user-1',
120
- entity,
121
- });
122
-
123
- // Test that API methods work with credentials
124
- const projects = await module.api.listProjects();
125
- expect(projects).toEqual({ projects: ['project1', 'project2'] });
126
-
127
- const folders = await module.api.getFolders();
128
- expect(folders).toEqual({ folders: ['folder1', 'folder2'] });
129
- });
130
-
131
- it('should handle missing credentials gracefully', () => {
132
- const entity = {
133
- id: 'entity-1',
134
- moduleName: 'testmodule',
135
- credential: {
136
- data: {
137
- // Empty credential data - no access_token
138
- },
139
- },
140
- };
141
-
142
- const module = new Module({
143
- definition: mockModuleDefinition,
144
- userId: 'user-1',
145
- entity,
146
- });
147
-
148
- // API should still be created with env params only
149
- expect(module.api).toBeDefined();
150
- expect(module.api.client_id).toBe('test_client_id');
151
- expect(module.api.access_token).toBeUndefined();
152
- });
153
- });
154
-
155
- describe('ModuleFactory', () => {
156
- it('should create module instance from entity and definition', async () => {
157
- const entity = {
158
- id: 'entity-1',
159
- moduleName: 'testmodule',
160
- userId: 'user-1',
161
- credential: {
162
- data: {
163
- access_token: 'factory_token',
164
- },
165
- },
166
- };
167
-
168
- const moduleRepository = {
169
- findEntityById: jest.fn().mockResolvedValue(entity),
170
- };
171
-
172
- const factory = new ModuleFactory({
173
- moduleRepository,
174
- moduleDefinitions: [mockModuleDefinition],
175
- });
176
-
177
- const module = await factory.getModuleInstance('entity-1', 'user-1');
178
-
179
- expect(module).toBeDefined();
180
- expect(module.api).toBeDefined();
181
- expect(module.api.access_token).toBe('factory_token');
182
- });
183
-
184
- it('should throw error if module definition not found', async () => {
185
- const entity = {
186
- id: 'entity-1',
187
- moduleName: 'unknownmodule',
188
- userId: 'user-1',
189
- };
190
-
191
- const moduleRepository = {
192
- findEntityById: jest.fn().mockResolvedValue(entity),
193
- };
194
-
195
- const factory = new ModuleFactory({
196
- moduleRepository,
197
- moduleDefinitions: [mockModuleDefinition],
198
- });
199
-
200
- await expect(
201
- factory.getModuleInstance('entity-1', 'user-1')
202
- ).rejects.toThrow('Module definition not found for module: unknownmodule');
203
- });
204
- });
205
- });
@@ -1,28 +0,0 @@
1
- const { Requester } = require('./requester');
2
-
3
- describe('429 and 5xx testing', () => {
4
- let backOffArray = [1, 1, 1];
5
- let requester = new Requester({ backOff: backOffArray });
6
- let sum = backOffArray.reduce((a, b) => {
7
- return a + b;
8
- }, 0);
9
- it.skip("should retry with 'exponential' back off due to 429", async () => {
10
- let startTime = await Date.now();
11
- let res = await requester._get({
12
- url: 'https://70e18ff0-1967-4fb5-8f96-10477ab6bb9e.mock.pstmn.io//429',
13
- });
14
- let endTime = await Date.now();
15
- let difference = endTime - startTime;
16
- expect(difference).toBeGreaterThan(sum * 1000);
17
- });
18
-
19
- it.skip("should retry with 'exponential' back off due to 500", async () => {
20
- let startTime = await Date.now();
21
- let res = await requester._get({
22
- url: 'https://70e18ff0-1967-4fb5-8f96-10477ab6bb9e.mock.pstmn.io//5xx',
23
- });
24
- let endTime = await Date.now();
25
- let difference = endTime - startTime;
26
- expect(difference).toBeGreaterThan(sum * 1000);
27
- });
28
- });
@@ -1,24 +0,0 @@
1
- const {
2
- CreateIndividualUser,
3
- } = require('../../use-cases/create-individual-user');
4
- const { TestUserRepository } = require('../doubles/test-user-repository');
5
-
6
- describe('CreateIndividualUser Use Case', () => {
7
- it('should create and return an individual user via the repository', async () => {
8
- const userConfig = { usePassword: true };
9
- const userRepository = new TestUserRepository({ userConfig });
10
- const createIndividualUser = new CreateIndividualUser({
11
- userRepository,
12
- userConfig,
13
- });
14
-
15
- const params = {
16
- username: 'test-user',
17
- password: 'password123',
18
- };
19
- const user = await createIndividualUser.execute(params);
20
-
21
- expect(user).toBeDefined();
22
- expect(user.getIndividualUser().username).toBe(params.username);
23
- });
24
- });
@@ -1,28 +0,0 @@
1
- const {
2
- CreateOrganizationUser,
3
- } = require('../../use-cases/create-organization-user');
4
- const { TestUserRepository } = require('../doubles/test-user-repository');
5
-
6
- describe('CreateOrganizationUser Use Case', () => {
7
- it('should create and return an organization user via the repository', async () => {
8
- const userConfig = {
9
- primary: 'organization',
10
- organizationUserRequired: true,
11
- individualUserRequired: false,
12
- };
13
- const userRepository = new TestUserRepository({ userConfig });
14
- const createOrganizationUser = new CreateOrganizationUser({
15
- userRepository,
16
- userConfig,
17
- });
18
-
19
- const params = {
20
- name: 'Test Org',
21
- appOrgId: 'org-123',
22
- };
23
- const user = await createOrganizationUser.execute(params);
24
-
25
- expect(user).toBeDefined();
26
- expect(user.getOrganizationUser().name).toBe(params.name);
27
- });
28
- });
@@ -1,19 +0,0 @@
1
- const {
2
- CreateTokenForUserId,
3
- } = require('../../use-cases/create-token-for-user-id');
4
- const { TestUserRepository } = require('../doubles/test-user-repository');
5
-
6
- describe('CreateTokenForUserId Use Case', () => {
7
- it('should create and return a token via the repository', async () => {
8
- const userConfig = {}; // Not used by this use case, but required by the test repo
9
- const userRepository = new TestUserRepository({ userConfig });
10
- const createTokenForUserId = new CreateTokenForUserId({ userRepository });
11
-
12
- const userId = 'user-123';
13
- const token = await createTokenForUserId.execute(userId);
14
-
15
- expect(token).toBeDefined();
16
- // The mock token is deterministic, so we can check it
17
- expect(token).toContain(`token-for-${userId}`);
18
- });
19
- });
@@ -1,64 +0,0 @@
1
- const {
2
- GetUserFromBearerToken,
3
- } = require('../../use-cases/get-user-from-bearer-token');
4
- const { TestUserRepository } = require('../doubles/test-user-repository');
5
-
6
- describe('GetUserFromBearerToken Use Case', () => {
7
- let userRepository;
8
- let getUserFromBearerToken;
9
- let userConfig;
10
-
11
- beforeEach(() => {
12
- userConfig = {
13
- usePassword: true,
14
- primary: 'individual',
15
- individualUserRequired: true,
16
- organizationUserRequired: false,
17
- };
18
- userRepository = new TestUserRepository({ userConfig });
19
- getUserFromBearerToken = new GetUserFromBearerToken({
20
- userRepository,
21
- userConfig
22
- });
23
- });
24
-
25
- it('should retrieve a user for a valid bearer token', async () => {
26
- const userId = 'user-123';
27
- const token = await userRepository.createToken(userId);
28
- const createdUserData = await userRepository.createIndividualUser({
29
- id: userId,
30
- });
31
-
32
- const user = await getUserFromBearerToken.execute(`Bearer ${token}`);
33
-
34
- expect(user).toBeDefined();
35
- expect(user.getId()).toBe(createdUserData.id);
36
- });
37
-
38
- it('should throw an unauthorized error if the bearer token is missing', async () => {
39
- await expect(getUserFromBearerToken.execute(null)).rejects.toThrow(
40
- 'Missing Authorization Header'
41
- );
42
- });
43
-
44
- it('should throw an unauthorized error for an invalid token format', async () => {
45
- await expect(
46
- getUserFromBearerToken.execute('InvalidToken')
47
- ).rejects.toThrow('Invalid Token Format');
48
- });
49
-
50
- it('should throw an unauthorized error if the Session Token is not found', async () => {
51
- userRepository.getSessionToken = jest.fn().mockResolvedValue(null);
52
- await expect(
53
- getUserFromBearerToken.execute('Bearer invalid-token')
54
- ).rejects.toThrow('Session Token Not Found');
55
- });
56
-
57
- it('should throw an unauthorized error if the token is valid but finds no user', async () => {
58
- userRepository.getSessionToken = jest.fn().mockResolvedValue(null);
59
- const token = await userRepository.createToken('user-dne');
60
- await expect(
61
- getUserFromBearerToken.execute(`Bearer ${token}`)
62
- ).rejects.toThrow('Session Token Not Found');
63
- });
64
- });
@@ -1,140 +0,0 @@
1
- const bcrypt = require('bcryptjs');
2
- const { LoginUser } = require('../../use-cases/login-user');
3
- const { TestUserRepository } = require('../doubles/test-user-repository');
4
-
5
- jest.mock('bcryptjs', () => ({
6
- compareSync: jest.fn(),
7
- }));
8
-
9
- describe('LoginUser Use Case', () => {
10
- let userRepository;
11
- let loginUser;
12
- let userConfig;
13
-
14
- beforeEach(() => {
15
- userConfig = { usePassword: true, individualUserRequired: true, organizationUserRequired: false };
16
- userRepository = new TestUserRepository({ userConfig });
17
- loginUser = new LoginUser({ userRepository, userConfig });
18
-
19
- bcrypt.compareSync.mockClear();
20
- });
21
-
22
- describe('With Password Authentication', () => {
23
- it('should successfully log in a user with correct credentials', async () => {
24
- const username = 'test-user';
25
- const password = 'password123';
26
- await userRepository.createIndividualUser({
27
- username,
28
- hashword: 'hashed-password',
29
- });
30
-
31
- bcrypt.compareSync.mockReturnValue(true);
32
-
33
- const user = await loginUser.execute({ username, password });
34
-
35
- expect(bcrypt.compareSync).toHaveBeenCalledWith(
36
- password,
37
- 'hashed-password'
38
- );
39
- expect(user).toBeDefined();
40
- expect(user.getIndividualUser().username).toBe(username);
41
- });
42
-
43
- it('should throw an unauthorized error for an incorrect password', async () => {
44
- const username = 'test-user';
45
- const password = 'wrong-password';
46
- await userRepository.createIndividualUser({
47
- username,
48
- hashword: 'hashed-password',
49
- });
50
-
51
- bcrypt.compareSync.mockReturnValue(false);
52
-
53
- await expect(
54
- loginUser.execute({ username, password })
55
- ).rejects.toThrow('Incorrect username or password');
56
- });
57
-
58
- it('should throw an unauthorized error for a non-existent user', async () => {
59
- const username = 'non-existent-user';
60
- const password = 'password123';
61
-
62
- await expect(
63
- loginUser.execute({ username, password })
64
- ).rejects.toThrow('user not found');
65
- });
66
- });
67
-
68
- describe('Without Password (appUserId)', () => {
69
- beforeEach(() => {
70
- userConfig = { usePassword: false, individualUserRequired: true, organizationUserRequired: false };
71
- userRepository = new TestUserRepository({ userConfig });
72
- loginUser = new LoginUser({
73
- userRepository,
74
- userConfig,
75
- });
76
- });
77
-
78
- it('should successfully retrieve a user by appUserId', async () => {
79
- const appUserId = 'app-user-123';
80
- const createdUserData = await userRepository.createIndividualUser({
81
- appUserId,
82
- });
83
-
84
- const result = await loginUser.execute({ appUserId });
85
- expect(result.getId()).toBe(createdUserData.id);
86
- });
87
- });
88
-
89
- describe('With Organization User', () => {
90
- beforeEach(() => {
91
- userConfig = {
92
- primary: 'organization',
93
- individualUserRequired: false,
94
- organizationUserRequired: true,
95
- };
96
- userRepository = new TestUserRepository({ userConfig });
97
- loginUser = new LoginUser({
98
- userRepository,
99
- userConfig,
100
- });
101
- });
102
-
103
- it('should successfully retrieve an organization user by appOrgId', async () => {
104
- const appOrgId = 'app-org-123';
105
- const createdUserData = await userRepository.createOrganizationUser({
106
- name: 'Test Org',
107
- appOrgId,
108
- });
109
-
110
- const result = await loginUser.execute({ appOrgId });
111
- expect(result.getId()).toBe(createdUserData.id);
112
- });
113
-
114
- it('should throw an unauthorized error for a non-existent organization user', async () => {
115
- const appOrgId = 'non-existent-org';
116
-
117
- await expect(loginUser.execute({ appOrgId })).rejects.toThrow(
118
- 'org user non-existent-org not found'
119
- );
120
- });
121
- });
122
-
123
- describe('Required User Checks', () => {
124
- it('should throw an error if a required individual user is not found', async () => {
125
- userConfig = {
126
- individualUserRequired: true,
127
- usePassword: false,
128
- };
129
- userRepository = new TestUserRepository({ userConfig });
130
- loginUser = new LoginUser({
131
- userRepository,
132
- userConfig,
133
- });
134
-
135
- await expect(
136
- loginUser.execute({ appUserId: 'a-non-existent-user-id' })
137
- ).rejects.toThrow('user not found');
138
- });
139
- });
140
- });