@scalekit-sdk/node 2.0.1 → 2.1.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/jest.config.js +15 -0
- package/lib/core.d.ts +1 -1
- package/lib/core.js +31 -31
- package/lib/core.js.map +1 -1
- package/lib/errors/base-exception.d.ts +32 -0
- package/lib/errors/base-exception.js +238 -0
- package/lib/errors/base-exception.js.map +1 -0
- package/lib/errors/index.d.ts +2 -0
- package/lib/errors/index.js +20 -0
- package/lib/errors/index.js.map +1 -0
- package/lib/errors/specific-exceptions.d.ts +39 -0
- package/lib/errors/specific-exceptions.js +90 -0
- package/lib/errors/specific-exceptions.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/pkg/grpc/scalekit/v1/commons/commons_pb.d.ts +34 -87
- package/lib/pkg/grpc/scalekit/v1/commons/commons_pb.js +31 -120
- package/lib/pkg/grpc/scalekit/v1/commons/commons_pb.js.map +1 -1
- package/lib/pkg/grpc/scalekit/v1/connections/connections_connect.d.ts +19 -10
- package/lib/pkg/grpc/scalekit/v1/connections/connections_connect.js +18 -9
- package/lib/pkg/grpc/scalekit/v1/connections/connections_connect.js.map +1 -1
- package/lib/pkg/grpc/scalekit/v1/connections/connections_pb.d.ts +209 -6
- package/lib/pkg/grpc/scalekit/v1/connections/connections_pb.js +272 -5
- package/lib/pkg/grpc/scalekit/v1/connections/connections_pb.js.map +1 -1
- package/lib/pkg/grpc/scalekit/v1/domains/domains_pb.d.ts +29 -0
- package/lib/pkg/grpc/scalekit/v1/domains/domains_pb.js +40 -1
- package/lib/pkg/grpc/scalekit/v1/domains/domains_pb.js.map +1 -1
- package/lib/pkg/grpc/scalekit/v1/errdetails/errdetails_pb.d.ts +25 -0
- package/lib/pkg/grpc/scalekit/v1/errdetails/errdetails_pb.js +38 -1
- package/lib/pkg/grpc/scalekit/v1/errdetails/errdetails_pb.js.map +1 -1
- package/lib/pkg/grpc/scalekit/v1/organizations/organizations_connect.d.ts +21 -1
- package/lib/pkg/grpc/scalekit/v1/organizations/organizations_connect.js +20 -0
- package/lib/pkg/grpc/scalekit/v1/organizations/organizations_connect.js.map +1 -1
- package/lib/pkg/grpc/scalekit/v1/organizations/organizations_pb.d.ts +110 -5
- package/lib/pkg/grpc/scalekit/v1/organizations/organizations_pb.js +164 -5
- package/lib/pkg/grpc/scalekit/v1/organizations/organizations_pb.js.map +1 -1
- package/lib/pkg/grpc/scalekit/v1/users/users_connect.d.ts +48 -1
- package/lib/pkg/grpc/scalekit/v1/users/users_connect.js +47 -0
- package/lib/pkg/grpc/scalekit/v1/users/users_connect.js.map +1 -1
- package/lib/pkg/grpc/scalekit/v1/users/users_pb.d.ts +280 -4
- package/lib/pkg/grpc/scalekit/v1/users/users_pb.js +449 -11
- package/lib/pkg/grpc/scalekit/v1/users/users_pb.js.map +1 -1
- package/lib/scalekit.d.ts +3 -3
- package/lib/scalekit.js +35 -22
- package/lib/scalekit.js.map +1 -1
- package/lib/types/user.d.ts +1 -1
- package/lib/user.d.ts +10 -3
- package/lib/user.js +26 -5
- package/lib/user.js.map +1 -1
- package/package.json +6 -2
- package/src/core.ts +31 -32
- package/src/errors/base-exception.ts +262 -0
- package/src/errors/index.ts +3 -0
- package/src/errors/specific-exceptions.ts +88 -0
- package/src/index.ts +3 -1
- package/src/pkg/grpc/scalekit/v1/commons/commons_pb.ts +49 -129
- package/src/pkg/grpc/scalekit/v1/connections/connections_connect.ts +19 -10
- package/src/pkg/grpc/scalekit/v1/connections/connections_pb.ts +377 -8
- package/src/pkg/grpc/scalekit/v1/domains/domains_pb.ts +44 -0
- package/src/pkg/grpc/scalekit/v1/errdetails/errdetails_pb.ts +49 -0
- package/src/pkg/grpc/scalekit/v1/organizations/organizations_connect.ts +21 -1
- package/src/pkg/grpc/scalekit/v1/organizations/organizations_pb.ts +218 -5
- package/src/pkg/grpc/scalekit/v1/users/users_connect.ts +48 -1
- package/src/pkg/grpc/scalekit/v1/users/users_pb.ts +558 -6
- package/src/scalekit.ts +39 -23
- package/src/types/user.ts +1 -1
- package/src/user.ts +34 -7
- package/tests/README.md +25 -0
- package/tests/connection.test.ts +42 -0
- package/tests/directory.test.ts +46 -0
- package/tests/organization.test.ts +65 -0
- package/tests/passwordless.test.ts +108 -0
- package/tests/scalekit.test.ts +104 -0
- package/tests/setup.ts +34 -0
- package/tests/users.test.ts +168 -0
- package/tests/utils/test-data.ts +248 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import ScalekitClient from '../src/scalekit';
|
|
2
|
+
import { CreateUserRequest, UpdateUserRequest } from '../src/types/user';
|
|
3
|
+
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
|
4
|
+
import { TestDataGenerator, TestOrganizationManager, TestUserManager } from './utils/test-data';
|
|
5
|
+
|
|
6
|
+
describe('Users', () => {
|
|
7
|
+
let client: ScalekitClient;
|
|
8
|
+
let testOrg: string;
|
|
9
|
+
let userId: string | null = null;
|
|
10
|
+
let sharedUserData: CreateUserRequest;
|
|
11
|
+
|
|
12
|
+
beforeEach(async () => {
|
|
13
|
+
// Use global client
|
|
14
|
+
client = global.client;
|
|
15
|
+
|
|
16
|
+
// Create test organization for each test
|
|
17
|
+
testOrg = await TestOrganizationManager.createTestOrganization(client);
|
|
18
|
+
|
|
19
|
+
// Create a shared user for testing
|
|
20
|
+
sharedUserData = TestDataGenerator.generateUserData();
|
|
21
|
+
const createResponse = await client.user.createUserAndMembership(testOrg, sharedUserData);
|
|
22
|
+
userId = createResponse.user?.id || null;
|
|
23
|
+
expect(userId).toBeDefined();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
afterEach(async () => {
|
|
27
|
+
// Clean up test resources
|
|
28
|
+
if (userId) {
|
|
29
|
+
await TestUserManager.cleanupTestUser(client, testOrg, userId);
|
|
30
|
+
userId = null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Clean up test organization
|
|
34
|
+
await TestOrganizationManager.cleanupTestOrganization(client, testOrg);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('listOrganizationUsers', () => {
|
|
38
|
+
it('should list users by organization', async () => {
|
|
39
|
+
// List users in the organization
|
|
40
|
+
const usersList = await client.user.listOrganizationUsers(testOrg, TestDataGenerator.generatePaginationParams());
|
|
41
|
+
|
|
42
|
+
expect(usersList).toBeDefined();
|
|
43
|
+
expect(usersList.users).toBeDefined();
|
|
44
|
+
expect(Array.isArray(usersList.users)).toBe(true);
|
|
45
|
+
expect(usersList.users.length).toBeGreaterThan(0);
|
|
46
|
+
|
|
47
|
+
// Verify basic user attributes
|
|
48
|
+
const firstUser = usersList.users[0];
|
|
49
|
+
expect(firstUser.id).toBeDefined();
|
|
50
|
+
expect(firstUser.email).toBeDefined();
|
|
51
|
+
expect(firstUser.environmentId).toBeDefined();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should handle pagination', async () => {
|
|
55
|
+
const firstPage = await client.user.listOrganizationUsers(testOrg, TestDataGenerator.generatePaginationParams(5));
|
|
56
|
+
|
|
57
|
+
expect(firstPage).toBeDefined();
|
|
58
|
+
expect(firstPage.users.length).toBeLessThanOrEqual(5);
|
|
59
|
+
|
|
60
|
+
if (firstPage.nextPageToken) {
|
|
61
|
+
const secondPage = await client.user.listOrganizationUsers(testOrg, {
|
|
62
|
+
pageSize: 5,
|
|
63
|
+
pageToken: firstPage.nextPageToken
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
expect(secondPage).toBeDefined();
|
|
67
|
+
expect(secondPage.users).toBeDefined();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('getUser', () => {
|
|
73
|
+
it('should get user by ID', async () => {
|
|
74
|
+
// Retrieve the user by ID
|
|
75
|
+
const user = await client.user.getUser(userId!);
|
|
76
|
+
|
|
77
|
+
expect(user).toBeDefined();
|
|
78
|
+
expect(user.user).toBeDefined();
|
|
79
|
+
expect(user.user?.id).toBe(userId);
|
|
80
|
+
expect(user.user?.email).toBe(sharedUserData.email);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('createUserAndMembership', () => {
|
|
85
|
+
it('should create user and membership', async () => {
|
|
86
|
+
// Create a new user for this specific test
|
|
87
|
+
const userData = TestDataGenerator.generateUserData();
|
|
88
|
+
let newUserId: string | null = null;
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const response = await client.user.createUserAndMembership(testOrg, userData);
|
|
92
|
+
|
|
93
|
+
expect(response).toBeDefined();
|
|
94
|
+
expect(response.user).toBeDefined();
|
|
95
|
+
expect(response.user?.id).toBeDefined();
|
|
96
|
+
expect(response.user?.email).toBe(userData.email);
|
|
97
|
+
expect(response.user?.metadata?.source).toBe('test');
|
|
98
|
+
|
|
99
|
+
newUserId = response.user?.id || null;
|
|
100
|
+
} finally {
|
|
101
|
+
// Clean up the new user created in this test
|
|
102
|
+
if (newUserId) {
|
|
103
|
+
await TestUserManager.cleanupTestUser(client, testOrg, newUserId);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should throw error when email is missing', async () => {
|
|
109
|
+
const userData = TestDataGenerator.generateUserData({ email: '' }); // Empty email
|
|
110
|
+
|
|
111
|
+
await expect(
|
|
112
|
+
client.user.createUserAndMembership(testOrg, userData)
|
|
113
|
+
).rejects.toThrow('email is required');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should throw error when organizationId is missing', async () => {
|
|
117
|
+
const userData = TestDataGenerator.generateUserData({ email: 'test@example.com' });
|
|
118
|
+
|
|
119
|
+
await expect(
|
|
120
|
+
client.user.createUserAndMembership('', userData)
|
|
121
|
+
).rejects.toThrow('organizationId is required');
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe('updateUser', () => {
|
|
126
|
+
it('should update user', async () => {
|
|
127
|
+
// Modify the shared user
|
|
128
|
+
const updateData = TestDataGenerator.generateUserUpdateData();
|
|
129
|
+
|
|
130
|
+
const updatedUser = await client.user.updateUser(userId!, updateData);
|
|
131
|
+
|
|
132
|
+
expect(updatedUser).toBeDefined();
|
|
133
|
+
expect(updatedUser.user).toBeDefined();
|
|
134
|
+
expect(updatedUser.user?.id).toBe(userId);
|
|
135
|
+
expect(updatedUser.user?.userProfile?.firstName).toBe('Updated');
|
|
136
|
+
expect(updatedUser.user?.userProfile?.lastName).toBe('Name');
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('resendInvite', () => {
|
|
141
|
+
it('should resend invite to user', async () => {
|
|
142
|
+
// Resend invite to the shared user
|
|
143
|
+
const resendResponse = await client.user.resendInvite(testOrg, userId!);
|
|
144
|
+
|
|
145
|
+
// Verify the response structure
|
|
146
|
+
expect(resendResponse).toBeDefined();
|
|
147
|
+
expect(resendResponse.invite).toBeDefined();
|
|
148
|
+
expect(resendResponse.invite?.userId).toBe(userId);
|
|
149
|
+
expect(resendResponse.invite?.organizationId).toBe(testOrg);
|
|
150
|
+
expect(resendResponse.invite?.status).toBe('PENDING_INVITE');
|
|
151
|
+
expect(resendResponse.invite?.createdAt).toBeDefined();
|
|
152
|
+
expect(resendResponse.invite?.expiresAt).toBeDefined();
|
|
153
|
+
expect(resendResponse.invite?.resentCount).toBe(1);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should throw error when organizationId is missing', async () => {
|
|
157
|
+
await expect(
|
|
158
|
+
client.user.resendInvite('', userId!)
|
|
159
|
+
).rejects.toThrow('organizationId is required');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should throw error when userId is missing', async () => {
|
|
163
|
+
await expect(
|
|
164
|
+
client.user.resendInvite(testOrg, '')
|
|
165
|
+
).rejects.toThrow('userId is required');
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
});
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { CreateUserRequest, UpdateUserRequest } from '../../src/types/user';
|
|
2
|
+
import { TemplateType } from '../../src/pkg/grpc/scalekit/v1/auth/passwordless_pb';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Test data generation utilities to reduce redundancy across test files
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class TestDataGenerator {
|
|
9
|
+
/**
|
|
10
|
+
* Generate a unique timestamp-based identifier
|
|
11
|
+
*/
|
|
12
|
+
static generateUniqueId(): string {
|
|
13
|
+
return Date.now().toString();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generate a unique email address for testing
|
|
18
|
+
*/
|
|
19
|
+
static generateUniqueEmail(): string {
|
|
20
|
+
return `test.user.${this.generateUniqueId()}@example.com`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Generate test organization data
|
|
25
|
+
*/
|
|
26
|
+
static generateOrganizationData() {
|
|
27
|
+
const uniqueId = this.generateUniqueId();
|
|
28
|
+
return {
|
|
29
|
+
name: `Test Org ${uniqueId}`,
|
|
30
|
+
externalId: `ext_org_${uniqueId}`
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Generate test user data
|
|
36
|
+
*/
|
|
37
|
+
static generateUserData(overrides: Partial<CreateUserRequest> = {}): CreateUserRequest {
|
|
38
|
+
const uniqueEmail = this.generateUniqueEmail();
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
email: uniqueEmail,
|
|
42
|
+
userProfile: {
|
|
43
|
+
firstName: 'Test',
|
|
44
|
+
lastName: 'User'
|
|
45
|
+
},
|
|
46
|
+
metadata: {
|
|
47
|
+
source: 'test'
|
|
48
|
+
},
|
|
49
|
+
...overrides
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Generate test user update data
|
|
55
|
+
*/
|
|
56
|
+
static generateUserUpdateData(overrides: Partial<UpdateUserRequest> = {}): UpdateUserRequest {
|
|
57
|
+
return {
|
|
58
|
+
userProfile: {
|
|
59
|
+
firstName: 'Updated',
|
|
60
|
+
lastName: 'Name'
|
|
61
|
+
},
|
|
62
|
+
...overrides
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Generate test passwordless email data
|
|
68
|
+
*/
|
|
69
|
+
static generatePasswordlessEmailData(overrides: any = {}) {
|
|
70
|
+
return {
|
|
71
|
+
template: TemplateType.SIGNIN,
|
|
72
|
+
state: 'test-state',
|
|
73
|
+
expiresIn: 3600,
|
|
74
|
+
magiclinkAuthUri: 'https://example.com/auth/callback',
|
|
75
|
+
...overrides
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Generate test passwordless email with template variables
|
|
81
|
+
*/
|
|
82
|
+
static generatePasswordlessEmailWithTemplateData(overrides: any = {}) {
|
|
83
|
+
return {
|
|
84
|
+
template: TemplateType.SIGNUP,
|
|
85
|
+
templateVariables: {
|
|
86
|
+
companyName: 'Test Company',
|
|
87
|
+
appName: 'Test App'
|
|
88
|
+
},
|
|
89
|
+
magiclinkAuthUri: 'https://example.com/auth/callback',
|
|
90
|
+
...overrides
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Generate test webhook data for verification
|
|
96
|
+
*/
|
|
97
|
+
static generateWebhookData() {
|
|
98
|
+
const secret = 'whsec_test-secret';
|
|
99
|
+
const payload = '{"test": "data"}';
|
|
100
|
+
const timestamp = Math.floor(Date.now() / 1000).toString();
|
|
101
|
+
const webhookId = 'msg_test_webhook_id';
|
|
102
|
+
|
|
103
|
+
// Generate valid signature for testing
|
|
104
|
+
const crypto = require('crypto');
|
|
105
|
+
const data = `${webhookId}.${timestamp}.${payload}`;
|
|
106
|
+
const hmac = crypto.createHmac('sha256', Buffer.from('test-secret', 'base64'));
|
|
107
|
+
hmac.update(data);
|
|
108
|
+
const computedSignature = hmac.digest('base64');
|
|
109
|
+
const signature = `v1,${computedSignature}`;
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
secret,
|
|
113
|
+
payload,
|
|
114
|
+
timestamp,
|
|
115
|
+
webhookId,
|
|
116
|
+
signature,
|
|
117
|
+
headers: {
|
|
118
|
+
'webhook-id': webhookId,
|
|
119
|
+
'webhook-timestamp': timestamp,
|
|
120
|
+
'webhook-signature': signature
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Generate test authorization URL options
|
|
127
|
+
*/
|
|
128
|
+
static generateAuthorizationUrlOptions(overrides: any = {}) {
|
|
129
|
+
return {
|
|
130
|
+
scopes: ['openid', 'profile'],
|
|
131
|
+
state: 'test-state',
|
|
132
|
+
nonce: 'test-nonce',
|
|
133
|
+
prompt: 'login',
|
|
134
|
+
...overrides
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Generate test PKCE parameters
|
|
140
|
+
*/
|
|
141
|
+
static generatePKCEParams() {
|
|
142
|
+
return {
|
|
143
|
+
codeChallenge: 'test-challenge',
|
|
144
|
+
codeChallengeMethod: 'S256'
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Generate test pagination parameters
|
|
150
|
+
*/
|
|
151
|
+
static generatePaginationParams(pageSize: number = 10) {
|
|
152
|
+
return {
|
|
153
|
+
pageSize,
|
|
154
|
+
pageToken: ''
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Generate test credential data for passwordless verification
|
|
160
|
+
*/
|
|
161
|
+
static generateCredentialData(type: 'code' | 'linkToken' = 'code') {
|
|
162
|
+
if (type === 'code') {
|
|
163
|
+
return { code: 'mock-code' };
|
|
164
|
+
} else {
|
|
165
|
+
return { linkToken: 'mock-link-token' };
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Test organization management utilities
|
|
172
|
+
*/
|
|
173
|
+
export class TestOrganizationManager {
|
|
174
|
+
/**
|
|
175
|
+
* Create a test organization and return its ID
|
|
176
|
+
*/
|
|
177
|
+
static async createTestOrganization(client: any): Promise<string> {
|
|
178
|
+
const orgData = TestDataGenerator.generateOrganizationData();
|
|
179
|
+
const orgResponse = await client.organization.createOrganization(
|
|
180
|
+
orgData.name,
|
|
181
|
+
{ externalId: orgData.externalId }
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const testOrg = orgResponse.organization?.id || '';
|
|
185
|
+
if (!testOrg) {
|
|
186
|
+
throw new Error('Failed to create test organization');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return testOrg;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Clean up a test organization
|
|
194
|
+
*/
|
|
195
|
+
static async cleanupTestOrganization(client: any, testOrg: string): Promise<void> {
|
|
196
|
+
if (testOrg) {
|
|
197
|
+
try {
|
|
198
|
+
await client.organization.deleteOrganization(testOrg);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
// Organization may already be deleted
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Test user management utilities
|
|
208
|
+
*/
|
|
209
|
+
export class TestUserManager {
|
|
210
|
+
/**
|
|
211
|
+
* Create a test user and return user data
|
|
212
|
+
*/
|
|
213
|
+
static async createTestUser(client: any, testOrg: string, overrides: Partial<CreateUserRequest> = {}) {
|
|
214
|
+
const userData = TestDataGenerator.generateUserData(overrides);
|
|
215
|
+
const createResponse = await client.user.createUserAndMembership(testOrg, userData);
|
|
216
|
+
const createdUserId = createResponse.user?.id;
|
|
217
|
+
|
|
218
|
+
if (!createdUserId) {
|
|
219
|
+
throw new Error('Failed to create test user');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
userId: createdUserId,
|
|
224
|
+
userData,
|
|
225
|
+
response: createResponse
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Clean up a test user
|
|
231
|
+
*/
|
|
232
|
+
static async cleanupTestUser(client: any, testOrg: string, userId: string): Promise<void> {
|
|
233
|
+
if (userId) {
|
|
234
|
+
try {
|
|
235
|
+
// Remove membership if it exists
|
|
236
|
+
await client.user.deleteMembership(testOrg, userId);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
// Membership may not exist
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
try {
|
|
242
|
+
await client.user.deleteUser(userId);
|
|
243
|
+
} catch (error) {
|
|
244
|
+
// User may already be deleted
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|