@nbakka/mcp-appium 3.0.10 → 3.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/server.js CHANGED
@@ -837,22 +837,46 @@ tool(
837
837
 
838
838
  // Process test cases - handle the specific format properly
839
839
  const processedTestCases = testCases.map((testCase, index) => {
840
- // Each testCase is an array like ["title", "description", "status", "originalCase"]
841
840
  if (Array.isArray(testCase)) {
842
- return {
843
- title: testCase[0] || `Test Case ${index + 1}`,
844
- description: testCase[1] || '',
845
- status: testCase[2] || 'New',
846
- originalCase: testCase[3] || '',
847
- index: index
848
- };
841
+ const arrayLength = testCase.length;
842
+
843
+ if (arrayLength === 4) {
844
+ // Modify case: ["original title", "new description", "Modify", "SCRUM-TC-1"]
845
+ return {
846
+ originalTitle: testCase[0] || `Test Case ${index + 1}`,
847
+ newDescription: testCase[1] || '',
848
+ status: testCase[2] || 'Modify',
849
+ testId: testCase[3] || '',
850
+ index: index
851
+ };
852
+ } else if (arrayLength === 3) {
853
+ // Remove case: ["title", "Remove", "SCRUM-TC-2"]
854
+ return {
855
+ title: testCase[0] || `Test Case ${index + 1}`,
856
+ status: testCase[1] || 'Remove',
857
+ testId: testCase[2] || '',
858
+ index: index
859
+ };
860
+ } else if (arrayLength === 2) {
861
+ // New case: ["title", "New"]
862
+ return {
863
+ title: testCase[0] || `Test Case ${index + 1}`,
864
+ status: testCase[1] || 'New',
865
+ index: index
866
+ };
867
+ } else {
868
+ // Fallback for unexpected format
869
+ return {
870
+ title: testCase[0] || `Test Case ${index + 1}`,
871
+ status: 'New',
872
+ index: index
873
+ };
874
+ }
849
875
  } else {
850
- // Fallback for unexpected format
876
+ // Fallback for non-array format
851
877
  return {
852
878
  title: String(testCase) || `Test Case ${index + 1}`,
853
- description: '',
854
879
  status: 'New',
855
- originalCase: '',
856
880
  index: index
857
881
  };
858
882
  }
@@ -864,12 +888,12 @@ tool(
864
888
 
865
889
  if (status === 'modify') {
866
890
  // For modify cases, show original → changed format
867
- return `${testCase.title}\n\nOriginal: ${testCase.originalCase || 'Not specified'}\nChanged to: ${testCase.description || 'Not specified'}`;
891
+ return `Original: ${testCase.originalTitle}\nChanged to: ${testCase.newDescription}`;
868
892
  } else if (status === 'remove') {
869
- // For remove cases, just show the title
893
+ // For remove cases, show the title
870
894
  return testCase.title;
871
895
  } else {
872
- // For new cases, just show the title
896
+ // For new cases, show the title
873
897
  return testCase.title;
874
898
  }
875
899
  };
@@ -1176,10 +1200,10 @@ tool(
1176
1200
 
1177
1201
  // Create proper label and test ID display for modify/remove cases
1178
1202
  let labelAndIdDisplay = '';
1179
- if (testCase.status.toLowerCase() === 'modify' && testCase.originalCase) {
1180
- labelAndIdDisplay = `<div style="margin-bottom: 8px; font-weight: 600; color: #856404; font-size: 13px;">Modify - ${testCase.originalCase}</div>`;
1181
- } else if (testCase.status.toLowerCase() === 'remove' && testCase.originalCase) {
1182
- labelAndIdDisplay = `<div style="margin-bottom: 8px; font-weight: 600; color: #721c24; font-size: 13px;">Remove - ${testCase.originalCase}</div>`;
1203
+ if (testCase.status.toLowerCase() === 'modify' && testCase.testId) {
1204
+ labelAndIdDisplay = `<div style="margin-bottom: 8px; font-weight: 600; color: #856404; font-size: 13px;">Modify - ${testCase.testId}</div>`;
1205
+ } else if (testCase.status.toLowerCase() === 'remove' && testCase.testId) {
1206
+ labelAndIdDisplay = `<div style="margin-bottom: 8px; font-weight: 600; color: #721c24; font-size: 13px;">Remove - ${testCase.testId}</div>`;
1183
1207
  }
1184
1208
 
1185
1209
  return `
@@ -1245,7 +1269,9 @@ tool(
1245
1269
  const status = originalTestCase.status.toLowerCase();
1246
1270
 
1247
1271
  if (status === 'modify') {
1248
- resetValue = originalTestCase.title + '\\n\\nOriginal: ' + (originalTestCase.originalCase || 'Not specified') + '\\nChanged to: ' + (originalTestCase.description || 'Not specified');
1272
+ resetValue = 'Original: ' + originalTestCase.originalTitle + '\\nChanged to: ' + originalTestCase.newDescription;
1273
+ } else if (status === 'remove') {
1274
+ resetValue = originalTestCase.title;
1249
1275
  } else {
1250
1276
  resetValue = originalTestCase.title;
1251
1277
  }
@@ -1275,13 +1301,32 @@ tool(
1275
1301
  const textarea = el.querySelector('textarea');
1276
1302
  const originalTestCase = testCases[index];
1277
1303
 
1278
- // Create the updated test case array in the original format
1279
- const updatedCase = [
1280
- textarea.value.trim(), // Updated title/content
1281
- originalTestCase.description, // Keep original description
1282
- originalTestCase.status, // Keep original status
1283
- originalTestCase.originalCase // Keep original case reference
1284
- ];
1304
+ // Create the updated test case array based on the original format
1305
+ let updatedCase;
1306
+ const status = originalTestCase.status.toLowerCase();
1307
+
1308
+ if (status === 'modify') {
1309
+ // For modify: [updatedContent, newDescription, "Modify", testId]
1310
+ updatedCase = [
1311
+ textarea.value.trim(),
1312
+ originalTestCase.newDescription,
1313
+ originalTestCase.status,
1314
+ originalTestCase.testId
1315
+ ];
1316
+ } else if (status === 'remove') {
1317
+ // For remove: [updatedContent, "Remove", testId]
1318
+ updatedCase = [
1319
+ textarea.value.trim(),
1320
+ originalTestCase.status,
1321
+ originalTestCase.testId
1322
+ ];
1323
+ } else {
1324
+ // For new: [updatedContent, "New"]
1325
+ updatedCase = [
1326
+ textarea.value.trim(),
1327
+ originalTestCase.status
1328
+ ];
1329
+ }
1285
1330
 
1286
1331
  updatedTestCases.push(updatedCase);
1287
1332
  }
@@ -1523,6 +1568,105 @@ tool(
1523
1568
  }
1524
1569
  );
1525
1570
 
1571
+ tool(
1572
+ "update_testcases_to_tcms",
1573
+ "Create new test cases in TCMS from approved test cases. Only processes test cases with 'New' status, ignores Modify and Remove cases since APIs are not available.",
1574
+ {
1575
+ testCases: zod_1.z.array(zod_1.z.array(zod_1.z.string())).describe("Array of test case arrays from approved test cases")
1576
+ },
1577
+ async ({ testCases }) => {
1578
+ try {
1579
+ // Load AIO token from Desktop/aio.json
1580
+ const aioConfigPath = path.join(os.homedir(), "Desktop", "aio.json");
1581
+ const configContent = await fs.readFile(aioConfigPath, "utf-8");
1582
+ const { token } = JSON.parse(configContent);
1583
+
1584
+ if (!token) throw new Error("AIO token missing in aio.json");
1585
+
1586
+ // Filter test cases to extract only "New" test cases
1587
+ const newTestCases = [];
1588
+
1589
+ for (const testCase of testCases) {
1590
+ if (Array.isArray(testCase) && testCase.length >= 2) {
1591
+ // Check if the last element or second-to-last element is "New"
1592
+ const status = testCase.length === 2 ? testCase[1] : testCase[testCase.length - 2];
1593
+
1594
+ if (status && status.toLowerCase() === 'new') {
1595
+ const title = testCase[0]; // First element is always the title
1596
+ if (title && title.trim().length > 0) {
1597
+ newTestCases.push(title.trim());
1598
+ }
1599
+ }
1600
+ }
1601
+ }
1602
+
1603
+ if (newTestCases.length === 0) {
1604
+ return "No new test cases found to create in TCMS. Only test cases marked as '(New)' are processed.";
1605
+ }
1606
+
1607
+ // Hard-coded values as requested
1608
+ const projectKey = "SCRUM";
1609
+ const folderId = 1;
1610
+ const ownerId = "712020:37085ff2-5a05-47eb-8977-50a485355755";
1611
+
1612
+ // Create test cases in TCMS one by one
1613
+ for (let i = 0; i < newTestCases.length; i++) {
1614
+ const title = newTestCases[i];
1615
+
1616
+ try {
1617
+ const requestBody = {
1618
+ title: title,
1619
+ ownedByID: ownerId,
1620
+ folder: {
1621
+ ID: folderId
1622
+ },
1623
+ status: {
1624
+ name: "Published",
1625
+ description: "The test is ready for execution",
1626
+ ID: 1
1627
+ }
1628
+ };
1629
+
1630
+ (0, logger_1.trace)(`Creating test case ${i + 1}/${newTestCases.length}: ${title}`);
1631
+
1632
+ const response = await axios.post(
1633
+ `https://tcms.aiojiraapps.com/aio-tcms/api/v1/project/${projectKey}/testcase`,
1634
+ requestBody,
1635
+ {
1636
+ headers: {
1637
+ "accept": "application/json;charset=utf-8",
1638
+ "Authorization": `AioAuth ${token}`,
1639
+ "Content-Type": "application/json"
1640
+ }
1641
+ }
1642
+ );
1643
+
1644
+ if (response.status === 200 || response.status === 201) {
1645
+ const testCaseKey = response.data.key || `${projectKey}-TC-${response.data.ID}`;
1646
+ (0, logger_1.trace)(`Successfully created test case: ${testCaseKey} - ${title}`);
1647
+ }
1648
+
1649
+ // Add a small delay between requests to avoid rate limiting
1650
+ await new Promise(resolve => setTimeout(resolve, 500));
1651
+
1652
+ } catch (error) {
1653
+ (0, logger_1.trace)(`Failed to create test case: ${title} - ${error.message}`);
1654
+ throw new Error(`Failed to create test case "${title}": ${error.message}`);
1655
+ }
1656
+ }
1657
+
1658
+ return "All test cases have been updated to TCMS";
1659
+
1660
+ } catch (error) {
1661
+ console.error('TCMS update error:', error);
1662
+ if (error.response) {
1663
+ return `❌ TCMS API Error: ${error.response.status} - ${error.response.data?.message || error.response.statusText}`;
1664
+ }
1665
+ return `❌ Error updating test cases to TCMS: ${error.message}`;
1666
+ }
1667
+ }
1668
+ );
1669
+
1526
1670
  return server;
1527
1671
  };
1528
1672
 
@@ -16,9 +16,10 @@ should contains before test case from tcms and after testcase that is generated,
16
16
  existing in TCMS and if change is to be done to it should be marked as Modify
17
17
  "SCRUM-TC-2" - id of existing test case in TCMS, only for Remove and Modify test cases
18
18
  if any new test case is to be created then don't mention any id against it
19
- for review_testcases test cases tool data should be in this format, strictly follow this format espcially for Modify test cases
19
+ for review_testcases and update_testcases_to_tcms tool data should be in this format, strictly follow this format espcially for Modify test cases
20
20
  {"testCases":[["Verify that brochure section is visible under overview tab","Verify brochure section is removed from property tour tab","Modify","SCRUM-TC-1"],
21
21
  ["Verify similar properties section is visible under over tab in pdp section","Remove","SCRUM-TC-2"],
22
22
  ["Verify Project Brochure section appears above the 'Explore on map' section in Overview tab","New"]]}
23
23
 
24
+ for update_testcases_to_tcms tool, send only test cases approved by user
24
25
  NOTE: keep polling continously for 10 times max till the test cases are approved by user
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nbakka/mcp-appium",
3
- "version": "3.0.10",
3
+ "version": "3.0.12",
4
4
  "description": "Appium MCP",
5
5
  "engines": {
6
6
  "node": ">=18"