workos 2.16.0 → 3.0.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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/Gemfile.lock +5 -14
  4. data/lib/workos/authentication_factor_and_challenge.rb +31 -0
  5. data/lib/workos/authentication_response.rb +27 -0
  6. data/lib/workos/client.rb +1 -1
  7. data/lib/workos/configuration.rb +1 -1
  8. data/lib/workos/invitation.rb +68 -0
  9. data/lib/workos/organization_membership.rb +50 -0
  10. data/lib/workos/sso.rb +1 -1
  11. data/lib/workos/types/invitation_struct.rb +20 -0
  12. data/lib/workos/types/magic_auth_challenge_struct.rb +12 -0
  13. data/lib/workos/types/organization_membership_struct.rb +15 -0
  14. data/lib/workos/types/provider_enum.rb +1 -0
  15. data/lib/workos/types/user_struct.rb +17 -0
  16. data/lib/workos/types.rb +9 -5
  17. data/lib/workos/user.rb +57 -0
  18. data/lib/workos/user_and_token.rb +29 -0
  19. data/lib/workos/user_management.rb +1008 -0
  20. data/lib/workos/user_response.rb +25 -0
  21. data/lib/workos/version.rb +1 -1
  22. data/lib/workos.rb +35 -28
  23. data/spec/lib/workos/sso_spec.rb +8 -8
  24. data/spec/lib/workos/user_management_spec.rb +1092 -0
  25. data/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_code/invalid.yml +84 -0
  26. data/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_code/valid.yml +82 -0
  27. data/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_email_verification/invalid.yml +83 -0
  28. data/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_email_verification/valid.yml +81 -0
  29. data/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_magic_auth/invalid.yml +82 -0
  30. data/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_magic_auth/valid.yml +82 -0
  31. data/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_organization_selection/invalid.yml +81 -0
  32. data/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_organization_selection/valid.yml +82 -0
  33. data/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_password/invalid.yml +82 -0
  34. data/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_password/valid.yml +82 -0
  35. data/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_totp/invalid.yml +83 -0
  36. data/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_totp/valid.yml +81 -0
  37. data/spec/support/fixtures/vcr_cassettes/user_management/confirm_password_reset/invalid.yml +82 -0
  38. data/spec/support/fixtures/vcr_cassettes/user_management/confirm_password_reset/valid.yml +82 -0
  39. data/spec/support/fixtures/vcr_cassettes/user_management/create_organization_membership/invalid.yml +83 -0
  40. data/spec/support/fixtures/vcr_cassettes/user_management/create_organization_membership/valid.yml +82 -0
  41. data/spec/support/fixtures/vcr_cassettes/user_management/create_user_invalid.yml +83 -0
  42. data/spec/support/fixtures/vcr_cassettes/user_management/create_user_valid.yml +82 -0
  43. data/spec/support/fixtures/vcr_cassettes/user_management/delete_organization_membership/invalid.yml +82 -0
  44. data/spec/support/fixtures/vcr_cassettes/user_management/delete_organization_membership/valid.yml +78 -0
  45. data/spec/support/fixtures/vcr_cassettes/user_management/delete_user/invalid.yml +82 -0
  46. data/spec/support/fixtures/vcr_cassettes/user_management/delete_user/valid.yml +78 -0
  47. data/spec/support/fixtures/vcr_cassettes/user_management/enroll_auth_factor/invalid.yml +82 -0
  48. data/spec/support/fixtures/vcr_cassettes/user_management/enroll_auth_factor/valid.yml +82 -0
  49. data/spec/support/fixtures/vcr_cassettes/user_management/get_invitation/invalid.yml +82 -0
  50. data/spec/support/fixtures/vcr_cassettes/user_management/get_invitation/valid.yml +82 -0
  51. data/spec/support/fixtures/vcr_cassettes/user_management/get_organization_membership.yml +82 -0
  52. data/spec/support/fixtures/vcr_cassettes/user_management/get_user.yml +82 -0
  53. data/spec/support/fixtures/vcr_cassettes/user_management/list_auth_factors/invalid.yml +82 -0
  54. data/spec/support/fixtures/vcr_cassettes/user_management/list_auth_factors/valid.yml +82 -0
  55. data/spec/support/fixtures/vcr_cassettes/user_management/list_invitations/with_after.yml +83 -0
  56. data/spec/support/fixtures/vcr_cassettes/user_management/list_invitations/with_before.yml +83 -0
  57. data/spec/support/fixtures/vcr_cassettes/user_management/list_invitations/with_limit.yml +83 -0
  58. data/spec/support/fixtures/vcr_cassettes/user_management/list_invitations/with_no_options.yml +83 -0
  59. data/spec/support/fixtures/vcr_cassettes/user_management/list_invitations/with_organization_id.yml +83 -0
  60. data/spec/support/fixtures/vcr_cassettes/user_management/list_organization_memberships/no_options.yml +82 -0
  61. data/spec/support/fixtures/vcr_cassettes/user_management/list_organization_memberships/with_options.yml +82 -0
  62. data/spec/support/fixtures/vcr_cassettes/user_management/list_users/no_options.yml +82 -0
  63. data/spec/support/fixtures/vcr_cassettes/user_management/list_users/with_options.yml +82 -0
  64. data/spec/support/fixtures/vcr_cassettes/user_management/reset_password/invalid.yml +82 -0
  65. data/spec/support/fixtures/vcr_cassettes/user_management/reset_password/valid.yml +82 -0
  66. data/spec/support/fixtures/vcr_cassettes/user_management/revoke_invitation/invalid.yml +82 -0
  67. data/spec/support/fixtures/vcr_cassettes/user_management/revoke_invitation/valid.yml +82 -0
  68. data/spec/support/fixtures/vcr_cassettes/user_management/send_invitation/invalid.yml +82 -0
  69. data/spec/support/fixtures/vcr_cassettes/user_management/send_invitation/valid.yml +82 -0
  70. data/spec/support/fixtures/vcr_cassettes/user_management/send_magic_auth_code/valid.yml +82 -0
  71. data/spec/support/fixtures/vcr_cassettes/user_management/send_password_reset_email/invalid.yml +83 -0
  72. data/spec/support/fixtures/vcr_cassettes/user_management/send_password_reset_email/valid.yml +82 -0
  73. data/spec/support/fixtures/vcr_cassettes/user_management/send_verification_email/invalid.yml +82 -0
  74. data/spec/support/fixtures/vcr_cassettes/user_management/send_verification_email/valid.yml +82 -0
  75. data/spec/support/fixtures/vcr_cassettes/user_management/update_user/invalid.yml +82 -0
  76. data/spec/support/fixtures/vcr_cassettes/user_management/update_user/valid.yml +82 -0
  77. data/spec/support/fixtures/vcr_cassettes/user_management/update_user_password/invalid.yml +82 -0
  78. data/spec/support/fixtures/vcr_cassettes/user_management/update_user_password/valid.yml +82 -0
  79. data/spec/support/fixtures/vcr_cassettes/user_management/verify_email/invalid_code.yml +83 -0
  80. data/spec/support/fixtures/vcr_cassettes/user_management/verify_email/invalid_magic_auth_challenge.yml +82 -0
  81. data/spec/support/fixtures/vcr_cassettes/user_management/verify_email/valid.yml +82 -0
  82. data/workos.gemspec +0 -2
  83. metadata +132 -55
  84. data/bin/docs +0 -5
  85. data/docs/WorkOS/APIError.html +0 -160
  86. data/docs/WorkOS/AuditLog.html +0 -235
  87. data/docs/WorkOS/AuditTrail.html +0 -235
  88. data/docs/WorkOS/AuthenticationError.html +0 -160
  89. data/docs/WorkOS/Base.html +0 -287
  90. data/docs/WorkOS/Client.html +0 -504
  91. data/docs/WorkOS/InvalidRequestError.html +0 -160
  92. data/docs/WorkOS/Profile.html +0 -788
  93. data/docs/WorkOS/RequestError.html +0 -135
  94. data/docs/WorkOS/SSO.html +0 -691
  95. data/docs/WorkOS/Types/ProfileStruct.html +0 -135
  96. data/docs/WorkOS/Types/Provider.html +0 -135
  97. data/docs/WorkOS/Types.html +0 -128
  98. data/docs/WorkOS/WorkOSError.html +0 -447
  99. data/docs/WorkOS.html +0 -324
  100. data/docs/class_list.html +0 -51
  101. data/docs/css/common.css +0 -1
  102. data/docs/css/full_list.css +0 -58
  103. data/docs/css/style.css +0 -496
  104. data/docs/file.README.html +0 -252
  105. data/docs/file_list.html +0 -56
  106. data/docs/frames.html +0 -17
  107. data/docs/index.html +0 -250
  108. data/docs/js/app.js +0 -314
  109. data/docs/js/full_list.js +0 -216
  110. data/docs/js/jquery.js +0 -4
  111. data/docs/method_list.html +0 -267
  112. data/docs/top-level-namespace.html +0 -110
  113. data/lib/workos/audit_trail.rb +0 -111
  114. data/spec/lib/workos/audit_trail_spec.rb +0 -146
@@ -0,0 +1,1092 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ describe WorkOS::UserManagement do
5
+ it_behaves_like 'client'
6
+
7
+ describe '.authorization_url' do
8
+ context 'with a provider' do
9
+ let(:args) do
10
+ {
11
+ provider: 'authkit',
12
+ client_id: 'workos-proj-123',
13
+ redirect_uri: 'foo.com/auth/callback',
14
+ state: {
15
+ next_page: '/dashboard/edit',
16
+ }.to_s,
17
+ }
18
+ end
19
+ it 'returns a valid URL' do
20
+ authorization_url = described_class.authorization_url(**args)
21
+
22
+ expect(URI.parse(authorization_url)).to be_a URI
23
+ end
24
+
25
+ it 'returns the expected hostname' do
26
+ authorization_url = described_class.authorization_url(**args)
27
+
28
+ expect(URI.parse(authorization_url).host).to eq(WorkOS.config.api_hostname)
29
+ end
30
+
31
+ it 'returns the expected query string' do
32
+ authorization_url = described_class.authorization_url(**args)
33
+
34
+ expect(URI.parse(authorization_url).query).to eq(
35
+ 'client_id=workos-proj-123&redirect_uri=foo.com%2Fauth%2Fcallback' \
36
+ '&response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2F' \
37
+ 'edit%22%7D&provider=authkit',
38
+ )
39
+ end
40
+ end
41
+
42
+ context 'with a connection selector' do
43
+ let(:args) do
44
+ {
45
+ connection_id: 'connection_123',
46
+ client_id: 'workos-proj-123',
47
+ redirect_uri: 'foo.com/auth/callback',
48
+ state: {
49
+ next_page: '/dashboard/edit',
50
+ }.to_s,
51
+ }
52
+ end
53
+ it 'returns a valid URL' do
54
+ authorization_url = described_class.authorization_url(**args)
55
+
56
+ expect(URI.parse(authorization_url)).to be_a URI
57
+ end
58
+
59
+ it 'returns the expected hostname' do
60
+ authorization_url = described_class.authorization_url(**args)
61
+
62
+ expect(URI.parse(authorization_url).host).to eq(WorkOS.config.api_hostname)
63
+ end
64
+
65
+ it 'returns the expected query string' do
66
+ authorization_url = described_class.authorization_url(**args)
67
+
68
+ expect(URI.parse(authorization_url).query).to eq(
69
+ 'client_id=workos-proj-123&redirect_uri=foo.com%2Fauth%2Fcallback' \
70
+ '&response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2F' \
71
+ 'edit%22%7D&connection_id=connection_123',
72
+ )
73
+ end
74
+ end
75
+
76
+ context 'with an organization selector' do
77
+ let(:args) do
78
+ {
79
+ organization_id: 'org_123',
80
+ client_id: 'workos-proj-123',
81
+ redirect_uri: 'foo.com/auth/callback',
82
+ state: {
83
+ next_page: '/dashboard/edit',
84
+ }.to_s,
85
+ }
86
+ end
87
+ it 'returns a valid URL' do
88
+ authorization_url = described_class.authorization_url(**args)
89
+
90
+ expect(URI.parse(authorization_url)).to be_a URI
91
+ end
92
+
93
+ it 'returns the expected hostname' do
94
+ authorization_url = described_class.authorization_url(**args)
95
+
96
+ expect(URI.parse(authorization_url).host).to eq(WorkOS.config.api_hostname)
97
+ end
98
+
99
+ it 'returns the expected query string' do
100
+ authorization_url = described_class.authorization_url(**args)
101
+
102
+ expect(URI.parse(authorization_url).query).to eq(
103
+ 'client_id=workos-proj-123&redirect_uri=foo.com%2Fauth%2Fcallback' \
104
+ '&response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2F' \
105
+ 'edit%22%7D&organization_id=org_123',
106
+ )
107
+ end
108
+ end
109
+
110
+ context 'with a domain hint' do
111
+ let(:args) do
112
+ {
113
+ connection_id: 'connection_123',
114
+ domain_hint: 'foo.com',
115
+ client_id: 'workos-proj-123',
116
+ redirect_uri: 'foo.com/auth/callback',
117
+ state: {
118
+ next_page: '/dashboard/edit',
119
+ }.to_s,
120
+ }
121
+ end
122
+ it 'returns a valid URL' do
123
+ authorization_url = described_class.authorization_url(**args)
124
+
125
+ expect(URI.parse(authorization_url)).to be_a URI
126
+ end
127
+
128
+ it 'returns the expected hostname' do
129
+ authorization_url = described_class.authorization_url(**args)
130
+
131
+ expect(URI.parse(authorization_url).host).to eq(WorkOS.config.api_hostname)
132
+ end
133
+
134
+ it 'returns the expected query string' do
135
+ authorization_url = described_class.authorization_url(**args)
136
+
137
+ expect(URI.parse(authorization_url).query).to eq(
138
+ 'client_id=workos-proj-123&redirect_uri=foo.com%2Fauth%2Fcallback' \
139
+ '&response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2' \
140
+ 'Fedit%22%7D&domain_hint=foo.com&connection_id=connection_123',
141
+ )
142
+ end
143
+ end
144
+
145
+ context 'with a login hint' do
146
+ let(:args) do
147
+ {
148
+ connection_id: 'connection_123',
149
+ login_hint: 'foo@workos.com',
150
+ client_id: 'workos-proj-123',
151
+ redirect_uri: 'foo.com/auth/callback',
152
+ state: {
153
+ next_page: '/dashboard/edit',
154
+ }.to_s,
155
+ }
156
+ end
157
+ it 'returns a valid URL' do
158
+ authorization_url = described_class.authorization_url(**args)
159
+
160
+ expect(URI.parse(authorization_url)).to be_a URI
161
+ end
162
+
163
+ it 'returns the expected hostname' do
164
+ authorization_url = described_class.authorization_url(**args)
165
+
166
+ expect(URI.parse(authorization_url).host).to eq(WorkOS.config.api_hostname)
167
+ end
168
+
169
+ it 'returns the expected query string' do
170
+ authorization_url = described_class.authorization_url(**args)
171
+
172
+ expect(URI.parse(authorization_url).query).to eq(
173
+ 'client_id=workos-proj-123&redirect_uri=foo.com%2Fauth%2Fcallback' \
174
+ '&response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2' \
175
+ 'Fedit%22%7D&login_hint=foo%40workos.com&connection_id=connection_123',
176
+ )
177
+ end
178
+ end
179
+
180
+ context 'with neither connection_id, organization_id or provider' do
181
+ let(:args) do
182
+ {
183
+ client_id: 'workos-proj-123',
184
+ redirect_uri: 'foo.com/auth/callback',
185
+ state: {
186
+ next_page: '/dashboard/edit',
187
+ }.to_s,
188
+ }
189
+ end
190
+ it 'raises an error' do
191
+ expect do
192
+ described_class.authorization_url(**args)
193
+ end.to raise_error(
194
+ ArgumentError,
195
+ 'Either connection ID, organization ID, or provider is required.',
196
+ )
197
+ end
198
+ end
199
+
200
+ context 'with an invalid provider' do
201
+ let(:args) do
202
+ {
203
+ provider: 'Okta',
204
+ client_id: 'workos-proj-123',
205
+ redirect_uri: 'foo.com/auth/callback',
206
+ state: {
207
+ next_page: '/dashboard/edit',
208
+ }.to_s,
209
+ }
210
+ end
211
+ it 'raises an error' do
212
+ expect do
213
+ described_class.authorization_url(**args)
214
+ end.to raise_error(
215
+ ArgumentError,
216
+ 'Okta is not a valid value. `provider` must be in ' \
217
+ '["GitHubOAuth", "GoogleOAuth", "MicrosoftOAuth", "authkit"]',
218
+ )
219
+ end
220
+ end
221
+ end
222
+
223
+ describe '.get_user' do
224
+ context 'with a valid id' do
225
+ it 'returns a user' do
226
+ VCR.use_cassette 'user_management/get_user' do
227
+ user = described_class.get_user(
228
+ id: 'user_01H7TVSKS45SDHN5V9XPSM6H44',
229
+ )
230
+
231
+ expect(user.id.instance_of?(String))
232
+ expect(user.instance_of?(WorkOS::User))
233
+ end
234
+ end
235
+ end
236
+
237
+ context 'with an invalid id' do
238
+ it 'returns an error' do
239
+ expect do
240
+ described_class.get_user(
241
+ id: 'invalid_user_id',
242
+ ).to raise_error(WorkOS::APIError)
243
+ end
244
+ end
245
+ end
246
+ end
247
+
248
+ describe '.list_users' do
249
+ context 'with no options' do
250
+ it 'returns a list of users' do
251
+ expected_metadata = {
252
+ 'after' => nil,
253
+ 'before' => 'before-id',
254
+ }
255
+
256
+ VCR.use_cassette 'user_management/list_users/no_options' do
257
+ users = described_class.list_users
258
+
259
+ expect(users.data.size).to eq(2)
260
+ expect(users.list_metadata).to eq(expected_metadata)
261
+ end
262
+ end
263
+ end
264
+
265
+ context 'with options' do
266
+ it 'returns a list of matching users' do
267
+ request_args = [
268
+ '/user_management/users?email=lucy.lawless%40example.com&order=desc&limit=5',
269
+ 'Content-Type' => 'application/json'
270
+ ]
271
+
272
+ expected_request = Net::HTTP::Get.new(*request_args)
273
+
274
+ expect(Net::HTTP::Get).to receive(:new).with(*request_args).
275
+ and_return(expected_request)
276
+
277
+ VCR.use_cassette 'user_management/list_users/with_options' do
278
+ users = described_class.list_users(
279
+ email: 'lucy.lawless@example.com',
280
+ order: 'desc',
281
+ limit: '5',
282
+ )
283
+
284
+ expect(users.data.size).to eq(1)
285
+ expect(users.data[0].email).to eq('lucy.lawless@example.com')
286
+ end
287
+ end
288
+ end
289
+ end
290
+
291
+ describe '.create_user' do
292
+ context 'with a valid payload' do
293
+ it 'creates a user' do
294
+ VCR.use_cassette 'user_management/create_user_valid' do
295
+ user = described_class.create_user(
296
+ email: 'foo@example.com',
297
+ first_name: 'Foo',
298
+ last_name: 'Bar',
299
+ email_verified: true,
300
+ )
301
+
302
+ expect(user.first_name).to eq('Foo')
303
+ expect(user.last_name).to eq('Bar')
304
+ expect(user.email).to eq('foo@example.com')
305
+ end
306
+ end
307
+
308
+ context 'with an invalid payload' do
309
+ it 'returns an error' do
310
+ VCR.use_cassette 'user_management/create_user_invalid' do
311
+ expect do
312
+ described_class.create_user(email: '')
313
+ end.to raise_error(
314
+ WorkOS::InvalidRequestError,
315
+ /email_string_required/,
316
+ )
317
+ end
318
+ end
319
+ end
320
+ end
321
+ end
322
+
323
+ describe '.update_user' do
324
+ context 'with a valid payload' do
325
+ it 'update_user a user' do
326
+ VCR.use_cassette 'user_management/update_user/valid' do
327
+ user = described_class.update_user(
328
+ id: 'user_01H7TVSKS45SDHN5V9XPSM6H44',
329
+ first_name: 'Jane',
330
+ last_name: 'Doe',
331
+ email_verified: false,
332
+ )
333
+ expect(user.first_name).to eq('Jane')
334
+ expect(user.last_name).to eq('Doe')
335
+ expect(user.email_verified).to eq(false)
336
+ end
337
+ end
338
+
339
+ context 'with an invalid payload' do
340
+ it 'returns an error' do
341
+ VCR.use_cassette 'user_management/update_user/invalid' do
342
+ expect do
343
+ described_class.update_user(id: 'invalid')
344
+ end.to raise_error(WorkOS::APIError, /User not found/)
345
+ end
346
+ end
347
+ end
348
+ end
349
+ end
350
+
351
+ describe '.delete_user' do
352
+ context 'with a valid id' do
353
+ it 'returns true' do
354
+ VCR.use_cassette('user_management/delete_user/valid') do
355
+ response = WorkOS::UserManagement.delete_user(
356
+ id: 'user_01H7WRJBPAAHX1BYRQHEK7QC4A',
357
+ )
358
+
359
+ expect(response).to be(true)
360
+ end
361
+ end
362
+ end
363
+
364
+ context 'with an invalid id' do
365
+ it 'raises an error' do
366
+ VCR.use_cassette('user_management/delete_user/invalid') do
367
+ expect do
368
+ WorkOS::UserManagement.delete_user(id: 'invalid')
369
+ end.to raise_error(WorkOS::APIError, /User not found/)
370
+ end
371
+ end
372
+ end
373
+ end
374
+
375
+ describe '.authenticate_with_password' do
376
+ context 'with a valid password' do
377
+ it 'returns user' do
378
+ VCR.use_cassette('user_management/authenticate_with_password/valid') do
379
+ authentication_response = WorkOS::UserManagement.authenticate_with_password(
380
+ email: 'test@workos.app',
381
+ password: '7YtYic00VWcXatPb',
382
+ client_id: 'client_123',
383
+ ip_address: '200.240.210.16',
384
+ user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36',
385
+ )
386
+ expect(authentication_response.user.id).to eq('user_01H7TVSKS45SDHN5V9XPSM6H44')
387
+ end
388
+ end
389
+ end
390
+
391
+ context 'with an invalid user' do
392
+ it 'raises an error' do
393
+ VCR.use_cassette('user_management/authenticate_with_password/invalid') do
394
+ expect do
395
+ WorkOS::UserManagement.authenticate_with_password(
396
+ email: 'invalid@workos.app',
397
+ password: 'invalid',
398
+ client_id: 'client_123',
399
+ ip_address: '200.240.210.16',
400
+ user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36',
401
+ )
402
+ end.to raise_error(WorkOS::APIError, /User not found/)
403
+ end
404
+ end
405
+ end
406
+ end
407
+
408
+ describe '.authenticate_with_code' do
409
+ context 'with a valid code' do
410
+ it 'returns user' do
411
+ VCR.use_cassette('user_management/authenticate_with_code/valid') do
412
+ authentication_response = WorkOS::UserManagement.authenticate_with_code(
413
+ code: '01H93ZZHA0JBHFJH9RR11S83YN',
414
+ client_id: 'client_123',
415
+ ip_address: '200.240.210.16',
416
+ user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36',
417
+ )
418
+ expect(authentication_response.user.id).to eq('user_01H93ZY4F80YZRRS6N59Z2HFVS')
419
+ end
420
+ end
421
+ end
422
+
423
+ context 'with an invalid code' do
424
+ it 'raises an error' do
425
+ VCR.use_cassette('user_management/authenticate_with_code/invalid') do
426
+ expect do
427
+ WorkOS::UserManagement.authenticate_with_code(
428
+ code: 'invalid',
429
+ client_id: 'client_123',
430
+ ip_address: '200.240.210.16',
431
+ user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36',
432
+ )
433
+ end.to raise_error(WorkOS::InvalidRequestError, /Status 400/)
434
+ end
435
+ end
436
+ end
437
+ end
438
+
439
+ describe '.authenticate_with_magic_auth' do
440
+ context 'with a valid code' do
441
+ it 'returns user' do
442
+ VCR.use_cassette('user_management/authenticate_with_magic_auth/valid') do
443
+ authentication_response = WorkOS::UserManagement.authenticate_with_magic_auth(
444
+ code: '452079',
445
+ client_id: 'project_01EGKAEB7G5N88E83MF99J785F',
446
+ email: 'test@workos.com',
447
+ ip_address: '200.240.210.16',
448
+ user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36',
449
+ )
450
+ expect(authentication_response.user.id).to eq('user_01H93WD0R0KWF8Q7BK02C0RPYJ')
451
+ end
452
+ end
453
+ end
454
+
455
+ context 'with an invalid code' do
456
+ it 'returns an error' do
457
+ VCR.use_cassette('user_management/authenticate_with_magic_auth/invalid') do
458
+ expect do
459
+ WorkOS::UserManagement.authenticate_with_magic_auth(
460
+ code: 'invalid',
461
+ client_id: 'client_123',
462
+ email: 'test@workos.com',
463
+ )
464
+ end.to raise_error(WorkOS::APIError, /User not found/)
465
+ end
466
+ end
467
+ end
468
+ end
469
+
470
+ describe '.authenticate_with_organization_selection' do
471
+ context 'with a valid code' do
472
+ it 'returns user' do
473
+ VCR.use_cassette('user_management/authenticate_with_organization_selection/valid') do
474
+ authentication_response = WorkOS::UserManagement.authenticate_with_organization_selection(
475
+ client_id: 'project_01EGKAEB7G5N88E83MF99J785F',
476
+ organization_id: 'org_01H5JQDV7R7ATEYZDEG0W5PRYS',
477
+ pending_authentication_token: 'pending_authentication_token_1234',
478
+ ip_address: '200.240.210.16',
479
+ user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36',
480
+ )
481
+ expect(authentication_response.user.id).to eq('user_01H93WD0R0KWF8Q7BK02C0RPYJ')
482
+ expect(authentication_response.organization_id).to eq('org_01H5JQDV7R7ATEYZDEG0W5PRYS')
483
+ end
484
+ end
485
+ end
486
+
487
+ context 'with an invalid token' do
488
+ it 'returns an error' do
489
+ VCR.use_cassette('user_management/authenticate_with_organization_selection/invalid') do
490
+ expect do
491
+ WorkOS::UserManagement.authenticate_with_organization_selection(
492
+ organization_id: 'invalid_org_id',
493
+ client_id: 'project_01EGKAEB7G5N88E83MF99J785F',
494
+ pending_authentication_token: 'pending_authentication_token_1234',
495
+ )
496
+ end.to raise_error(WorkOS::InvalidRequestError, /Status 400/)
497
+ end
498
+ end
499
+ end
500
+ end
501
+
502
+ describe '.authenticate_with_totp' do
503
+ context 'with a valid code' do
504
+ it 'returns user' do
505
+ VCR.use_cassette('user_management/authenticate_with_totp/valid') do
506
+ authentication_response = WorkOS::UserManagement.authenticate_with_totp(
507
+ code: '01H93ZZHA0JBHFJH9RR11S83YN',
508
+ client_id: 'client_123',
509
+ pending_authentication_token: 'pending_authentication_token_1234',
510
+ authentication_challenge_id: 'authentication_challenge_id',
511
+ ip_address: '200.240.210.16',
512
+ user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36',
513
+ )
514
+ expect(authentication_response.user.id).to eq('user_01H93ZY4F80YZRRS6N59Z2HFVS')
515
+ end
516
+ end
517
+ end
518
+
519
+ context 'with an invalid code' do
520
+ it 'raises an error' do
521
+ VCR.use_cassette('user_management/authenticate_with_totp/invalid') do
522
+ expect do
523
+ WorkOS::UserManagement.authenticate_with_totp(
524
+ code: 'invalid',
525
+ client_id: 'client_123',
526
+ pending_authentication_token: 'pending_authentication_token_1234',
527
+ authentication_challenge_id: 'authentication_challenge_id',
528
+ ip_address: '200.240.210.16',
529
+ user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36',
530
+ )
531
+ end.to raise_error(WorkOS::InvalidRequestError, /Status 400/)
532
+ end
533
+ end
534
+ end
535
+ end
536
+
537
+ describe '.authenticate_with_email_verification' do
538
+ context 'with a valid code' do
539
+ it 'returns user' do
540
+ VCR.use_cassette('user_management/authenticate_with_email_verification/valid') do
541
+ authentication_response = WorkOS::UserManagement.authenticate_with_email_verification(
542
+ code: '01H93ZZHA0JBHFJH9RR11S83YN',
543
+ client_id: 'client_123',
544
+ pending_authentication_token: 'pending_authentication_token_1234',
545
+ ip_address: '200.240.210.16',
546
+ user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36',
547
+ )
548
+ expect(authentication_response.user.id).to eq('user_01H93ZY4F80YZRRS6N59Z2HFVS')
549
+ end
550
+ end
551
+ end
552
+
553
+ context 'with an invalid code' do
554
+ it 'raises an error' do
555
+ VCR.use_cassette('user_management/authenticate_with_email_verification/invalid') do
556
+ expect do
557
+ WorkOS::UserManagement.authenticate_with_email_verification(
558
+ code: 'invalid',
559
+ client_id: 'client_123',
560
+ pending_authentication_token: 'pending_authentication_token_1234',
561
+ ip_address: '200.240.210.16',
562
+ user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36',
563
+ )
564
+ end.to raise_error(WorkOS::InvalidRequestError, /Status 400/)
565
+ end
566
+ end
567
+ end
568
+ end
569
+
570
+ describe '.send_magic_auth_code' do
571
+ context 'with valid parameters' do
572
+ it 'sends a magic link to the email address' do
573
+ VCR.use_cassette 'user_management/send_magic_auth_code/valid' do
574
+ described_class.send_magic_auth_code(
575
+ email: 'test@gmail.com',
576
+ )
577
+ end
578
+ end
579
+ end
580
+ end
581
+
582
+ describe '.enroll_auth_factor' do
583
+ context 'with a valid user_id and auth factor type' do
584
+ it 'returns an auth factor and challenge' do
585
+ VCR.use_cassette('user_management/enroll_auth_factor/valid') do
586
+ authentication_response = WorkOS::UserManagement.enroll_auth_factor(
587
+ user_id: 'user_01H7TVSKS45SDHN5V9XPSM6H44',
588
+ type: 'totp',
589
+ )
590
+
591
+ expect(authentication_response.authentication_factor.id).to eq('auth_factor_01H96FETXENNY99ARX0GRC804C')
592
+ expect(authentication_response.authentication_challenge.id).to eq('auth_challenge_01H96FETXGTW1QMBSBT2T36PW0')
593
+ end
594
+ end
595
+ end
596
+
597
+ context 'with an incorrect user id' do
598
+ it 'raises an error' do
599
+ VCR.use_cassette('user_management/enroll_auth_factor/invalid') do
600
+ expect do
601
+ WorkOS::UserManagement.enroll_auth_factor(
602
+ user_id: 'user_01H7TVSKS45SDHN5V9XPSM6H44',
603
+ type: 'totp',
604
+ )
605
+ end.to raise_error(WorkOS::InvalidRequestError, /Status 400/)
606
+ end
607
+ end
608
+ end
609
+
610
+ context 'with an invalid auth factor type' do
611
+ it 'raises an error' do
612
+ expect do
613
+ described_class.enroll_auth_factor(user_id: 'user_01H7TVSKS45SDHN5V9XPSM6H44',
614
+ type: 'invalid-factor',)
615
+ end.to raise_error(
616
+ ArgumentError,
617
+ 'invalid-factor is not a valid value. `type` must be in ["totp"]',
618
+ )
619
+ end
620
+ end
621
+ end
622
+
623
+ describe '.list_auth_factors' do
624
+ context 'with a valid user_id' do
625
+ it 'returns a list of auth factors' do
626
+ VCR.use_cassette('user_management/list_auth_factors/valid') do
627
+ authentication_response = WorkOS::UserManagement.list_auth_factors(
628
+ user_id: 'user_01H7TVSKS45SDHN5V9XPSM6H44',
629
+ )
630
+
631
+ expect(authentication_response.data.first.id).to eq('auth_factor_01H96FETXENNY99ARX0GRC804C')
632
+ end
633
+ end
634
+ end
635
+ context 'with an incorrect user id' do
636
+ it 'raises an error' do
637
+ VCR.use_cassette('user_management/list_auth_factors/invalid') do
638
+ expect do
639
+ WorkOS::UserManagement.list_auth_factors(
640
+ user_id: 'user_01H7TVSKS45SDHN5V9XPSM6H44',
641
+ )
642
+ end.to raise_error(WorkOS::InvalidRequestError, /Status 400/)
643
+ end
644
+ end
645
+ end
646
+ end
647
+
648
+ describe '.send_verification_email' do
649
+ context 'with valid parameters' do
650
+ it 'sends an email to that user and the magic auth challenge' do
651
+ VCR.use_cassette 'user_management/send_verification_email/valid' do
652
+ verification_response = described_class.send_verification_email(
653
+ user_id: 'user_01H93WD0R0KWF8Q7BK02C0RPYJ',
654
+ )
655
+ expect(verification_response.user.id).to eq('user_01H93WD0R0KWF8Q7BK02C0RPYJ')
656
+ end
657
+ end
658
+ end
659
+
660
+ context 'when the user does not exist' do
661
+ it 'returns an error' do
662
+ VCR.use_cassette 'user_management/send_verification_email/invalid' do
663
+ expect do
664
+ described_class.send_verification_email(
665
+ user_id: 'bad_id',
666
+ )
667
+ end.to raise_error(WorkOS::APIError, /User not found/)
668
+ end
669
+ end
670
+ end
671
+ end
672
+
673
+ describe '.verify_email' do
674
+ context 'with valid parameters' do
675
+ it 'verifies the email and returns the user' do
676
+ VCR.use_cassette 'user_management/verify_email/valid' do
677
+ verify_response = described_class.verify_email(
678
+ code: '333495',
679
+ user_id: 'user_01H968BR1R84DSPYS9QR5PM6RZ',
680
+ )
681
+
682
+ expect(verify_response.user.id).to eq('user_01H968BR1R84DSPYS9QR5PM6RZ')
683
+ end
684
+ end
685
+ end
686
+
687
+ context 'with invalid parameters' do
688
+ context 'when the id does not exist' do
689
+ it 'raises an error' do
690
+ VCR.use_cassette 'user_management/verify_email/invalid_magic_auth_challenge' do
691
+ expect do
692
+ described_class.verify_email(
693
+ code: '659770',
694
+ user_id: 'bad_id',
695
+ )
696
+ end.to raise_error(WorkOS::APIError, /User not found/)
697
+ end
698
+ end
699
+ end
700
+
701
+ context 'when the code is incorrect' do
702
+ it 'raises an error' do
703
+ VCR.use_cassette 'user_management/verify_email/invalid_code' do
704
+ expect do
705
+ described_class.verify_email(
706
+ code: '000000',
707
+ user_id: 'user_01H93WD0R0KWF8Q7BK02C0RPYJ',
708
+ )
709
+ end.to raise_error(WorkOS::InvalidRequestError, /Email verification code is incorrect/)
710
+ end
711
+ end
712
+ end
713
+ end
714
+ end
715
+
716
+ describe '.send_password_reset_email' do
717
+ context 'with a valid payload' do
718
+ it 'sends a password reset email' do
719
+ VCR.use_cassette 'user_management/send_password_reset_email/valid' do
720
+ response = described_class.send_password_reset_email(
721
+ email: 'lucy.lawless@example.com',
722
+ password_reset_url: 'https://example.com/reset',
723
+ )
724
+
725
+ expect(response).to be(true)
726
+ end
727
+ end
728
+ end
729
+
730
+ context 'with an invalid payload' do
731
+ it 'returns an error' do
732
+ VCR.use_cassette 'user_management/send_password_reset_email/invalid' do
733
+ expect do
734
+ described_class.send_password_reset_email(
735
+ email: 'foo@bar.com',
736
+ password_reset_url: '',
737
+ )
738
+ end.to raise_error(
739
+ WorkOS::InvalidRequestError,
740
+ /password_reset_url_string_required/,
741
+ )
742
+ end
743
+ end
744
+ end
745
+ end
746
+
747
+ describe '.reset_password' do
748
+ context 'with a valid payload' do
749
+ it 'resets the password and returns the user' do
750
+ VCR.use_cassette 'user_management/reset_password/valid' do
751
+ user = described_class.reset_password(
752
+ token: 'eEgAgvAE0blvU1zWV3yWVAD22',
753
+ new_password: 'very_cool_new_pa$$word',
754
+ )
755
+
756
+ expect(user.email).to eq('lucy.lawless@example.com')
757
+ end
758
+ end
759
+ end
760
+
761
+ context 'with an invalid payload' do
762
+ it 'returns an error' do
763
+ VCR.use_cassette 'user_management/reset_password/invalid' do
764
+ expect do
765
+ described_class.reset_password(
766
+ token: 'bogus_token',
767
+ new_password: 'new_password',
768
+ )
769
+ end.to raise_error(
770
+ WorkOS::APIError,
771
+ /Could not locate user with provided token/,
772
+ )
773
+ end
774
+ end
775
+ end
776
+ end
777
+
778
+ describe '.get_organization_membership' do
779
+ context 'with a valid id' do
780
+ it 'returns a organization membership' do
781
+ VCR.use_cassette 'user_management/get_organization_membership' do
782
+ organization_membership = described_class.get_organization_membership(
783
+ id: 'om_01H5JQDV7R7ATEYZDEG0W5PRYS',
784
+ )
785
+
786
+ expect(organization_membership.id.instance_of?(String))
787
+ expect(organization_membership.instance_of?(WorkOS::OrganizationMembership))
788
+ end
789
+ end
790
+ end
791
+
792
+ context 'with an invalid id' do
793
+ it 'returns an error' do
794
+ expect do
795
+ described_class.get_organization_membership(
796
+ id: 'invalid_organization_membership_id',
797
+ ).to raise_error(WorkOS::APIError)
798
+ end
799
+ end
800
+ end
801
+ end
802
+
803
+ describe '.list_organization_memberships' do
804
+ context 'with no options' do
805
+ it 'returns a list of users' do
806
+ expected_metadata = {
807
+ 'after' => nil,
808
+ 'before' => 'before-id',
809
+ }
810
+
811
+ VCR.use_cassette 'user_management/list_organization_memberships/no_options' do
812
+ organization_memberships = described_class.list_organization_memberships
813
+
814
+ expect(organization_memberships.data.size).to eq(2)
815
+ expect(organization_memberships.list_metadata).to eq(expected_metadata)
816
+ end
817
+ end
818
+ end
819
+
820
+ context 'with options' do
821
+ it 'returns a list of matching users' do
822
+ request_args = [
823
+ '/user_management/organization_memberships?user_id=user_01H5JQDV7R7ATEYZDEG0W5PRYS&order=desc&limit=5',
824
+ 'Content-Type' => 'application/json'
825
+ ]
826
+
827
+ expected_request = Net::HTTP::Get.new(*request_args)
828
+
829
+ expect(Net::HTTP::Get).to receive(:new).with(*request_args).
830
+ and_return(expected_request)
831
+
832
+ VCR.use_cassette 'user_management/list_organization_memberships/with_options' do
833
+ organization_memberships = described_class.list_organization_memberships(
834
+ user_id: 'user_01H5JQDV7R7ATEYZDEG0W5PRYS',
835
+ order: 'desc',
836
+ limit: '5',
837
+ )
838
+
839
+ expect(organization_memberships.data.size).to eq(1)
840
+ expect(organization_memberships.data[0].user_id).to eq('user_01H5JQDV7R7ATEYZDEG0W5PRYS')
841
+ end
842
+ end
843
+ end
844
+ end
845
+
846
+ describe '.create_organization_membership' do
847
+ context 'with a valid payload' do
848
+ it 'creates an organization membership' do
849
+ VCR.use_cassette 'user_management/create_organization_membership/valid' do
850
+ organization_membership = described_class.create_organization_membership(
851
+ user_id: 'user_01H5JQDV7R7ATEYZDEG0W5PRYS',
852
+ organization_id: 'org_01H5JQDV7R7ATEYZDEG0W5PRYS',
853
+ )
854
+
855
+ expect(organization_membership.organization_id).to eq('organization_01H5JQDV7R7ATEYZDEG0W5PRYS')
856
+ expect(organization_membership.user_id).to eq('user_01H5JQDV7R7ATEYZDEG0W5PRYS')
857
+ end
858
+ end
859
+
860
+ context 'with an invalid payload' do
861
+ it 'returns an error' do
862
+ VCR.use_cassette 'user_management/create_organization_membership/invalid' do
863
+ expect do
864
+ described_class.create_organization_membership(user_id: '', organization_id: '')
865
+ end.to raise_error(
866
+ WorkOS::InvalidRequestError,
867
+ /user_id_string_required/,
868
+ )
869
+ end
870
+ end
871
+ end
872
+ end
873
+ end
874
+
875
+ describe '.delete_organization_membership' do
876
+ context 'with a valid id' do
877
+ it 'returns true' do
878
+ VCR.use_cassette('user_management/delete_organization_membership/valid') do
879
+ response = WorkOS::UserManagement.delete_organization_membership(
880
+ id: 'om_01H5JQDV7R7ATEYZDEG0W5PRYS',
881
+ )
882
+
883
+ expect(response).to be(true)
884
+ end
885
+ end
886
+ end
887
+
888
+ context 'with an invalid id' do
889
+ it 'raises an error' do
890
+ VCR.use_cassette('user_management/delete_organization_membership/invalid') do
891
+ expect do
892
+ WorkOS::UserManagement.delete_organization_membership(id: 'invalid')
893
+ end.to raise_error(WorkOS::APIError, /Organization Membership not found/)
894
+ end
895
+ end
896
+ end
897
+ end
898
+
899
+ describe '.get_invitation' do
900
+ context 'with a valid id' do
901
+ it 'returns an invitation' do
902
+ VCR.use_cassette 'user_management/get_invitation/valid' do
903
+ invitation = described_class.get_invitation(
904
+ id: 'invitation_01H5JQDV7R7ATEYZDEG0W5PRYS',
905
+ )
906
+
907
+ expect(invitation.id.instance_of?(String))
908
+ expect(invitation.instance_of?(WorkOS::Invitation))
909
+ end
910
+ end
911
+ end
912
+
913
+ context 'with an invalid id' do
914
+ it 'raises an error' do
915
+ VCR.use_cassette('user_management/get_invitation/invalid') do
916
+ expect do
917
+ WorkOS::UserManagement.get_invitation(id: 'invalid')
918
+ end.to raise_error(WorkOS::APIError, /Invitation not found/)
919
+ end
920
+ end
921
+ end
922
+ end
923
+
924
+ describe '.list_invitations' do
925
+ context 'with no options' do
926
+ it 'returns invitations and metadata' do
927
+ expected_metadata = {
928
+ 'after' => nil,
929
+ 'before' => 'before_id',
930
+ }
931
+
932
+ VCR.use_cassette 'user_management/list_invitations/with_no_options' do
933
+ invitations = described_class.list_invitations
934
+
935
+ expect(invitations.data.size).to eq(5)
936
+ expect(invitations.list_metadata).to eq(expected_metadata)
937
+ end
938
+ end
939
+ end
940
+
941
+ context 'with organization_id option' do
942
+ it 'forms the proper request to the API' do
943
+ request_args = [
944
+ '/user_management/invitations?organization_id=org_01H5JQDV7R7ATEYZDEG0W5PRYS',
945
+ 'Content-Type' => 'application/json'
946
+ ]
947
+
948
+ expected_request = Net::HTTP::Get.new(*request_args)
949
+
950
+ expect(Net::HTTP::Get).to receive(:new).with(*request_args).
951
+ and_return(expected_request)
952
+
953
+ VCR.use_cassette 'user_management/list_invitations/with_organization_id' do
954
+ invitations = described_class.list_invitations(
955
+ organization_id: 'org_01H5JQDV7R7ATEYZDEG0W5PRYS',
956
+ )
957
+
958
+ expect(invitations.data.size).to eq(1)
959
+ expect(invitations.data.first.organization_id).to eq(
960
+ 'org_01H5JQDV7R7ATEYZDEG0W5PRYS',
961
+ )
962
+ end
963
+ end
964
+ end
965
+
966
+ context 'with limit option' do
967
+ it 'forms the proper request to the API' do
968
+ request_args = [
969
+ '/user_management/invitations?limit=2',
970
+ 'Content-Type' => 'application/json'
971
+ ]
972
+
973
+ expected_request = Net::HTTP::Get.new(*request_args)
974
+
975
+ expect(Net::HTTP::Get).to receive(:new).with(*request_args).
976
+ and_return(expected_request)
977
+
978
+ VCR.use_cassette 'user_management/list_invitations/with_limit' do
979
+ invitations = described_class.list_invitations(
980
+ limit: 2,
981
+ )
982
+
983
+ expect(invitations.data.size).to eq(3)
984
+ end
985
+ end
986
+ end
987
+
988
+ context 'with before option' do
989
+ it 'forms the proper request to the API' do
990
+ request_args = [
991
+ '/user_management/invitations?before=invitation_01H5JQDV7R7ATEYZDEG0W5PRYS',
992
+ 'Content-Type' => 'application/json'
993
+ ]
994
+
995
+ expected_request = Net::HTTP::Get.new(*request_args)
996
+
997
+ expect(Net::HTTP::Get).to receive(:new).with(*request_args).
998
+ and_return(expected_request)
999
+
1000
+ VCR.use_cassette 'user_management/list_invitations/with_before' do
1001
+ invitations = described_class.list_invitations(
1002
+ before: 'invitation_01H5JQDV7R7ATEYZDEG0W5PRYS',
1003
+ )
1004
+
1005
+ expect(invitations.data.size).to eq(2)
1006
+ end
1007
+ end
1008
+ end
1009
+
1010
+ context 'with after option' do
1011
+ it 'forms the proper request to the API' do
1012
+ request_args = [
1013
+ '/user_management/invitations?after=invitation_01H5JQDV7R7ATEYZDEG0W5PRYS',
1014
+ 'Content-Type' => 'application/json'
1015
+ ]
1016
+
1017
+ expected_request = Net::HTTP::Get.new(*request_args)
1018
+
1019
+ expect(Net::HTTP::Get).to receive(:new).with(*request_args).
1020
+ and_return(expected_request)
1021
+
1022
+ VCR.use_cassette 'user_management/list_invitations/with_after' do
1023
+ invitations = described_class.list_invitations(
1024
+ after: 'invitation_01H5JQDV7R7ATEYZDEG0W5PRYS',
1025
+ )
1026
+
1027
+ expect(invitations.data.size).to eq(2)
1028
+ end
1029
+ end
1030
+ end
1031
+ end
1032
+
1033
+ describe '.send_invitation' do
1034
+ context 'with valid payload' do
1035
+ it 'sends an invitation' do
1036
+ VCR.use_cassette 'user_management/send_invitation/valid' do
1037
+ invitation = described_class.send_invitation(
1038
+ email: 'test@workos.com',
1039
+ )
1040
+
1041
+ expect(invitation.id).to eq('invitation_01H5JQDV7R7ATEYZDEG0W5PRYS')
1042
+ expect(invitation.email).to eq('test@workos.com')
1043
+ end
1044
+ end
1045
+ end
1046
+
1047
+ context 'with an invalid payload' do
1048
+ it 'returns an error' do
1049
+ VCR.use_cassette 'user_management/send_invitation/invalid' do
1050
+ expect do
1051
+ described_class.send_invitation(
1052
+ email: 'invalid@workos.com',
1053
+ )
1054
+ end.to raise_error(
1055
+ WorkOS::APIError,
1056
+ /An Invitation with the email invalid@workos.com already exists/,
1057
+ )
1058
+ end
1059
+ end
1060
+ end
1061
+ end
1062
+
1063
+ describe '.revoke_invitation' do
1064
+ context 'with valid payload' do
1065
+ it 'revokes invitation' do
1066
+ VCR.use_cassette 'user_management/revoke_invitation/valid' do
1067
+ invitation = described_class.revoke_invitation(
1068
+ id: 'invitation_01H5JQDV7R7ATEYZDEG0W5PRYS',
1069
+ )
1070
+
1071
+ expect(invitation.id).to eq('invitation_01H5JQDV7R7ATEYZDEG0W5PRYS')
1072
+ expect(invitation.email).to eq('test@workos.com')
1073
+ end
1074
+ end
1075
+ end
1076
+
1077
+ context 'with an invalid payload' do
1078
+ it 'returns an error' do
1079
+ VCR.use_cassette 'user_management/revoke_invitation/invalid' do
1080
+ expect do
1081
+ described_class.revoke_invitation(
1082
+ id: 'invalid_id',
1083
+ )
1084
+ end.to raise_error(
1085
+ WorkOS::APIError,
1086
+ /Invitation not found/,
1087
+ )
1088
+ end
1089
+ end
1090
+ end
1091
+ end
1092
+ end