@friggframework/core 2.0.0--canary.461.bb7fcba.0 → 2.0.0--canary.461.5767fa4.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.
- package/generated/prisma-mongodb/client.d.ts +1 -0
- package/generated/prisma-mongodb/client.js +4 -0
- package/generated/prisma-mongodb/default.d.ts +1 -0
- package/generated/prisma-mongodb/default.js +4 -0
- package/generated/prisma-mongodb/edge.d.ts +1 -0
- package/generated/prisma-mongodb/edge.js +336 -0
- package/generated/prisma-mongodb/index-browser.js +318 -0
- package/generated/prisma-mongodb/index.d.ts +22993 -0
- package/generated/prisma-mongodb/index.js +361 -0
- package/generated/prisma-mongodb/package.json +183 -0
- package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/runtime/binary.d.ts +1 -0
- package/generated/prisma-mongodb/runtime/binary.js +289 -0
- package/generated/prisma-mongodb/runtime/edge-esm.js +34 -0
- package/generated/prisma-mongodb/runtime/edge.js +34 -0
- package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-mongodb/runtime/index-browser.js +16 -0
- package/generated/prisma-mongodb/runtime/library.d.ts +3977 -0
- package/generated/prisma-mongodb/runtime/react-native.js +83 -0
- package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-mongodb/schema.prisma +364 -0
- package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm.d.ts +1 -0
- package/generated/prisma-mongodb/wasm.js +343 -0
- package/generated/prisma-postgresql/client.d.ts +1 -0
- package/generated/prisma-postgresql/client.js +4 -0
- package/generated/prisma-postgresql/default.d.ts +1 -0
- package/generated/prisma-postgresql/default.js +4 -0
- package/generated/prisma-postgresql/edge.d.ts +1 -0
- package/generated/prisma-postgresql/edge.js +358 -0
- package/generated/prisma-postgresql/index-browser.js +340 -0
- package/generated/prisma-postgresql/index.d.ts +25171 -0
- package/generated/prisma-postgresql/index.js +383 -0
- package/generated/prisma-postgresql/package.json +183 -0
- package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -0
- package/generated/prisma-postgresql/query_engine_bg.js +2 -0
- package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
- package/generated/prisma-postgresql/runtime/binary.d.ts +1 -0
- package/generated/prisma-postgresql/runtime/binary.js +289 -0
- package/generated/prisma-postgresql/runtime/edge-esm.js +34 -0
- package/generated/prisma-postgresql/runtime/edge.js +34 -0
- package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-postgresql/runtime/index-browser.js +16 -0
- package/generated/prisma-postgresql/runtime/library.d.ts +3977 -0
- package/generated/prisma-postgresql/runtime/react-native.js +83 -0
- package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-postgresql/schema.prisma +347 -0
- package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm.d.ts +1 -0
- package/generated/prisma-postgresql/wasm.js +365 -0
- package/package.json +5 -5
- package/application/commands/integration-commands.test.js +0 -123
- package/core/Worker.test.js +0 -159
- package/database/encryption/encryption-integration.test.js +0 -553
- package/database/encryption/encryption-schema-registry.test.js +0 -392
- package/database/encryption/field-encryption-service.test.js +0 -525
- package/database/encryption/mongo-decryption-fix-verification.test.js +0 -348
- package/database/encryption/postgres-decryption-fix-verification.test.js +0 -371
- package/database/encryption/postgres-relation-decryption.test.js +0 -245
- package/database/encryption/prisma-encryption-extension.test.js +0 -439
- package/database/repositories/migration-status-repository-s3.test.js +0 -158
- package/database/use-cases/check-encryption-health-use-case.test.js +0 -192
- package/database/use-cases/get-migration-status-use-case.test.js +0 -171
- package/database/use-cases/run-database-migration-use-case.test.js +0 -310
- package/database/use-cases/trigger-database-migration-use-case.test.js +0 -250
- package/database/utils/prisma-runner.test.js +0 -486
- package/encrypt/Cryptor.test.js +0 -144
- package/errors/base-error.test.js +0 -32
- package/errors/fetch-error.test.js +0 -79
- package/errors/halt-error.test.js +0 -11
- package/errors/validation-errors.test.js +0 -120
- package/handlers/auth-flow.integration.test.js +0 -147
- package/handlers/integration-event-dispatcher.test.js +0 -209
- package/handlers/routers/db-migration.test.js +0 -51
- package/handlers/routers/health.test.js +0 -210
- package/handlers/routers/integration-webhook-routers.test.js +0 -126
- package/handlers/use-cases/check-integrations-health-use-case.test.js +0 -125
- package/handlers/webhook-flow.integration.test.js +0 -356
- package/handlers/workers/db-migration.test.js +0 -50
- package/handlers/workers/integration-defined-workers.test.js +0 -184
- package/integrations/tests/integration-router-multi-auth.test.js +0 -369
- package/integrations/tests/use-cases/create-integration.test.js +0 -131
- package/integrations/tests/use-cases/delete-integration-for-user.test.js +0 -150
- package/integrations/tests/use-cases/find-integration-context-by-external-entity-id.test.js +0 -92
- package/integrations/tests/use-cases/get-integration-for-user.test.js +0 -150
- package/integrations/tests/use-cases/get-integration-instance.test.js +0 -176
- package/integrations/tests/use-cases/get-integrations-for-user.test.js +0 -176
- package/integrations/tests/use-cases/get-possible-integrations.test.js +0 -188
- package/integrations/tests/use-cases/update-integration-messages.test.js +0 -142
- package/integrations/tests/use-cases/update-integration-status.test.js +0 -103
- package/integrations/tests/use-cases/update-integration.test.js +0 -141
- package/integrations/use-cases/create-process.test.js +0 -178
- package/integrations/use-cases/get-process.test.js +0 -190
- package/integrations/use-cases/load-integration-context-full.test.js +0 -329
- package/integrations/use-cases/load-integration-context.test.js +0 -114
- package/integrations/use-cases/update-process-metrics.test.js +0 -308
- package/integrations/use-cases/update-process-state.test.js +0 -256
- package/lambda/TimeoutCatcher.test.js +0 -68
- package/logs/logger.test.js +0 -76
- package/modules/module-hydration.test.js +0 -205
- package/modules/requester/requester.test.js +0 -28
- package/queues/queuer-util.test.js +0 -132
- package/user/tests/use-cases/create-individual-user.test.js +0 -24
- package/user/tests/use-cases/create-organization-user.test.js +0 -28
- package/user/tests/use-cases/create-token-for-user-id.test.js +0 -19
- package/user/tests/use-cases/get-user-from-adopter-jwt.test.js +0 -113
- package/user/tests/use-cases/get-user-from-bearer-token.test.js +0 -64
- package/user/tests/use-cases/get-user-from-x-frigg-headers.test.js +0 -346
- package/user/tests/use-cases/login-user.test.js +0 -220
- package/user/tests/user-password-encryption-isolation.test.js +0 -237
- package/user/tests/user-password-hashing.test.js +0 -235
- package/websocket/repositories/websocket-connection-repository.test.js +0 -227
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
const Boom = require('@hapi/boom');
|
|
2
|
-
const { GetUserFromAdopterJwt } = require('../../use-cases/get-user-from-adopter-jwt');
|
|
3
|
-
|
|
4
|
-
describe('GetUserFromAdopterJwt', () => {
|
|
5
|
-
let getUserFromAdopterJwt;
|
|
6
|
-
let mockUserRepository;
|
|
7
|
-
let mockUserConfig;
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
mockUserRepository = {
|
|
11
|
-
findIndividualUserByAppUserId: jest.fn(),
|
|
12
|
-
findOrganizationUserByAppOrgId: jest.fn(),
|
|
13
|
-
createIndividualUser: jest.fn(),
|
|
14
|
-
createOrganizationUser: jest.fn(),
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
mockUserConfig = {
|
|
18
|
-
usePassword: false,
|
|
19
|
-
primary: 'individual',
|
|
20
|
-
individualUserRequired: true,
|
|
21
|
-
organizationUserRequired: false,
|
|
22
|
-
authModes: {
|
|
23
|
-
adopterJwt: true,
|
|
24
|
-
},
|
|
25
|
-
jwtConfig: {
|
|
26
|
-
secret: 'test-secret',
|
|
27
|
-
userIdClaim: 'sub',
|
|
28
|
-
orgIdClaim: 'org_id',
|
|
29
|
-
algorithm: 'HS256',
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
getUserFromAdopterJwt = new GetUserFromAdopterJwt({
|
|
34
|
-
userRepository: mockUserRepository,
|
|
35
|
-
userConfig: mockUserConfig,
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe('Stub Behavior', () => {
|
|
40
|
-
it('should throw 501 Not Implemented error', async () => {
|
|
41
|
-
const jwtToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIiwib3JnX2lkIjoib3JnNDU2In0.signature';
|
|
42
|
-
|
|
43
|
-
await expect(
|
|
44
|
-
getUserFromAdopterJwt.execute(jwtToken)
|
|
45
|
-
).rejects.toThrow(Boom.notImplemented().message);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('should provide helpful error message about alternative auth modes', async () => {
|
|
49
|
-
const jwtToken = 'test.jwt.token';
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
await getUserFromAdopterJwt.execute(jwtToken);
|
|
53
|
-
fail('Should have thrown error');
|
|
54
|
-
} catch (error) {
|
|
55
|
-
expect(error.message).toContain('not yet implemented');
|
|
56
|
-
expect(error.message).toContain('friggToken');
|
|
57
|
-
expect(error.message).toContain('xFriggHeaders');
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should throw 501 error with any token format', async () => {
|
|
62
|
-
await expect(
|
|
63
|
-
getUserFromAdopterJwt.execute('simple-token')
|
|
64
|
-
).rejects.toThrow(Boom.notImplemented().message);
|
|
65
|
-
|
|
66
|
-
await expect(
|
|
67
|
-
getUserFromAdopterJwt.execute('part1.part2.part3')
|
|
68
|
-
).rejects.toThrow(Boom.notImplemented().message);
|
|
69
|
-
|
|
70
|
-
await expect(getUserFromAdopterJwt.execute('')).rejects.toThrow(
|
|
71
|
-
Boom.notImplemented().message
|
|
72
|
-
);
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
describe('Initialization', () => {
|
|
77
|
-
it('should initialize successfully with valid configuration', () => {
|
|
78
|
-
expect(getUserFromAdopterJwt).toBeDefined();
|
|
79
|
-
expect(getUserFromAdopterJwt.userRepository).toBe(
|
|
80
|
-
mockUserRepository
|
|
81
|
-
);
|
|
82
|
-
expect(getUserFromAdopterJwt.userConfig).toBe(mockUserConfig);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('should initialize without jwtConfig (will fail on execute)', () => {
|
|
86
|
-
const configWithoutJwt = {
|
|
87
|
-
usePassword: false,
|
|
88
|
-
primary: 'individual',
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const instance = new GetUserFromAdopterJwt({
|
|
92
|
-
userRepository: mockUserRepository,
|
|
93
|
-
userConfig: configWithoutJwt,
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
expect(instance).toBeDefined();
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
describe('Future Implementation Notes', () => {
|
|
101
|
-
it('should have documented todos for JWT implementation', () => {
|
|
102
|
-
const useCaseFileContent = require('fs').readFileSync(
|
|
103
|
-
require.resolve('../../use-cases/get-user-from-adopter-jwt.js'),
|
|
104
|
-
'utf-8'
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
expect(useCaseFileContent).toContain('@todo');
|
|
108
|
-
expect(useCaseFileContent).toContain('jsonwebtoken');
|
|
109
|
-
expect(useCaseFileContent).toContain('FUTURE IMPLEMENTATION');
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
|
|
@@ -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,346 +0,0 @@
|
|
|
1
|
-
const Boom = require('@hapi/boom');
|
|
2
|
-
const { GetUserFromXFriggHeaders } = require('../../use-cases/get-user-from-x-frigg-headers');
|
|
3
|
-
const { User } = require('../../user');
|
|
4
|
-
|
|
5
|
-
describe('GetUserFromXFriggHeaders', () => {
|
|
6
|
-
let getUserFromXFriggHeaders;
|
|
7
|
-
let mockUserRepository;
|
|
8
|
-
let mockUserConfig;
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
mockUserRepository = {
|
|
12
|
-
findIndividualUserByAppUserId: jest.fn(),
|
|
13
|
-
findOrganizationUserByAppOrgId: jest.fn(),
|
|
14
|
-
createIndividualUser: jest.fn(),
|
|
15
|
-
createOrganizationUser: jest.fn(),
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
mockUserConfig = {
|
|
19
|
-
usePassword: false,
|
|
20
|
-
primary: 'individual',
|
|
21
|
-
individualUserRequired: true,
|
|
22
|
-
organizationUserRequired: false,
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
getUserFromXFriggHeaders = new GetUserFromXFriggHeaders({
|
|
26
|
-
userRepository: mockUserRepository,
|
|
27
|
-
userConfig: mockUserConfig,
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe('Validation', () => {
|
|
32
|
-
it('should throw 400 error when neither appUserId nor appOrgId provided', async () => {
|
|
33
|
-
await expect(
|
|
34
|
-
getUserFromXFriggHeaders.execute(null, null)
|
|
35
|
-
).rejects.toThrow(Boom.badRequest().message);
|
|
36
|
-
|
|
37
|
-
await expect(
|
|
38
|
-
getUserFromXFriggHeaders.execute(undefined, undefined)
|
|
39
|
-
).rejects.toThrow();
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
describe('Find Existing User', () => {
|
|
44
|
-
it('should find existing individual user by appUserId', async () => {
|
|
45
|
-
const mockIndividualUser = {
|
|
46
|
-
id: 'user-123',
|
|
47
|
-
appUserId: 'app-user-456',
|
|
48
|
-
username: 'testuser',
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
mockUserRepository.findIndividualUserByAppUserId.mockResolvedValue(
|
|
52
|
-
mockIndividualUser
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
const result = await getUserFromXFriggHeaders.execute(
|
|
56
|
-
'app-user-456',
|
|
57
|
-
null
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
expect(result).toBeInstanceOf(User);
|
|
61
|
-
expect(
|
|
62
|
-
mockUserRepository.findIndividualUserByAppUserId
|
|
63
|
-
).toHaveBeenCalledWith('app-user-456');
|
|
64
|
-
expect(
|
|
65
|
-
mockUserRepository.createIndividualUser
|
|
66
|
-
).not.toHaveBeenCalled();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should find existing organization user by appOrgId', async () => {
|
|
70
|
-
mockUserConfig.organizationUserRequired = true;
|
|
71
|
-
mockUserConfig.primary = 'organization';
|
|
72
|
-
|
|
73
|
-
const mockOrgUser = {
|
|
74
|
-
id: 'org-123',
|
|
75
|
-
appOrgId: 'app-org-456',
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
mockUserRepository.findOrganizationUserByAppOrgId.mockResolvedValue(
|
|
79
|
-
mockOrgUser
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
const result = await getUserFromXFriggHeaders.execute(
|
|
83
|
-
null,
|
|
84
|
-
'app-org-456'
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
expect(result).toBeInstanceOf(User);
|
|
88
|
-
expect(
|
|
89
|
-
mockUserRepository.findOrganizationUserByAppOrgId
|
|
90
|
-
).toHaveBeenCalledWith('app-org-456');
|
|
91
|
-
expect(
|
|
92
|
-
mockUserRepository.createOrganizationUser
|
|
93
|
-
).not.toHaveBeenCalled();
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
describe('Auto-create User', () => {
|
|
98
|
-
it('should create new individual user when appUserId not found', async () => {
|
|
99
|
-
mockUserRepository.findIndividualUserByAppUserId.mockResolvedValue(
|
|
100
|
-
null
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
const mockCreatedUser = {
|
|
104
|
-
id: 'user-new',
|
|
105
|
-
appUserId: 'new-app-user',
|
|
106
|
-
username: 'app-user-new-app-user',
|
|
107
|
-
email: 'new-app-user@app.local',
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
mockUserRepository.createIndividualUser.mockResolvedValue(
|
|
111
|
-
mockCreatedUser
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
const result = await getUserFromXFriggHeaders.execute(
|
|
115
|
-
'new-app-user',
|
|
116
|
-
null
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
expect(result).toBeInstanceOf(User);
|
|
120
|
-
expect(
|
|
121
|
-
mockUserRepository.createIndividualUser
|
|
122
|
-
).toHaveBeenCalledWith({
|
|
123
|
-
appUserId: 'new-app-user',
|
|
124
|
-
username: 'app-user-new-app-user',
|
|
125
|
-
email: 'new-app-user@app.local',
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('should create new organization user when appOrgId not found', async () => {
|
|
130
|
-
mockUserConfig.organizationUserRequired = true;
|
|
131
|
-
mockUserConfig.primary = 'organization';
|
|
132
|
-
mockUserConfig.individualUserRequired = false;
|
|
133
|
-
|
|
134
|
-
mockUserRepository.findOrganizationUserByAppOrgId.mockResolvedValue(
|
|
135
|
-
null
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
const mockCreatedOrgUser = {
|
|
139
|
-
id: 'org-new',
|
|
140
|
-
appOrgId: 'new-app-org',
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
mockUserRepository.createOrganizationUser.mockResolvedValue(
|
|
144
|
-
mockCreatedOrgUser
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
const result = await getUserFromXFriggHeaders.execute(
|
|
148
|
-
null,
|
|
149
|
-
'new-app-org'
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
expect(result).toBeInstanceOf(User);
|
|
153
|
-
expect(
|
|
154
|
-
mockUserRepository.createOrganizationUser
|
|
155
|
-
).toHaveBeenCalledWith({
|
|
156
|
-
appOrgId: 'new-app-org',
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
describe('User ID Conflict Detection', () => {
|
|
162
|
-
it('should throw 400 error when both IDs provided but belong to different users', async () => {
|
|
163
|
-
const mockIndividualUser = {
|
|
164
|
-
id: 'user-123',
|
|
165
|
-
appUserId: 'app-user-456',
|
|
166
|
-
organizationUser: 'org-999', // Different org
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
const mockOrgUser = {
|
|
170
|
-
id: 'org-888', // Different ID
|
|
171
|
-
appOrgId: 'app-org-789',
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
mockUserConfig.organizationUserRequired = true;
|
|
175
|
-
|
|
176
|
-
mockUserRepository.findIndividualUserByAppUserId.mockResolvedValue(
|
|
177
|
-
mockIndividualUser
|
|
178
|
-
);
|
|
179
|
-
mockUserRepository.findOrganizationUserByAppOrgId.mockResolvedValue(
|
|
180
|
-
mockOrgUser
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
await expect(
|
|
184
|
-
getUserFromXFriggHeaders.execute('app-user-456', 'app-org-789')
|
|
185
|
-
).rejects.toThrow(Boom.badRequest().message);
|
|
186
|
-
|
|
187
|
-
await expect(
|
|
188
|
-
getUserFromXFriggHeaders.execute('app-user-456', 'app-org-789')
|
|
189
|
-
).rejects.toThrow('User ID mismatch');
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
it('should succeed when both IDs provided and belong to same user', async () => {
|
|
193
|
-
const mockOrgUser = {
|
|
194
|
-
id: 'org-123',
|
|
195
|
-
appOrgId: 'app-org-789',
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
const mockIndividualUser = {
|
|
199
|
-
id: 'user-456',
|
|
200
|
-
appUserId: 'app-user-456',
|
|
201
|
-
organizationUser: 'org-123', // Matches org user
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
mockUserConfig.organizationUserRequired = true;
|
|
205
|
-
|
|
206
|
-
mockUserRepository.findIndividualUserByAppUserId.mockResolvedValue(
|
|
207
|
-
mockIndividualUser
|
|
208
|
-
);
|
|
209
|
-
mockUserRepository.findOrganizationUserByAppOrgId.mockResolvedValue(
|
|
210
|
-
mockOrgUser
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
const result = await getUserFromXFriggHeaders.execute(
|
|
214
|
-
'app-user-456',
|
|
215
|
-
'app-org-789'
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
expect(result).toBeInstanceOf(User);
|
|
219
|
-
expect(
|
|
220
|
-
mockUserRepository.createIndividualUser
|
|
221
|
-
).not.toHaveBeenCalled();
|
|
222
|
-
expect(
|
|
223
|
-
mockUserRepository.createOrganizationUser
|
|
224
|
-
).not.toHaveBeenCalled();
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it('should not validate conflict when only one ID provided', async () => {
|
|
228
|
-
const mockIndividualUser = {
|
|
229
|
-
id: 'user-123',
|
|
230
|
-
appUserId: 'app-user-456',
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
mockUserRepository.findIndividualUserByAppUserId.mockResolvedValue(
|
|
234
|
-
mockIndividualUser
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
const result = await getUserFromXFriggHeaders.execute(
|
|
238
|
-
'app-user-456',
|
|
239
|
-
null
|
|
240
|
-
);
|
|
241
|
-
|
|
242
|
-
expect(result).toBeInstanceOf(User);
|
|
243
|
-
expect(
|
|
244
|
-
mockUserRepository.findOrganizationUserByAppOrgId
|
|
245
|
-
).not.toHaveBeenCalled();
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
describe('User Config Respect', () => {
|
|
250
|
-
it('should respect individualUserRequired setting', async () => {
|
|
251
|
-
mockUserConfig.individualUserRequired = false;
|
|
252
|
-
|
|
253
|
-
mockUserRepository.findIndividualUserByAppUserId.mockResolvedValue(
|
|
254
|
-
null
|
|
255
|
-
);
|
|
256
|
-
|
|
257
|
-
await getUserFromXFriggHeaders.execute('app-user-test', null);
|
|
258
|
-
|
|
259
|
-
// Should not attempt to query or create individual user if not required
|
|
260
|
-
expect(
|
|
261
|
-
mockUserRepository.findIndividualUserByAppUserId
|
|
262
|
-
).not.toHaveBeenCalled();
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it('should respect organizationUserRequired setting', async () => {
|
|
266
|
-
mockUserConfig.organizationUserRequired = false;
|
|
267
|
-
|
|
268
|
-
mockUserRepository.findOrganizationUserByAppOrgId.mockResolvedValue(
|
|
269
|
-
null
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
const mockIndividualUser = {
|
|
273
|
-
id: 'user-123',
|
|
274
|
-
appUserId: 'app-user-456',
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
mockUserRepository.findIndividualUserByAppUserId.mockResolvedValue(
|
|
278
|
-
mockIndividualUser
|
|
279
|
-
);
|
|
280
|
-
|
|
281
|
-
await getUserFromXFriggHeaders.execute('app-user-456', 'app-org-789');
|
|
282
|
-
|
|
283
|
-
// Should not query org user if not required
|
|
284
|
-
expect(
|
|
285
|
-
mockUserRepository.findOrganizationUserByAppOrgId
|
|
286
|
-
).not.toHaveBeenCalled();
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
it('should respect primary user setting', async () => {
|
|
290
|
-
mockUserConfig.primary = 'organization';
|
|
291
|
-
mockUserConfig.organizationUserRequired = true;
|
|
292
|
-
|
|
293
|
-
const mockOrgUser = {
|
|
294
|
-
id: 'org-123',
|
|
295
|
-
appOrgId: 'app-org-789',
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
mockUserRepository.findOrganizationUserByAppOrgId.mockResolvedValue(
|
|
299
|
-
mockOrgUser
|
|
300
|
-
);
|
|
301
|
-
|
|
302
|
-
const result = await getUserFromXFriggHeaders.execute(
|
|
303
|
-
null,
|
|
304
|
-
'app-org-789'
|
|
305
|
-
);
|
|
306
|
-
|
|
307
|
-
expect(result).toBeInstanceOf(User);
|
|
308
|
-
// Verify User is constructed with org as primary
|
|
309
|
-
expect(result.config.primary).toBe('organization');
|
|
310
|
-
});
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
describe('Edge Cases', () => {
|
|
314
|
-
it('should handle both IDs when only one user exists', async () => {
|
|
315
|
-
const mockIndividualUser = {
|
|
316
|
-
id: 'user-123',
|
|
317
|
-
appUserId: 'app-user-456',
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
mockUserConfig.organizationUserRequired = true;
|
|
321
|
-
|
|
322
|
-
mockUserRepository.findIndividualUserByAppUserId.mockResolvedValue(
|
|
323
|
-
mockIndividualUser
|
|
324
|
-
);
|
|
325
|
-
mockUserRepository.findOrganizationUserByAppOrgId.mockResolvedValue(
|
|
326
|
-
null
|
|
327
|
-
);
|
|
328
|
-
|
|
329
|
-
const result = await getUserFromXFriggHeaders.execute(
|
|
330
|
-
'app-user-456',
|
|
331
|
-
'app-org-789'
|
|
332
|
-
);
|
|
333
|
-
|
|
334
|
-
expect(result).toBeInstanceOf(User);
|
|
335
|
-
// Should not throw conflict error when only one user found
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
it('should handle empty string IDs as falsy', async () => {
|
|
339
|
-
await expect(
|
|
340
|
-
getUserFromXFriggHeaders.execute('', '')
|
|
341
|
-
).rejects.toThrow();
|
|
342
|
-
});
|
|
343
|
-
});
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
|