@tiberriver256/mcp-server-azure-devops
Version:
Azure DevOps reference server for the Model Context Protocol (MCP)
219 lines • 8.17 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const feature_1 = require("./feature");
const client_factory_1 = require("../../../shared/auth/client-factory");
const errors_1 = require("../../../shared/errors");
// Mock the AzureDevOpsClient
jest.mock('../../../shared/auth/client-factory');
describe('updatePullRequest', () => {
const mockGetPullRequestById = jest.fn();
const mockUpdatePullRequest = jest.fn();
const mockUpdateWorkItem = jest.fn();
const mockGetWorkItem = jest.fn();
// Mock Git API
const mockGitApi = {
getPullRequestById: mockGetPullRequestById,
updatePullRequest: mockUpdatePullRequest,
};
// Mock Work Item Tracking API
const mockWorkItemTrackingApi = {
updateWorkItem: mockUpdateWorkItem,
getWorkItem: mockGetWorkItem,
};
// Mock connection
const mockConnection = {
getGitApi: jest.fn().mockResolvedValue(mockGitApi),
getWorkItemTrackingApi: jest
.fn()
.mockResolvedValue(mockWorkItemTrackingApi),
};
const mockAzureDevopsClient = {
getWebApiClient: jest.fn().mockResolvedValue(mockConnection),
// ...other properties if needed
};
beforeEach(() => {
jest.clearAllMocks();
client_factory_1.AzureDevOpsClient.mockImplementation(() => mockAzureDevopsClient);
});
it('should throw error when pull request does not exist', async () => {
mockGetPullRequestById.mockResolvedValueOnce(null);
await expect((0, feature_1.updatePullRequest)({
projectId: 'project-1',
repositoryId: 'repo1',
pullRequestId: 123,
})).rejects.toThrow(errors_1.AzureDevOpsError);
});
it('should update the pull request title and description', async () => {
mockGetPullRequestById.mockResolvedValueOnce({
repository: { id: 'repo1' },
});
mockUpdatePullRequest.mockResolvedValueOnce({
title: 'Updated Title',
description: 'Updated Description',
});
const result = await (0, feature_1.updatePullRequest)({
projectId: 'project-1',
repositoryId: 'repo1',
pullRequestId: 123,
title: 'Updated Title',
description: 'Updated Description',
});
expect(mockUpdatePullRequest).toHaveBeenCalledWith({
title: 'Updated Title',
description: 'Updated Description',
}, 'repo1', 123, 'project-1');
expect(result).toEqual({
title: 'Updated Title',
description: 'Updated Description',
});
});
it('should update the pull request status when status is provided', async () => {
mockGetPullRequestById.mockResolvedValueOnce({
repository: { id: 'repo1' },
});
mockUpdatePullRequest.mockResolvedValueOnce({
status: 2, // Abandoned
});
const result = await (0, feature_1.updatePullRequest)({
projectId: 'project-1',
repositoryId: 'repo1',
pullRequestId: 123,
status: 'abandoned',
});
expect(mockUpdatePullRequest).toHaveBeenCalledWith({
status: 2, // Abandoned value
}, 'repo1', 123, 'project-1');
expect(result).toEqual({
status: 2, // Abandoned
});
});
it('should throw error for invalid status', async () => {
mockGetPullRequestById.mockResolvedValueOnce({
repository: { id: 'repo1' },
});
await expect((0, feature_1.updatePullRequest)({
projectId: 'project-1',
repositoryId: 'repo1',
pullRequestId: 123,
status: 'invalid-status',
})).rejects.toThrow(errors_1.AzureDevOpsError);
});
it('should update the pull request draft status', async () => {
mockGetPullRequestById.mockResolvedValueOnce({
repository: { id: 'repo1' },
});
mockUpdatePullRequest.mockResolvedValueOnce({
isDraft: true,
});
const result = await (0, feature_1.updatePullRequest)({
projectId: 'project-1',
repositoryId: 'repo1',
pullRequestId: 123,
isDraft: true,
});
expect(mockUpdatePullRequest).toHaveBeenCalledWith({
isDraft: true,
}, 'repo1', 123, 'project-1');
expect(result).toEqual({
isDraft: true,
});
});
it('should include additionalProperties in the update', async () => {
mockGetPullRequestById.mockResolvedValueOnce({
repository: { id: 'repo1' },
});
mockUpdatePullRequest.mockResolvedValueOnce({
title: 'Title',
customProperty: 'custom value',
});
const result = await (0, feature_1.updatePullRequest)({
projectId: 'project-1',
repositoryId: 'repo1',
pullRequestId: 123,
additionalProperties: {
customProperty: 'custom value',
},
});
expect(mockUpdatePullRequest).toHaveBeenCalledWith({
customProperty: 'custom value',
}, 'repo1', 123, 'project-1');
expect(result).toEqual({
title: 'Title',
customProperty: 'custom value',
});
});
it('should handle work item links', async () => {
// Define the artifactId that will be used
const artifactId = 'vstfs:///Git/PullRequestId/project-1/repo1/123';
mockGetPullRequestById.mockResolvedValueOnce({
repository: { id: 'repo1' },
artifactId: artifactId, // Add the artifactId to the mock response
});
mockUpdatePullRequest.mockResolvedValueOnce({
pullRequestId: 123,
repository: { id: 'repo1' },
artifactId: artifactId,
});
// Mocks for work items to remove
mockGetWorkItem.mockResolvedValueOnce({
relations: [
{
rel: 'ArtifactLink',
url: artifactId, // Use the same artifactId here
attributes: {
name: 'Pull Request',
},
},
],
});
mockGetWorkItem.mockResolvedValueOnce({
relations: [
{
rel: 'ArtifactLink',
url: artifactId, // Use the same artifactId here
attributes: {
name: 'Pull Request',
},
},
],
});
await (0, feature_1.updatePullRequest)({
projectId: 'project-1',
repositoryId: 'repo1',
pullRequestId: 123,
addWorkItemIds: [456, 789],
removeWorkItemIds: [101, 202],
});
// Check that updateWorkItem was called for adding work items
expect(mockUpdateWorkItem).toHaveBeenCalledTimes(4); // 2 for add, 2 for remove
expect(mockUpdateWorkItem).toHaveBeenCalledWith(null, [
{
op: 'add',
path: '/relations/-',
value: {
rel: 'ArtifactLink',
url: 'vstfs:///Git/PullRequestId/project-1/repo1/123',
attributes: {
name: 'Pull Request',
},
},
},
], 456);
// Check for removing work items
expect(mockUpdateWorkItem).toHaveBeenCalledWith(null, [
{
op: 'remove',
path: '/relations/0',
},
], 101);
});
it('should wrap unexpected errors in a friendly error message', async () => {
mockGetPullRequestById.mockRejectedValueOnce(new Error('Unexpected'));
await expect((0, feature_1.updatePullRequest)({
projectId: 'project-1',
repositoryId: 'repo1',
pullRequestId: 123,
})).rejects.toThrow(errors_1.AzureDevOpsError);
});
});
//# sourceMappingURL=feature.spec.unit.js.map