Skip to content

Commit 4480c85

Browse files
authored
test: get test case steps for all suites (#14191)
* test: get test case steps for all suites * test: explicitly returning a value
1 parent 45618e6 commit 4480c85

File tree

2 files changed

+131
-109
lines changed

2 files changed

+131
-109
lines changed

.github/workflows/ui-test-vscuse.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ jobs:
172172
AZURE_DEVOPS_ORG_URL: "https://dev.azure.com/msazure/"
173173
AZURE_DEVOPS_PROJECT: "Microsoft Teams Extensibility"
174174
AZURE_DEVOPS_TEST_PLAN_ID: "33256964"
175-
AZURE_DEVOPS_TEST_SUITE_ID: "33256965"
176175
run: npx ts-node ./scripts/fetch-test-plan-test-cases.ts vscuse/agent_cases
177176

178177

packages/tests/scripts/fetch-test-plan-test-cases.ts

Lines changed: 131 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import * as azdev from "azure-devops-node-api";
22
import { AzureCliCredential } from "@azure/identity";
3+
import * as TestPlanApi from "azure-devops-node-api/TestPlanApi";
4+
import * as TestInterfaces from "azure-devops-node-api/interfaces/TestPlanInterfaces";
35
import * as fs from "fs";
46
import * as path from "path";
57

@@ -21,14 +23,9 @@ async function run() {
2123
"AZURE_DEVOPS_TEST_PLAN_ID:",
2224
process.env.AZURE_DEVOPS_TEST_PLAN_ID
2325
);
24-
console.log(
25-
"AZURE_DEVOPS_TEST_SUITE_ID:",
26-
process.env.AZURE_DEVOPS_TEST_SUITE_ID
27-
);
2826
const orgUrl = process.env.AZURE_DEVOPS_ORG_URL!;
2927
const project = process.env.AZURE_DEVOPS_PROJECT!;
3028
const planId = parseInt(process.env.AZURE_DEVOPS_TEST_PLAN_ID!);
31-
const suiteId = parseInt(process.env.AZURE_DEVOPS_TEST_SUITE_ID!);
3229

3330
// Get Azure AD token using Azure CLI credential
3431
const credential = new AzureCliCredential();
@@ -47,126 +44,152 @@ async function run() {
4744
const testApi = await connection.getTestApi();
4845
console.log("Test API client initialized successfully");
4946

50-
const testCases = await testApi.getTestCases(project, planId, suiteId);
51-
console.log("Test cases fetched successfully");
52-
console.log(
53-
`Found ${testCases.length} test cases in plan ${planId}, suite ${suiteId}`
54-
);
55-
for (const tc of testCases) {
56-
if (tc.testCase) {
57-
console.log(`Test case - ${tc.testCase.id}`);
58-
59-
// Fetch the work item JSON from the url
60-
if (tc.testCase.url) {
61-
try {
62-
// Use the Azure AD token for authentication
63-
const response = await fetch(tc.testCase.url, {
64-
headers: {
65-
Authorization: `Bearer ${token.token}`,
66-
"Content-Type": "application/json",
67-
},
68-
});
69-
if (!response.ok) {
70-
console.error(
71-
`Failed to fetch work item: ${tc.testCase.url}, status: ${response.status}`
72-
);
73-
continue;
74-
}
75-
76-
// Define a minimal type for workItem
77-
type WorkItem = {
78-
fields?: {
79-
[key: string]: any;
80-
};
81-
};
82-
const workItem = (await response.json()) as WorkItem;
83-
84-
// The content fianlly to write into the file
85-
const outputLines: string[] = [];
47+
const suites = await getTestSuitesForPlan(connection, project, planId);
48+
if (suites) {
49+
for (const suite of suites) {
50+
const suiteId = suite.id;
51+
console.log("AZURE_DEVOPS_TEST_SUITE_ID:", suiteId);
52+
const testCases = await testApi.getTestCases(project, planId, suiteId);
53+
console.log("Test cases fetched successfully");
54+
console.log(
55+
`Found ${testCases.length} test cases in plan ${planId}, suite ${suiteId}`
56+
);
57+
for (const tc of testCases) {
58+
if (tc.testCase) {
59+
console.log(`Test case - ${tc.testCase.id}`);
8660

87-
// Get the URL of the work item
88-
outputLines.push(
89-
`#URL: https://msazure.visualstudio.com/Microsoft%20Teams%20Extensibility/_workitems/edit/${tc.testCase.id}`
90-
);
91-
92-
// Get the title of the work itme
93-
const title = workItem.fields?.["System.Title"];
94-
if (title) {
95-
outputLines.push(`#Title: ${title}`);
96-
}
61+
// Fetch the work item JSON from the url
62+
if (tc.testCase.url) {
63+
try {
64+
// Use the Azure AD token for authentication
65+
const response = await fetch(tc.testCase.url, {
66+
headers: {
67+
Authorization: `Bearer ${token.token}`,
68+
"Content-Type": "application/json",
69+
},
70+
});
71+
if (!response.ok) {
72+
console.error(
73+
`Failed to fetch work item: ${tc.testCase.url}, status: ${response.status}`
74+
);
75+
continue;
76+
}
9777

98-
// Get the author of the work item
99-
const assignedTo = workItem.fields?.["System.AssignedTo"];
100-
const uniqueName =
101-
assignedTo && typeof assignedTo === "object"
102-
? assignedTo.uniqueName
103-
: undefined;
104-
if (uniqueName) {
105-
outputLines.push(`#Author: ${uniqueName}`);
106-
}
78+
// Define a minimal type for workItem
79+
type WorkItem = {
80+
fields?: {
81+
[key: string]: any;
82+
};
83+
};
84+
const workItem = (await response.json()) as WorkItem;
10785

108-
//if (tags && tags.includes("VSCUSE")) {
109-
const steps = workItem.fields?.["Microsoft.VSTS.TCM.Steps"];
110-
if (typeof steps === "string") {
111-
const stepBlocks = steps.match(/<step[\s\S]*?<\/step>/gi) || [];
86+
// The content fianlly to write into the file
87+
const outputLines: string[] = [];
11288

113-
stepBlocks.forEach((stepBlock, idx) => {
114-
const paramMatch = stepBlock.match(
115-
/<parameterizedString[^>]*>([\s\S]*?)<\/parameterizedString>/i
89+
// Get the URL of the work item
90+
outputLines.push(
91+
`#URL: https://msazure.visualstudio.com/Microsoft%20Teams%20Extensibility/_workitems/edit/${tc.testCase.id}`
11692
);
117-
let text = "";
118-
if (paramMatch && paramMatch[1]) {
119-
const html = paramMatch[1]
120-
.replace(/&lt;/g, "<")
121-
.replace(/&gt;/g, ">");
122-
const pMatch =
123-
html.match(/<p>([\s\S]*?)<\/p>/i) ||
124-
html.match(/<P>([\s\S]*?)<\/P>/i);
125-
if (pMatch && pMatch[1]) {
126-
text = pMatch[1].replace(/<[^>]+>/g, "").trim();
127-
}
93+
94+
// Get the title of the work itme
95+
const title = workItem.fields?.["System.Title"];
96+
if (title) {
97+
outputLines.push(`#Title: ${title}`);
12898
}
129-
if (!text) {
130-
const match =
131-
stepBlock.match(/<p>([\s\S]*?)<\/p>/i) ||
132-
stepBlock.match(/<P>([\s\S]*?)<\/P>/i);
133-
if (match && match[1]) {
134-
text = match[1].replace(/<[^>]+>/g, "").trim();
135-
}
99+
100+
// Get the author of the work item
101+
const assignedTo = workItem.fields?.["System.AssignedTo"];
102+
const uniqueName =
103+
assignedTo && typeof assignedTo === "object"
104+
? assignedTo.uniqueName
105+
: undefined;
106+
if (uniqueName) {
107+
outputLines.push(`#Author: ${uniqueName}`);
136108
}
137-
if (text) {
138-
outputLines.push(text);
109+
110+
//if (tags && tags.includes("VSCUSE")) {
111+
const steps = workItem.fields?.["Microsoft.VSTS.TCM.Steps"];
112+
if (typeof steps === "string") {
113+
const stepBlocks = steps.match(/<step[\s\S]*?<\/step>/gi) || [];
114+
115+
stepBlocks.forEach((stepBlock, idx) => {
116+
const paramMatch = stepBlock.match(
117+
/<parameterizedString[^>]*>([\s\S]*?)<\/parameterizedString>/i
118+
);
119+
let text = "";
120+
if (paramMatch && paramMatch[1]) {
121+
const html = paramMatch[1]
122+
.replace(/&lt;/g, "<")
123+
.replace(/&gt;/g, ">");
124+
const pMatch =
125+
html.match(/<p>([\s\S]*?)<\/p>/i) ||
126+
html.match(/<P>([\s\S]*?)<\/P>/i);
127+
if (pMatch && pMatch[1]) {
128+
text = pMatch[1].replace(/<[^>]+>/g, "").trim();
129+
}
130+
}
131+
if (!text) {
132+
const match =
133+
stepBlock.match(/<p>([\s\S]*?)<\/p>/i) ||
134+
stepBlock.match(/<P>([\s\S]*?)<\/P>/i);
135+
if (match && match[1]) {
136+
text = match[1].replace(/<[^>]+>/g, "").trim();
137+
}
138+
}
139+
if (text) {
140+
outputLines.push(text);
141+
}
142+
});
143+
const filePath = path.join(outputDir, `${tc.testCase.id}.txt`);
144+
fs.writeFileSync(filePath, outputLines.join("\n"), {
145+
encoding: "utf8",
146+
});
147+
console.log(
148+
`Wrote steps for test case ${tc.testCase.id} to ${filePath}`
149+
);
150+
console.log(
151+
`The file content is: \n${outputLines.join(
152+
"\n"
153+
)} \n [End of file]`
154+
);
155+
} else {
156+
console.log(`The type is: ${typeof steps}`);
139157
}
140-
});
141-
const filePath = path.join(outputDir, `${tc.testCase.id}.txt`);
142-
fs.writeFileSync(filePath, outputLines.join("\n"), {
143-
encoding: "utf8",
144-
});
145-
console.log(
146-
`Wrote steps for test case ${tc.testCase.id} to ${filePath}`
147-
);
148-
console.log(
149-
`The file content is: \n${outputLines.join(
150-
"\n"
151-
)} \n [End of file]`
152-
);
153-
} else {
154-
console.log(`The type is: ${typeof steps}`);
158+
//}
159+
} catch (err) {
160+
console.error(
161+
`Error fetching work item for test case ${tc.testCase.id}:`,
162+
err
163+
);
164+
}
155165
}
156-
//}
157-
} catch (err) {
166+
} else {
158167
console.error(
159-
`Error fetching work item for test case ${tc.testCase.id}:`,
160-
err
168+
`- Warning: Test case is undefined or missing details.`
161169
);
162170
}
163171
}
164-
} else {
165-
console.error(`- Warning: Test case is undefined or missing details.`);
166172
}
167173
}
168174
}
169175

176+
async function getTestSuitesForPlan(
177+
connection: azdev.WebApi,
178+
project: string,
179+
planId: number
180+
): Promise<TestInterfaces.TestSuite[] | undefined> {
181+
try {
182+
const testPlanApi: TestPlanApi.ITestPlanApi =
183+
await connection.getTestPlanApi();
184+
const suites: TestInterfaces.TestSuite[] =
185+
await testPlanApi.getTestSuitesForPlan(project, planId);
186+
return suites;
187+
} catch (err) {
188+
console.error("Error retrieving test suites:", err);
189+
return undefined;
190+
}
191+
}
192+
170193
run().catch((err) => {
171194
console.error("Error:", err);
172195
process.exit(1);

0 commit comments

Comments
 (0)