scope.spec.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import { SCOPE, type Scope } from './scope';
  2. /**
  3. * Helper to extract all scope strings from the SCOPE constant
  4. */
  5. function extractAllScopeStrings(obj: unknown, result: string[] = []): string[] {
  6. if (typeof obj === 'string') {
  7. result.push(obj);
  8. } else if (typeof obj === 'object' && obj !== null) {
  9. for (const value of Object.values(obj)) {
  10. extractAllScopeStrings(value, result);
  11. }
  12. }
  13. return result;
  14. }
  15. describe('Scope type', () => {
  16. it('should include all runtime scope values in the Scope type', () => {
  17. const allRuntimeScopes = extractAllScopeStrings(SCOPE);
  18. // This test verifies type safety - if a scope is missing from the Scope type,
  19. // TypeScript will fail to compile when we try to assign it to a Scope variable
  20. const typedScopes: Scope[] = allRuntimeScopes as Scope[];
  21. expect(typedScopes.length).toBeGreaterThan(0);
  22. });
  23. it('should have the expected scope structure', () => {
  24. // Verify SCOPE.READ exists
  25. expect(SCOPE.READ).toBeDefined();
  26. expect(SCOPE.WRITE).toBeDefined();
  27. // Verify admin scopes
  28. expect(SCOPE.READ.ADMIN).toBeDefined();
  29. expect(SCOPE.READ.ADMIN.TOP).toBe('read:admin:top');
  30. expect(SCOPE.READ.ADMIN.PLUGIN).toBe('read:admin:plugin');
  31. expect(SCOPE.READ.ADMIN.ALL).toBe('read:admin:*');
  32. // Verify user_settings scopes
  33. expect(SCOPE.READ.USER_SETTINGS).toBeDefined();
  34. expect(SCOPE.READ.USER_SETTINGS.INFO).toBe('read:user_settings:info');
  35. expect(SCOPE.READ.USER_SETTINGS.API.API_TOKEN).toBe(
  36. 'read:user_settings:api:api_token',
  37. );
  38. expect(SCOPE.READ.USER_SETTINGS.API.ACCESS_TOKEN).toBe(
  39. 'read:user_settings:api:access_token',
  40. );
  41. expect(SCOPE.READ.USER_SETTINGS.API.ALL).toBe('read:user_settings:api:*');
  42. // Verify features scopes
  43. expect(SCOPE.READ.FEATURES).toBeDefined();
  44. expect(SCOPE.READ.FEATURES.PAGE).toBe('read:features:page');
  45. expect(SCOPE.READ.FEATURES.AI_ASSISTANT).toBe('read:features:ai_assistant');
  46. // Verify write scopes
  47. expect(SCOPE.WRITE.ADMIN.TOP).toBe('write:admin:top');
  48. expect(SCOPE.WRITE.FEATURES.PAGE).toBe('write:features:page');
  49. });
  50. it('should have consistent scope count', () => {
  51. const allRuntimeScopes = extractAllScopeStrings(SCOPE);
  52. // Expected count based on the SCOPE_SEED structure:
  53. // Admin: 17 leaf scopes + 1 wildcard = 18
  54. // User Settings: 6 leaf + 2 nested (api) + 2 wildcards = 10
  55. // Features: 6 leaf scopes + 1 wildcard = 7
  56. // Total per action: 35
  57. // Total: 35 * 2 (read/write) = 70
  58. // But some wildcards are at category level, so actual count may vary
  59. // Just ensure we have a reasonable number of scopes
  60. expect(allRuntimeScopes.length).toBeGreaterThanOrEqual(60);
  61. expect(allRuntimeScopes.length).toBeLessThanOrEqual(100);
  62. });
  63. it('should allow valid scope strings to be assigned to Scope type', () => {
  64. // These assignments should compile without error
  65. const readAdminTop: Scope = 'read:admin:top';
  66. const writeAdminPlugin: Scope = 'write:admin:plugin';
  67. const readUserSettingsApiToken: Scope = 'read:user_settings:api:api_token';
  68. const readAdminWildcard: Scope = 'read:admin:*';
  69. const readWildcard: Scope = 'read:*';
  70. expect(readAdminTop).toBe('read:admin:top');
  71. expect(writeAdminPlugin).toBe('write:admin:plugin');
  72. expect(readUserSettingsApiToken).toBe('read:user_settings:api:api_token');
  73. expect(readAdminWildcard).toBe('read:admin:*');
  74. expect(readWildcard).toBe('read:*');
  75. });
  76. });