Skip to main content
Glama

Azure DevOps MCP Server

feature.spec.unit.ts9.07 kB
import { getRepositoryDetails } from './feature'; import { GitVersionType } from 'azure-devops-node-api/interfaces/GitInterfaces'; import { AzureDevOpsError, AzureDevOpsResourceNotFoundError, } from '../../../shared/errors'; import { GitRepository, GitBranchStats, GitRef } from '../types'; // Unit tests should only focus on isolated logic // No real connections, HTTP requests, or dependencies describe('getRepositoryDetails unit', () => { // Mock repository data const mockRepository: GitRepository = { id: 'repo-id', name: 'test-repo', url: 'https://dev.azure.com/org/project/_apis/git/repositories/repo-id', project: { id: 'project-id', name: 'test-project', }, defaultBranch: 'refs/heads/main', size: 1024, remoteUrl: 'https://dev.azure.com/org/project/_git/test-repo', sshUrl: 'git@ssh.dev.azure.com:v3/org/project/test-repo', webUrl: 'https://dev.azure.com/org/project/_git/test-repo', }; // Mock branch stats data const mockBranchStats: GitBranchStats[] = [ { name: 'refs/heads/main', aheadCount: 0, behindCount: 0, isBaseVersion: true, commit: { commitId: 'commit-id', author: { name: 'Test User', email: 'test@example.com', date: new Date(), }, committer: { name: 'Test User', email: 'test@example.com', date: new Date(), }, comment: 'Test commit', }, }, ]; // Mock refs data const mockRefs: GitRef[] = [ { name: 'refs/heads/main', objectId: 'commit-id', creator: { displayName: 'Test User', id: 'user-id', }, url: 'https://dev.azure.com/org/project/_apis/git/repositories/repo-id/refs/heads/main', }, ]; test('should return basic repository information when no additional options are specified', async () => { // Arrange const mockConnection: any = { getGitApi: jest.fn().mockImplementation(() => ({ getRepository: jest.fn().mockResolvedValue(mockRepository), })), }; // Act const result = await getRepositoryDetails(mockConnection, { projectId: 'test-project', repositoryId: 'test-repo', }); // Assert expect(result).toBeDefined(); expect(result.repository).toEqual(mockRepository); expect(result.statistics).toBeUndefined(); expect(result.refs).toBeUndefined(); }); test('should include branch statistics when includeStatistics is true', async () => { // Arrange const mockConnection: any = { getGitApi: jest.fn().mockImplementation(() => ({ getRepository: jest.fn().mockResolvedValue(mockRepository), getBranches: jest.fn().mockResolvedValue(mockBranchStats), })), }; // Act const result = await getRepositoryDetails(mockConnection, { projectId: 'test-project', repositoryId: 'test-repo', includeStatistics: true, }); // Assert expect(result).toBeDefined(); expect(result.repository).toEqual(mockRepository); expect(result.statistics).toBeDefined(); expect(result.statistics?.branches).toEqual(mockBranchStats); expect(result.refs).toBeUndefined(); }); test('should include refs when includeRefs is true', async () => { // Arrange const mockConnection: any = { getGitApi: jest.fn().mockImplementation(() => ({ getRepository: jest.fn().mockResolvedValue(mockRepository), getRefs: jest.fn().mockResolvedValue(mockRefs), })), }; // Act const result = await getRepositoryDetails(mockConnection, { projectId: 'test-project', repositoryId: 'test-repo', includeRefs: true, }); // Assert expect(result).toBeDefined(); expect(result.repository).toEqual(mockRepository); expect(result.statistics).toBeUndefined(); expect(result.refs).toBeDefined(); expect(result.refs?.value).toEqual(mockRefs); expect(result.refs?.count).toBe(mockRefs.length); }); test('should include both statistics and refs when both options are true', async () => { // Arrange const mockConnection: any = { getGitApi: jest.fn().mockImplementation(() => ({ getRepository: jest.fn().mockResolvedValue(mockRepository), getBranches: jest.fn().mockResolvedValue(mockBranchStats), getRefs: jest.fn().mockResolvedValue(mockRefs), })), }; // Act const result = await getRepositoryDetails(mockConnection, { projectId: 'test-project', repositoryId: 'test-repo', includeStatistics: true, includeRefs: true, }); // Assert expect(result).toBeDefined(); expect(result.repository).toEqual(mockRepository); expect(result.statistics).toBeDefined(); expect(result.statistics?.branches).toEqual(mockBranchStats); expect(result.refs).toBeDefined(); expect(result.refs?.value).toEqual(mockRefs); expect(result.refs?.count).toBe(mockRefs.length); }); test('should pass refFilter to getRefs when provided', async () => { // Arrange const getRefs = jest.fn().mockResolvedValue(mockRefs); const mockConnection: any = { getGitApi: jest.fn().mockImplementation(() => ({ getRepository: jest.fn().mockResolvedValue(mockRepository), getRefs, })), }; // Act await getRepositoryDetails(mockConnection, { projectId: 'test-project', repositoryId: 'test-repo', includeRefs: true, refFilter: 'heads/', }); // Assert expect(getRefs).toHaveBeenCalledWith( mockRepository.id, 'test-project', 'heads/', ); }); test('should pass branchName to getBranches when provided', async () => { // Arrange const getBranches = jest.fn().mockResolvedValue(mockBranchStats); const mockConnection: any = { getGitApi: jest.fn().mockImplementation(() => ({ getRepository: jest.fn().mockResolvedValue(mockRepository), getBranches, })), }; // Act await getRepositoryDetails(mockConnection, { projectId: 'test-project', repositoryId: 'test-repo', includeStatistics: true, branchName: 'main', }); // Assert expect(getBranches).toHaveBeenCalledWith( mockRepository.id, 'test-project', { version: 'main', versionType: GitVersionType.Branch, }, ); }); test('should propagate resource not found errors', async () => { // Arrange const mockConnection: any = { getGitApi: jest.fn().mockImplementation(() => ({ getRepository: jest.fn().mockResolvedValue(null), // Simulate repository not found })), }; // Act & Assert await expect( getRepositoryDetails(mockConnection, { projectId: 'test-project', repositoryId: 'non-existent-repo', }), ).rejects.toThrow(AzureDevOpsResourceNotFoundError); await expect( getRepositoryDetails(mockConnection, { projectId: 'test-project', repositoryId: 'non-existent-repo', }), ).rejects.toThrow( "Repository 'non-existent-repo' not found in project 'test-project'", ); }); test('should propagate custom errors when thrown internally', async () => { // Arrange const mockConnection: any = { getGitApi: jest.fn().mockImplementation(() => { throw new AzureDevOpsError('Custom error'); }), }; // Act & Assert await expect( getRepositoryDetails(mockConnection, { projectId: 'test-project', repositoryId: 'test-repo', }), ).rejects.toThrow(AzureDevOpsError); await expect( getRepositoryDetails(mockConnection, { projectId: 'test-project', repositoryId: 'test-repo', }), ).rejects.toThrow('Custom error'); }); test('should wrap unexpected errors in a friendly error message', async () => { // Arrange const mockConnection: any = { getGitApi: jest.fn().mockImplementation(() => { throw new Error('Unexpected error'); }), }; // Act & Assert await expect( getRepositoryDetails(mockConnection, { projectId: 'test-project', repositoryId: 'test-repo', }), ).rejects.toThrow('Failed to get repository details: Unexpected error'); }); test('should handle null refs gracefully', async () => { // Arrange const mockConnection: any = { getGitApi: jest.fn().mockImplementation(() => ({ getRepository: jest.fn().mockResolvedValue(mockRepository), getRefs: jest.fn().mockResolvedValue(null), // Simulate null refs })), }; // Act const result = await getRepositoryDetails(mockConnection, { projectId: 'test-project', repositoryId: 'test-repo', includeRefs: true, }); // Assert expect(result).toBeDefined(); expect(result.repository).toEqual(mockRepository); expect(result.refs).toBeDefined(); expect(result.refs?.value).toEqual([]); expect(result.refs?.count).toBe(0); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Tiberriver256/mcp-server-azure-devops'

If you have feedback or need assistance with the MCP directory API, please join our Discord server