azure-ad-provider.spec.ts•6.14 kB
import { AzureADOAuthProvider } from '../src/authz/providers/azure-ad.provider';
describe('Azure AD OAuth Provider', () => {
  describe('Provider Configuration', () => {
    it('should have correct name and display name', () => {
      expect(AzureADOAuthProvider.name).toBe('azure-ad');
      expect(AzureADOAuthProvider.displayName).toBe('Microsoft Azure AD');
    });
    it('should have correct scope configuration', () => {
      expect(AzureADOAuthProvider.scope).toEqual([
        'openid',
        'profile',
        'email',
        'User.Read',
      ]);
    });
    it('should generate correct strategy options', () => {
      const options = AzureADOAuthProvider.strategyOptions({
        serverUrl: 'https://example.com',
        clientId: 'test-client-id',
        clientSecret: 'test-client-secret',
        callbackPath: 'auth/callback',
      });
      expect(options).toEqual({
        clientID: 'test-client-id',
        clientSecret: 'test-client-secret',
        callbackURL: 'https://example.com/auth/callback',
        tenant: 'common',
        resource: 'https://graph.microsoft.com/',
      });
    });
    it('should normalize callback URL correctly', () => {
      const options1 = AzureADOAuthProvider.strategyOptions({
        serverUrl: 'https://example.com/',
        clientId: 'test',
        clientSecret: 'test',
        callbackPath: '/auth/callback',
      });
      const options2 = AzureADOAuthProvider.strategyOptions({
        serverUrl: 'https://example.com',
        clientId: 'test',
        clientSecret: 'test',
        callbackPath: 'auth/callback',
      });
      expect(options1.callbackURL).toBe('https://example.com/auth/callback');
      expect(options2.callbackURL).toBe('https://example.com/auth/callback');
    });
  });
  describe('Profile Mapping', () => {
    it('should correctly map Azure AD profile with _json', () => {
      const mockProfile = {
        id: 'azure-user-123',
        _json: {
          id: 'azure-user-123',
          userPrincipalName: 'john.doe@company.com',
          displayName: 'John Doe',
          mail: 'john.doe@company.com',
          photo: 'https://graph.microsoft.com/photo.jpg',
        },
      };
      const mappedProfile = AzureADOAuthProvider.profileMapper(mockProfile);
      expect(mappedProfile).toEqual({
        id: 'azure-user-123',
        username: 'john.doe@company.com',
        email: 'john.doe@company.com',
        displayName: 'John Doe',
        avatarUrl: 'https://graph.microsoft.com/photo.jpg',
        raw: mockProfile,
      });
    });
    it('should correctly map Azure AD profile without _json', () => {
      const mockProfile = {
        id: 'azure-user-456',
        userPrincipalName: 'jane.smith@company.com',
        displayName: 'Jane Smith',
        mail: 'jane.smith@company.com',
      };
      const mappedProfile = AzureADOAuthProvider.profileMapper(mockProfile);
      expect(mappedProfile).toEqual({
        id: 'azure-user-456',
        username: 'jane.smith@company.com',
        email: 'jane.smith@company.com',
        displayName: 'Jane Smith',
        avatarUrl: undefined,
        raw: mockProfile,
      });
    });
    it('should handle profile with alternative field names', () => {
      const mockProfile = {
        id: 'azure-user-789',
        oid: 'azure-oid-789', // Alternative ID field
        preferred_username: 'preferred.user@company.com',
        name: 'Alternative Name',
        email: 'alt.email@company.com',
      };
      const mappedProfile = AzureADOAuthProvider.profileMapper(mockProfile);
      expect(mappedProfile.id).toBe('azure-user-789');
      expect(mappedProfile.username).toBe('preferred.user@company.com');
      expect(mappedProfile.email).toBe('alt.email@company.com');
      expect(mappedProfile.displayName).toBe('Alternative Name');
    });
    it('should handle profile with missing optional fields', () => {
      const mockProfile = {
        id: 'azure-user-minimal',
      };
      const mappedProfile = AzureADOAuthProvider.profileMapper(mockProfile);
      expect(mappedProfile.id).toBe('azure-user-minimal');
      expect(mappedProfile.username).toBeUndefined();
      expect(mappedProfile.email).toBeUndefined();
      expect(mappedProfile.displayName).toBeUndefined();
      expect(mappedProfile.avatarUrl).toBeUndefined();
      expect(mappedProfile.raw).toBe(mockProfile);
    });
    it('should prioritize _json fields over root fields', () => {
      const mockProfile = {
        id: 'root-id',
        userPrincipalName: 'root@example.com',
        _json: {
          id: 'json-id',
          userPrincipalName: 'json@example.com',
          displayName: 'JSON User',
        },
      };
      const mappedProfile = AzureADOAuthProvider.profileMapper(mockProfile);
      expect(mappedProfile.id).toBe('json-id');
      expect(mappedProfile.username).toBe('json@example.com');
      expect(mappedProfile.displayName).toBe('JSON User');
    });
    it('should handle profile with passport emails array fallback', () => {
      const mockProfile = {
        id: 'passport-user',
        emails: [{ value: 'passport@example.com' }],
        username: 'passport-username',
      };
      const mappedProfile = AzureADOAuthProvider.profileMapper(mockProfile);
      expect(mappedProfile.id).toBe('passport-user');
      expect(mappedProfile.username).toBe('passport-username');
      expect(mappedProfile.email).toBe('passport@example.com');
    });
    it('should handle profile with passport photos array fallback', () => {
      const mockProfile = {
        id: 'photo-user',
        photos: [{ value: 'https://example.com/photo.jpg' }],
      };
      const mappedProfile = AzureADOAuthProvider.profileMapper(mockProfile);
      expect(mappedProfile.id).toBe('photo-user');
      expect(mappedProfile.avatarUrl).toBe('https://example.com/photo.jpg');
    });
  });
  describe('Strategy Class', () => {
    it('should use the correct passport strategy', () => {
      expect(AzureADOAuthProvider.strategy).toBeDefined();
      expect(typeof AzureADOAuthProvider.strategy).toBe('function');
    });
  });
});