|
| 1 | +import type { Page } from '@playwright/test'; |
1 | 2 | import { expect, test } from '@playwright/test'; |
2 | 3 |
|
3 | 4 | import { appConfigs } from '../../presets'; |
4 | 5 | import type { FakeOrganization, FakeUser } from '../../testUtils'; |
5 | 6 | import { createTestUtils, testAgainstRunningApps } from '../../testUtils'; |
6 | 7 |
|
| 8 | +const mockAPIKeysEnvironmentSettings = async ( |
| 9 | + page: Page, |
| 10 | + overrides: Partial<{ |
| 11 | + user_api_keys_enabled: boolean; |
| 12 | + orgs_api_keys_enabled: boolean; |
| 13 | + }>, |
| 14 | +) => { |
| 15 | + await page.route('*/**/v1/environment*', async route => { |
| 16 | + const response = await route.fetch(); |
| 17 | + const json = await response.json(); |
| 18 | + const newJson = { |
| 19 | + ...json, |
| 20 | + api_keys_settings: { |
| 21 | + user_api_keys_enabled: true, |
| 22 | + orgs_api_keys_enabled: true, |
| 23 | + ...overrides, |
| 24 | + }, |
| 25 | + }; |
| 26 | + await route.fulfill({ response, json: newJson }); |
| 27 | + }); |
| 28 | +}; |
| 29 | + |
7 | 30 | testAgainstRunningApps({ |
8 | 31 | withEnv: [appConfigs.envs.withAPIKeys], |
9 | 32 | withPattern: ['withMachine.next.appRouter'], |
@@ -214,81 +237,111 @@ testAgainstRunningApps({ |
214 | 237 | expect(clipboardText).toBe(secret); |
215 | 238 | }); |
216 | 239 |
|
217 | | - test('component does not render for orgs when user does not have permissions', async ({ page, context }) => { |
| 240 | + test('UserProfile API keys page visibility', async ({ page, context }) => { |
218 | 241 | const u = createTestUtils({ app, page, context }); |
219 | 242 |
|
220 | | - const fakeMember = u.services.users.createFakeUser(); |
221 | | - const member = await u.services.users.createBapiUser(fakeMember); |
| 243 | + await u.po.signIn.goTo(); |
| 244 | + await u.po.signIn.waitForMounted(); |
| 245 | + await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeAdmin.email, password: fakeAdmin.password }); |
| 246 | + await u.po.expect.toBeSignedIn(); |
222 | 247 |
|
223 | | - await u.services.clerk.organizations.createOrganizationMembership({ |
224 | | - organizationId: fakeOrganization.organization.id, |
225 | | - role: 'org:member', |
226 | | - userId: member.id, |
227 | | - }); |
| 248 | + // user_api_keys_enabled: false should hide API keys page |
| 249 | + await mockAPIKeysEnvironmentSettings(u.page, { user_api_keys_enabled: false }); |
| 250 | + await u.po.page.goToRelative('/user'); |
| 251 | + await u.po.userProfile.waitForMounted(); |
| 252 | + await u.po.page.goToRelative('/user#/api-keys'); |
| 253 | + await expect(u.page.locator('.cl-apiKeys')).toBeHidden({ timeout: 2000 }); |
| 254 | + |
| 255 | + // user_api_keys_enabled: true should show API keys page |
| 256 | + await mockAPIKeysEnvironmentSettings(u.page, { user_api_keys_enabled: true }); |
| 257 | + await page.reload(); |
| 258 | + await u.po.userProfile.waitForMounted(); |
| 259 | + await u.po.page.goToRelative('/user#/api-keys'); |
| 260 | + await expect(u.page.locator('.cl-apiKeys')).toBeVisible({ timeout: 5000 }); |
| 261 | + |
| 262 | + await u.page.unrouteAll(); |
| 263 | + }); |
| 264 | + |
| 265 | + test('OrganizationProfile API keys page visibility', async ({ page, context }) => { |
| 266 | + const u = createTestUtils({ app, page, context }); |
| 267 | + |
| 268 | + await u.po.signIn.goTo(); |
| 269 | + await u.po.signIn.waitForMounted(); |
| 270 | + await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeAdmin.email, password: fakeAdmin.password }); |
| 271 | + await u.po.expect.toBeSignedIn(); |
| 272 | + |
| 273 | + // orgs_api_keys_enabled: false should hide API keys page |
| 274 | + await mockAPIKeysEnvironmentSettings(u.page, { orgs_api_keys_enabled: false }); |
| 275 | + await u.po.page.goToRelative('/organization-profile'); |
| 276 | + await u.po.page.goToRelative('/organization-profile#/organization-api-keys'); |
| 277 | + await expect(u.page.locator('.cl-apiKeys')).toBeHidden({ timeout: 2000 }); |
| 278 | + |
| 279 | + // orgs_api_keys_enabled: true should show API keys page |
| 280 | + await mockAPIKeysEnvironmentSettings(u.page, { orgs_api_keys_enabled: true }); |
| 281 | + await page.reload(); |
| 282 | + await u.po.page.goToRelative('/organization-profile#/organization-api-keys'); |
| 283 | + await expect(u.page.locator('.cl-apiKeys')).toBeVisible({ timeout: 5000 }); |
| 284 | + |
| 285 | + await u.page.unrouteAll(); |
| 286 | + }); |
| 287 | + |
| 288 | + test('standalone API keys component in user context based on user_api_keys_enabled', async ({ page, context }) => { |
| 289 | + const u = createTestUtils({ app, page, context }); |
228 | 290 |
|
229 | 291 | await u.po.signIn.goTo(); |
230 | 292 | await u.po.signIn.waitForMounted(); |
231 | | - await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeMember.email, password: fakeMember.password }); |
| 293 | + await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeAdmin.email, password: fakeAdmin.password }); |
232 | 294 | await u.po.expect.toBeSignedIn(); |
233 | 295 |
|
| 296 | + // user_api_keys_enabled: false should prevent standalone component from rendering |
| 297 | + await mockAPIKeysEnvironmentSettings(u.page, { user_api_keys_enabled: false }); |
| 298 | + |
234 | 299 | let apiKeysRequestWasMade = false; |
235 | | - u.page.on('request', request => { |
236 | | - if (request.url().includes('/api_keys')) { |
237 | | - apiKeysRequestWasMade = true; |
238 | | - } |
| 300 | + await u.page.route('**/api_keys*', async route => { |
| 301 | + apiKeysRequestWasMade = true; |
| 302 | + await route.abort(); |
239 | 303 | }); |
240 | 304 |
|
241 | | - // Check that standalone component is not rendered |
242 | 305 | await u.po.page.goToRelative('/api-keys'); |
243 | 306 | await expect(u.page.locator('.cl-apiKeys-root')).toBeHidden({ timeout: 1000 }); |
244 | | - |
245 | | - // Check that page is not rendered in OrganizationProfile |
246 | | - await u.po.page.goToRelative('/organization-profile#/organization-api-keys'); |
247 | | - await expect(u.page.locator('.cl-apiKeys-root')).toBeHidden({ timeout: 1000 }); |
248 | | - |
249 | 307 | expect(apiKeysRequestWasMade).toBe(false); |
250 | 308 |
|
251 | | - await fakeMember.deleteIfExists(); |
| 309 | + // user_api_keys_enabled: true should allow standalone component to render |
| 310 | + await mockAPIKeysEnvironmentSettings(u.page, { user_api_keys_enabled: true }); |
| 311 | + await page.reload(); |
| 312 | + await u.po.apiKeys.waitForMounted(); |
| 313 | + await expect(u.page.locator('.cl-apiKeys-root')).toBeVisible(); |
| 314 | + |
| 315 | + await u.page.unrouteAll(); |
252 | 316 | }); |
253 | 317 |
|
254 | | - test('user with read permission can view API keys but not manage them', async ({ page, context }) => { |
| 318 | + test('standalone API keys component in org context based on orgs_api_keys_enabled', async ({ page, context }) => { |
255 | 319 | const u = createTestUtils({ app, page, context }); |
256 | 320 |
|
257 | | - const fakeViewer = u.services.users.createFakeUser(); |
258 | | - const viewer = await u.services.users.createBapiUser(fakeViewer); |
259 | | - |
260 | | - await u.services.clerk.organizations.createOrganizationMembership({ |
261 | | - organizationId: fakeOrganization.organization.id, |
262 | | - role: 'org:viewer', |
263 | | - userId: viewer.id, |
264 | | - }); |
265 | | - |
266 | 321 | await u.po.signIn.goTo(); |
267 | 322 | await u.po.signIn.waitForMounted(); |
268 | | - await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeViewer.email, password: fakeViewer.password }); |
| 323 | + await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeAdmin.email, password: fakeAdmin.password }); |
269 | 324 | await u.po.expect.toBeSignedIn(); |
270 | 325 |
|
| 326 | + // orgs_api_keys_enabled: false should prevent standalone component from rendering in org context |
| 327 | + await mockAPIKeysEnvironmentSettings(u.page, { orgs_api_keys_enabled: false }); |
| 328 | + |
271 | 329 | let apiKeysRequestWasMade = false; |
272 | | - u.page.on('request', request => { |
273 | | - if (request.url().includes('/api_keys')) { |
274 | | - apiKeysRequestWasMade = true; |
275 | | - } |
| 330 | + await u.page.route('**/api_keys*', async route => { |
| 331 | + apiKeysRequestWasMade = true; |
| 332 | + await route.abort(); |
276 | 333 | }); |
277 | 334 |
|
278 | | - // Check that standalone component is rendered and user can read API keys |
279 | 335 | await u.po.page.goToRelative('/api-keys'); |
280 | | - await u.po.apiKeys.waitForMounted(); |
281 | | - await expect(u.page.getByRole('button', { name: /Add new key/i })).toBeHidden(); |
282 | | - await expect(u.page.getByRole('columnheader', { name: /Actions/i })).toBeHidden(); |
283 | | - |
284 | | - // Check that page is rendered in OrganizationProfile and user can read API keys |
285 | | - await u.po.page.goToRelative('/organization-profile#/organization-api-keys'); |
286 | | - await expect(u.page.locator('.cl-apiKeys')).toBeVisible(); |
287 | | - await expect(u.page.getByRole('button', { name: /Add new key/i })).toBeHidden(); |
288 | | - await expect(u.page.getByRole('columnheader', { name: /Actions/i })).toBeHidden(); |
| 336 | + await expect(u.page.locator('.cl-apiKeys-root')).toBeHidden({ timeout: 1000 }); |
| 337 | + expect(apiKeysRequestWasMade).toBe(false); |
289 | 338 |
|
290 | | - expect(apiKeysRequestWasMade).toBe(true); |
| 339 | + // orgs_api_keys_enabled: true should allow standalone component to render in org context |
| 340 | + await mockAPIKeysEnvironmentSettings(u.page, { orgs_api_keys_enabled: true }); |
| 341 | + await page.reload(); |
| 342 | + await u.po.apiKeys.waitForMounted(); |
| 343 | + await expect(u.page.locator('.cl-apiKeys-root')).toBeVisible(); |
291 | 344 |
|
292 | | - await fakeViewer.deleteIfExists(); |
| 345 | + await u.page.unrouteAll(); |
293 | 346 | }); |
294 | 347 | }); |
0 commit comments