Skip to content

Commit 3b23e90

Browse files
authored
test: add more test coverage for work items (#428)
add additional test coverage for missing code blocks in work items ## GitHub issue number ## **Associated Risks** N/A ## ✅ **PR Checklist** - [x] **I have read the [contribution guidelines](https://github.com/microsoft/azure-devops-mcp/blob/main/CONTRIBUTING.md)** - [ ] **I have read the [code of conduct guidelines](https://github.com/microsoft/azure-devops-mcp/blob/main/CODE_OF_CONDUCT.md)** - [x] Title of the pull request is clear and informative. - [x] 👌 Code hygiene - [x] 🔭 Telemetry added, updated, or N/A - [x] 📄 Documentation added, updated, or N/A - [x] 🛡️ Automated tests added, or N/A ## 🧪 **How did you test it?** re-run of automated tests
1 parent 0e2565c commit 3b23e90

File tree

1 file changed

+387
-0
lines changed

1 file changed

+387
-0
lines changed

test/src/tools/workitems.test.ts

Lines changed: 387 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2509,6 +2509,393 @@ describe("configureWorkItemTools", () => {
25092509
expect(result.content[0].text).toBe("Error adding artifact link to work item: API Error");
25102510
expect(result.isError).toBe(true);
25112511
});
2512+
2513+
// Tests to cover lines 929-973: URI building switch statement logic
2514+
it("should build Branch URI from components", async () => {
2515+
configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider);
2516+
2517+
const call = (server.tool as jest.Mock).mock.calls.find(([toolName]) => toolName === "wit_add_artifact_link");
2518+
if (!call) throw new Error("wit_add_artifact_link tool not registered");
2519+
const [, , , handler] = call;
2520+
2521+
const mockWorkItem = { id: 1234, fields: { "System.Title": "Test Item" } };
2522+
mockWorkItemTrackingApi.updateWorkItem.mockResolvedValue(mockWorkItem);
2523+
2524+
const params = {
2525+
workItemId: 1234,
2526+
project: "TestProject",
2527+
linkType: "Branch",
2528+
projectId: "project-guid",
2529+
repositoryId: "repo-guid",
2530+
branchName: "feature/test-branch",
2531+
};
2532+
2533+
const result = await handler(params);
2534+
2535+
expect(mockWorkItemTrackingApi.updateWorkItem).toHaveBeenCalledWith(
2536+
{},
2537+
[
2538+
{
2539+
op: "add",
2540+
path: "/relations/-",
2541+
value: {
2542+
rel: "ArtifactLink",
2543+
url: "vstfs:///Git/Ref/project-guid%2Frepo-guid%2FGBfeature%2Ftest-branch",
2544+
attributes: {
2545+
name: "Branch",
2546+
},
2547+
},
2548+
},
2549+
],
2550+
1234,
2551+
"TestProject"
2552+
);
2553+
2554+
const response = JSON.parse(result.content[0].text);
2555+
expect(response.success).toBe(true);
2556+
});
2557+
2558+
it("should return error for Branch link missing required parameters", async () => {
2559+
configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider);
2560+
2561+
const call = (server.tool as jest.Mock).mock.calls.find(([toolName]) => toolName === "wit_add_artifact_link");
2562+
if (!call) throw new Error("wit_add_artifact_link tool not registered");
2563+
const [, , , handler] = call;
2564+
2565+
const params = {
2566+
workItemId: 1234,
2567+
project: "TestProject",
2568+
linkType: "Branch",
2569+
projectId: "project-guid",
2570+
// Missing repositoryId and branchName
2571+
};
2572+
2573+
const result = await handler(params);
2574+
2575+
expect(result.isError).toBe(true);
2576+
expect(result.content[0].text).toBe("For 'Branch' links, 'projectId', 'repositoryId', and 'branchName' are required.");
2577+
});
2578+
2579+
it("should build Fixed in Commit URI from components", async () => {
2580+
configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider);
2581+
2582+
const call = (server.tool as jest.Mock).mock.calls.find(([toolName]) => toolName === "wit_add_artifact_link");
2583+
if (!call) throw new Error("wit_add_artifact_link tool not registered");
2584+
const [, , , handler] = call;
2585+
2586+
const mockWorkItem = { id: 1234, fields: { "System.Title": "Test Item" } };
2587+
mockWorkItemTrackingApi.updateWorkItem.mockResolvedValue(mockWorkItem);
2588+
2589+
const params = {
2590+
workItemId: 1234,
2591+
project: "TestProject",
2592+
linkType: "Fixed in Commit",
2593+
projectId: "project-guid",
2594+
repositoryId: "repo-guid",
2595+
commitId: "abc123def456",
2596+
comment: "Fixed in this commit",
2597+
};
2598+
2599+
const result = await handler(params);
2600+
2601+
expect(mockWorkItemTrackingApi.updateWorkItem).toHaveBeenCalledWith(
2602+
{},
2603+
[
2604+
{
2605+
op: "add",
2606+
path: "/relations/-",
2607+
value: {
2608+
rel: "ArtifactLink",
2609+
url: "vstfs:///Git/Commit/project-guid%2Frepo-guid%2Fabc123def456",
2610+
attributes: {
2611+
name: "Fixed in Commit",
2612+
comment: "Fixed in this commit",
2613+
},
2614+
},
2615+
},
2616+
],
2617+
1234,
2618+
"TestProject"
2619+
);
2620+
2621+
const response = JSON.parse(result.content[0].text);
2622+
expect(response.success).toBe(true);
2623+
});
2624+
2625+
it("should return error for Fixed in Commit link missing required parameters", async () => {
2626+
configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider);
2627+
2628+
const call = (server.tool as jest.Mock).mock.calls.find(([toolName]) => toolName === "wit_add_artifact_link");
2629+
if (!call) throw new Error("wit_add_artifact_link tool not registered");
2630+
const [, , , handler] = call;
2631+
2632+
const params = {
2633+
workItemId: 1234,
2634+
project: "TestProject",
2635+
linkType: "Fixed in Commit",
2636+
projectId: "project-guid",
2637+
// Missing repositoryId and commitId
2638+
};
2639+
2640+
const result = await handler(params);
2641+
2642+
expect(result.isError).toBe(true);
2643+
expect(result.content[0].text).toBe("For 'Fixed in Commit' links, 'projectId', 'repositoryId', and 'commitId' are required.");
2644+
});
2645+
2646+
it("should build Pull Request URI from components", async () => {
2647+
configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider);
2648+
2649+
const call = (server.tool as jest.Mock).mock.calls.find(([toolName]) => toolName === "wit_add_artifact_link");
2650+
if (!call) throw new Error("wit_add_artifact_link tool not registered");
2651+
const [, , , handler] = call;
2652+
2653+
const mockWorkItem = { id: 1234, fields: { "System.Title": "Test Item" } };
2654+
mockWorkItemTrackingApi.updateWorkItem.mockResolvedValue(mockWorkItem);
2655+
2656+
const params = {
2657+
workItemId: 1234,
2658+
project: "TestProject",
2659+
linkType: "Pull Request",
2660+
projectId: "project-guid",
2661+
repositoryId: "repo-guid",
2662+
pullRequestId: 42,
2663+
};
2664+
2665+
const result = await handler(params);
2666+
2667+
expect(mockWorkItemTrackingApi.updateWorkItem).toHaveBeenCalledWith(
2668+
{},
2669+
[
2670+
{
2671+
op: "add",
2672+
path: "/relations/-",
2673+
value: {
2674+
rel: "ArtifactLink",
2675+
url: "vstfs:///Git/PullRequestId/project-guid%2Frepo-guid%2F42",
2676+
attributes: {
2677+
name: "Pull Request",
2678+
},
2679+
},
2680+
},
2681+
],
2682+
1234,
2683+
"TestProject"
2684+
);
2685+
2686+
const response = JSON.parse(result.content[0].text);
2687+
expect(response.success).toBe(true);
2688+
});
2689+
2690+
it("should return error for Pull Request link missing required parameters", async () => {
2691+
configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider);
2692+
2693+
const call = (server.tool as jest.Mock).mock.calls.find(([toolName]) => toolName === "wit_add_artifact_link");
2694+
if (!call) throw new Error("wit_add_artifact_link tool not registered");
2695+
const [, , , handler] = call;
2696+
2697+
const params = {
2698+
workItemId: 1234,
2699+
project: "TestProject",
2700+
linkType: "Pull Request",
2701+
projectId: "project-guid",
2702+
repositoryId: "repo-guid",
2703+
// Missing pullRequestId
2704+
};
2705+
2706+
const result = await handler(params);
2707+
2708+
expect(result.isError).toBe(true);
2709+
expect(result.content[0].text).toBe("For 'Pull Request' links, 'projectId', 'repositoryId', and 'pullRequestId' are required.");
2710+
});
2711+
2712+
it("should build Build URI from components", async () => {
2713+
configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider);
2714+
2715+
const call = (server.tool as jest.Mock).mock.calls.find(([toolName]) => toolName === "wit_add_artifact_link");
2716+
if (!call) throw new Error("wit_add_artifact_link tool not registered");
2717+
const [, , , handler] = call;
2718+
2719+
const mockWorkItem = { id: 1234, fields: { "System.Title": "Test Item" } };
2720+
mockWorkItemTrackingApi.updateWorkItem.mockResolvedValue(mockWorkItem);
2721+
2722+
const params = {
2723+
workItemId: 1234,
2724+
project: "TestProject",
2725+
linkType: "Build",
2726+
buildId: 123,
2727+
};
2728+
2729+
const result = await handler(params);
2730+
2731+
expect(mockWorkItemTrackingApi.updateWorkItem).toHaveBeenCalledWith(
2732+
{},
2733+
[
2734+
{
2735+
op: "add",
2736+
path: "/relations/-",
2737+
value: {
2738+
rel: "ArtifactLink",
2739+
url: "vstfs:///Build/Build/123",
2740+
attributes: {
2741+
name: "Build",
2742+
},
2743+
},
2744+
},
2745+
],
2746+
1234,
2747+
"TestProject"
2748+
);
2749+
2750+
const response = JSON.parse(result.content[0].text);
2751+
expect(response.success).toBe(true);
2752+
});
2753+
2754+
it("should build Found in build URI from components", async () => {
2755+
configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider);
2756+
2757+
const call = (server.tool as jest.Mock).mock.calls.find(([toolName]) => toolName === "wit_add_artifact_link");
2758+
if (!call) throw new Error("wit_add_artifact_link tool not registered");
2759+
const [, , , handler] = call;
2760+
2761+
const mockWorkItem = { id: 1234, fields: { "System.Title": "Test Item" } };
2762+
mockWorkItemTrackingApi.updateWorkItem.mockResolvedValue(mockWorkItem);
2763+
2764+
const params = {
2765+
workItemId: 1234,
2766+
project: "TestProject",
2767+
linkType: "Found in build",
2768+
buildId: 456,
2769+
};
2770+
2771+
const result = await handler(params);
2772+
2773+
expect(mockWorkItemTrackingApi.updateWorkItem).toHaveBeenCalledWith(
2774+
{},
2775+
[
2776+
{
2777+
op: "add",
2778+
path: "/relations/-",
2779+
value: {
2780+
rel: "ArtifactLink",
2781+
url: "vstfs:///Build/Build/456",
2782+
attributes: {
2783+
name: "Found in build",
2784+
},
2785+
},
2786+
},
2787+
],
2788+
1234,
2789+
"TestProject"
2790+
);
2791+
2792+
const response = JSON.parse(result.content[0].text);
2793+
expect(response.success).toBe(true);
2794+
});
2795+
2796+
it("should build Integrated in build URI from components", async () => {
2797+
configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider);
2798+
2799+
const call = (server.tool as jest.Mock).mock.calls.find(([toolName]) => toolName === "wit_add_artifact_link");
2800+
if (!call) throw new Error("wit_add_artifact_link tool not registered");
2801+
const [, , , handler] = call;
2802+
2803+
const mockWorkItem = { id: 1234, fields: { "System.Title": "Test Item" } };
2804+
mockWorkItemTrackingApi.updateWorkItem.mockResolvedValue(mockWorkItem);
2805+
2806+
const params = {
2807+
workItemId: 1234,
2808+
project: "TestProject",
2809+
linkType: "Integrated in build",
2810+
buildId: 789,
2811+
};
2812+
2813+
const result = await handler(params);
2814+
2815+
expect(mockWorkItemTrackingApi.updateWorkItem).toHaveBeenCalledWith(
2816+
{},
2817+
[
2818+
{
2819+
op: "add",
2820+
path: "/relations/-",
2821+
value: {
2822+
rel: "ArtifactLink",
2823+
url: "vstfs:///Build/Build/789",
2824+
attributes: {
2825+
name: "Integrated in build",
2826+
},
2827+
},
2828+
},
2829+
],
2830+
1234,
2831+
"TestProject"
2832+
);
2833+
2834+
const response = JSON.parse(result.content[0].text);
2835+
expect(response.success).toBe(true);
2836+
});
2837+
2838+
it("should return error for build link types missing buildId", async () => {
2839+
configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider);
2840+
2841+
const call = (server.tool as jest.Mock).mock.calls.find(([toolName]) => toolName === "wit_add_artifact_link");
2842+
if (!call) throw new Error("wit_add_artifact_link tool not registered");
2843+
const [, , , handler] = call;
2844+
2845+
const params = {
2846+
workItemId: 1234,
2847+
project: "TestProject",
2848+
linkType: "Build",
2849+
// Missing buildId
2850+
};
2851+
2852+
const result = await handler(params);
2853+
2854+
expect(result.isError).toBe(true);
2855+
expect(result.content[0].text).toBe("For 'Build' links, 'buildId' is required.");
2856+
});
2857+
2858+
it("should return error for unsupported link type in URI building", async () => {
2859+
configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider);
2860+
2861+
const call = (server.tool as jest.Mock).mock.calls.find(([toolName]) => toolName === "wit_add_artifact_link");
2862+
if (!call) throw new Error("wit_add_artifact_link tool not registered");
2863+
const [, , , handler] = call;
2864+
2865+
const params = {
2866+
workItemId: 1234,
2867+
project: "TestProject",
2868+
linkType: "Model Link", // Unsupported link type for URI building
2869+
};
2870+
2871+
const result = await handler(params);
2872+
2873+
expect(result.isError).toBe(true);
2874+
expect(result.content[0].text).toBe("URI building from components is not supported for link type 'Model Link'. Please provide the full 'artifactUri' instead.");
2875+
});
2876+
2877+
it("should handle null response from updateWorkItem (line 1000 coverage)", async () => {
2878+
configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider);
2879+
2880+
const call = (server.tool as jest.Mock).mock.calls.find(([toolName]) => toolName === "wit_add_artifact_link");
2881+
if (!call) throw new Error("wit_add_artifact_link tool not registered");
2882+
const [, , , handler] = call;
2883+
2884+
// Mock updateWorkItem to return null
2885+
mockWorkItemTrackingApi.updateWorkItem.mockResolvedValue(null);
2886+
2887+
const params = {
2888+
workItemId: 1234,
2889+
project: "TestProject",
2890+
artifactUri: "vstfs:///Git/Ref/12341234-1234-1234-1234-123412341234%2F12341234-1234-1234-1234-123412341234%2FGBmain",
2891+
linkType: "Branch",
2892+
};
2893+
2894+
const result = await handler(params);
2895+
2896+
expect(result.isError).toBe(true);
2897+
expect(result.content[0].text).toBe("Work item update failed");
2898+
});
25122899
});
25132900
});
25142901
});

0 commit comments

Comments
 (0)