Azure DevOps MCP Server

import { WebApi } from 'azure-devops-node-api'; import { createAuthenticatedClient, isValidPatFormat } from '../../../src/api/auth'; import { AzureDevOpsAuthenticationError } from '../../../src/api/errors'; // Mock the azure-devops-node-api module jest.mock('azure-devops-node-api'); const MockWebApi = WebApi as jest.MockedClass<typeof WebApi>; describe('auth', () => { beforeEach(() => { jest.clearAllMocks(); }); describe('createAuthenticatedClient', () => { it('should throw error if PAT is missing', async () => { await expect(createAuthenticatedClient({ pat: '', orgUrl: 'https://dev.azure.com/org' })).rejects.toThrow(AzureDevOpsAuthenticationError); }); it('should throw error if organization URL is missing', async () => { await expect(createAuthenticatedClient({ pat: 'validpat', orgUrl: '' })).rejects.toThrow(AzureDevOpsAuthenticationError); }); it('should create WebApi client with correct configuration', async () => { // Mock getLocationsApi() which is used to test the connection const mockGetLocationsApi = jest.fn().mockResolvedValue({}); MockWebApi.mockImplementation(() => ({ getLocationsApi: mockGetLocationsApi } as any)); const config = { pat: 'validpat', orgUrl: 'https://dev.azure.com/org' }; const client = await createAuthenticatedClient(config); expect(MockWebApi).toHaveBeenCalledTimes(1); expect(mockGetLocationsApi).toHaveBeenCalledTimes(1); expect(client).toBeDefined(); }); it('should throw authentication error if API call fails', async () => { const mockGetLocationsApi = jest.fn().mockRejectedValue(new Error('API Error')); MockWebApi.mockImplementation(() => ({ getLocationsApi: mockGetLocationsApi } as any)); const config = { pat: 'validpat', orgUrl: 'https://dev.azure.com/org' }; await expect(createAuthenticatedClient(config)) .rejects .toThrow(AzureDevOpsAuthenticationError); }); }); describe('isValidPatFormat', () => { it('should return false for empty PAT', () => { expect(isValidPatFormat('')).toBe(false); }); it('should return false for PAT shorter than 64 characters', () => { expect(isValidPatFormat('short')).toBe(false); }); it('should return false for non-base64 PAT', () => { expect(isValidPatFormat('!@#$%^&*'.repeat(8))).toBe(false); }); it('should return true for valid base64 PAT', () => { // Create a valid base64 string of sufficient length const validPat = Buffer.from('a'.repeat(64)).toString('base64'); expect(isValidPatFormat(validPat)).toBe(true); }); }); });