|
|
@@ -0,0 +1,90 @@
|
|
|
+import { describe, it, expect } from 'vitest';
|
|
|
+
|
|
|
+import { SCOPE } from '../../interfaces/scope';
|
|
|
+
|
|
|
+import {
|
|
|
+ isValidScope, hasAllScope, extractAllScope, extractScopes,
|
|
|
+} from './scope-utils';
|
|
|
+
|
|
|
+describe('scope-utils', () => {
|
|
|
+ describe('isValidScope', () => {
|
|
|
+ it('should return true for valid scopes', () => {
|
|
|
+ expect(isValidScope(SCOPE.READ.USER.API.API_TOKEN)).toBe(true);
|
|
|
+ expect(isValidScope(SCOPE.WRITE.USER.API.ACCESS_TOKEN)).toBe(true);
|
|
|
+ expect(isValidScope(SCOPE.READ.ADMIN.APP)).toBe(true);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should return false for invalid scopes', () => {
|
|
|
+ expect(isValidScope('invalid:scope' as any)).toBe(false);
|
|
|
+ expect(isValidScope('read:invalid:path' as any)).toBe(false);
|
|
|
+ expect(isValidScope('write:user:invalid' as any)).toBe(false);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('hasAllScope', () => {
|
|
|
+ it('should return true for scopes ending with *', () => {
|
|
|
+ expect(hasAllScope(SCOPE.READ.USER.API.ALL)).toBe(true);
|
|
|
+ expect(hasAllScope(SCOPE.WRITE.ADMIN.ALL)).toBe(true);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should return false for specific scopes', () => {
|
|
|
+ expect(hasAllScope(SCOPE.READ.USER.API.API_TOKEN)).toBe(false);
|
|
|
+ expect(hasAllScope(SCOPE.WRITE.USER.API.ACCESS_TOKEN)).toBe(false);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('extractAllScope', () => {
|
|
|
+ it('should extract all specific scopes from ALL scope', () => {
|
|
|
+ const extracted = extractAllScope(SCOPE.READ.USER.API.ALL);
|
|
|
+ expect(extracted).toContain(SCOPE.READ.USER.API.API_TOKEN);
|
|
|
+ expect(extracted).toContain(SCOPE.READ.USER.API.ACCESS_TOKEN);
|
|
|
+ expect(extracted).not.toContain(SCOPE.READ.USER.API.ALL);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should return array with single scope for specific scope', () => {
|
|
|
+ const scope = SCOPE.READ.USER.API.API_TOKEN;
|
|
|
+ const extracted = extractAllScope(scope);
|
|
|
+ expect(extracted).toEqual([scope]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('extractScopes', () => {
|
|
|
+ it('should return empty array for undefined input', () => {
|
|
|
+ expect(extractScopes()).toEqual([]);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should extract all implied scopes including READ permission for WRITE scopes', () => {
|
|
|
+ const scopes = [SCOPE.WRITE.USER.API.ACCESS_TOKEN];
|
|
|
+ const extracted = extractScopes(scopes);
|
|
|
+
|
|
|
+ expect(extracted).toContain(SCOPE.WRITE.USER.API.ACCESS_TOKEN);
|
|
|
+ expect(extracted).toContain(SCOPE.READ.USER.API.ACCESS_TOKEN);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should extract all specific scopes from ALL scope with implied permissions', () => {
|
|
|
+ const scopes = [SCOPE.WRITE.USER.API.ALL];
|
|
|
+ const extracted = extractScopes(scopes);
|
|
|
+
|
|
|
+ // Should include both WRITE and READ permissions for all specific scopes
|
|
|
+ expect(extracted).toContain(SCOPE.WRITE.USER.API.API_TOKEN);
|
|
|
+ expect(extracted).toContain(SCOPE.WRITE.USER.API.ACCESS_TOKEN);
|
|
|
+ expect(extracted).toContain(SCOPE.READ.USER.API.API_TOKEN);
|
|
|
+ expect(extracted).toContain(SCOPE.READ.USER.API.ACCESS_TOKEN);
|
|
|
+
|
|
|
+ // Should not include ALL scopes
|
|
|
+ expect(extracted).not.toContain(SCOPE.WRITE.USER.API.ALL);
|
|
|
+ expect(extracted).not.toContain(SCOPE.READ.USER.API.ALL);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should remove duplicate scopes', () => {
|
|
|
+ const scopes = [
|
|
|
+ SCOPE.WRITE.USER.API.ACCESS_TOKEN,
|
|
|
+ SCOPE.READ.USER.API.ACCESS_TOKEN, // This is implied by WRITE
|
|
|
+ ];
|
|
|
+ const extracted = extractScopes(scopes);
|
|
|
+
|
|
|
+ const accessTokenScopes = extracted.filter(s => s.endsWith('access_token'));
|
|
|
+ expect(accessTokenScopes).toHaveLength(2); // Only READ and WRITE, no duplicates
|
|
|
+ });
|
|
|
+ });
|
|
|
+});
|