@nbakka/mcp-appium 2.0.81 → 2.0.83

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.
@@ -0,0 +1,38 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Test Case Review & Approval</title>
5
+ <link rel="stylesheet" href="/styles.css">
6
+ </head>
7
+ <body>
8
+ <div class="container">
9
+ <h1>Review Test Cases</h1>
10
+
11
+ <!-- New Test Cases Section -->
12
+ <div class="section" id="new-testcases-section">
13
+ <h2>New Test Cases</h2>
14
+ <div id="new-testcases"></div>
15
+ </div>
16
+
17
+ <!-- Modified Test Cases Section -->
18
+ <div class="section" id="modified-testcases-section">
19
+ <h2>Modified Test Cases</h2>
20
+ <div id="modified-testcases"></div>
21
+ </div>
22
+
23
+ <!-- Test Cases to Remove Section -->
24
+ <div class="section" id="remove-testcases-section">
25
+ <h2>Test Cases to Remove</h2>
26
+ <div id="remove-testcases"></div>
27
+ </div>
28
+
29
+ <div class="button-container">
30
+ <button id="approve-btn" onclick="approveTestCases()">✓ Approve Test Cases</button>
31
+ <button id="cancel-btn" onclick="cancelReview()">✗ Cancel Review</button>
32
+ <div id="status" class="status"></div>
33
+ </div>
34
+ </div>
35
+
36
+ <script src="/script.js"></script>
37
+ </body>
38
+ </html>
@@ -0,0 +1,176 @@
1
+ let sessionId = '';
2
+ let testCasesData = {};
3
+
4
+ function initializeTestCases(data) {
5
+ sessionId = data.sessionId;
6
+ testCasesData = data.testCases;
7
+
8
+ renderNewTestCases();
9
+ renderModifiedTestCases();
10
+ renderRemoveTestCases();
11
+
12
+ // Hide empty sections
13
+ toggleSectionVisibility();
14
+ }
15
+
16
+ function renderNewTestCases() {
17
+ const container = document.getElementById('new-testcases');
18
+ const newCases = testCasesData.new || [];
19
+
20
+ if (newCases.length === 0) {
21
+ container.innerHTML = '<p class="no-cases">No new test cases</p>';
22
+ return;
23
+ }
24
+
25
+ container.innerHTML = newCases.map((testCase, index) => `
26
+ <div class="test-case new" data-index="${index}" data-type="new">
27
+ <div class="test-case-header">
28
+ <span class="test-type new">New</span>
29
+ <button class="remove-btn" onclick="removeTestCase('new', ${index})">Remove</button>
30
+ </div>
31
+ <div class="test-description">
32
+ <textarea onchange="updateTestCase('new', ${index}, this.value)">${testCase}</textarea>
33
+ </div>
34
+ </div>
35
+ `).join('');
36
+ }
37
+
38
+ function renderModifiedTestCases() {
39
+ const container = document.getElementById('modified-testcases');
40
+ const modifiedCases = testCasesData.modify || [];
41
+
42
+ if (modifiedCases.length === 0) {
43
+ container.innerHTML = '<p class="no-cases">No modified test cases</p>';
44
+ return;
45
+ }
46
+
47
+ container.innerHTML = modifiedCases.map((testCase, index) => `
48
+ <div class="test-case modify" data-index="${index}" data-type="modify">
49
+ <div class="test-case-header">
50
+ <span class="test-id">${testCase.id}</span>
51
+ <div>
52
+ <span class="test-type modify">Modify</span>
53
+ <button class="remove-btn" onclick="removeTestCase('modify', ${index})">Remove</button>
54
+ </div>
55
+ </div>
56
+ <div class="before-after">
57
+ <div class="before-content">
58
+ <h4>Before (Original)</h4>
59
+ <div>${testCase.original}</div>
60
+ </div>
61
+ <div class="after-content">
62
+ <h4>After (Modified)</h4>
63
+ <textarea onchange="updateModifiedTestCase(${index}, this.value)">${testCase.modified}</textarea>
64
+ </div>
65
+ </div>
66
+ </div>
67
+ `).join('');
68
+ }
69
+
70
+ function renderRemoveTestCases() {
71
+ const container = document.getElementById('remove-testcases');
72
+ const removeCases = testCasesData.remove || [];
73
+
74
+ if (removeCases.length === 0) {
75
+ container.innerHTML = '<p class="no-cases">No test cases to remove</p>';
76
+ return;
77
+ }
78
+
79
+ container.innerHTML = removeCases.map((testCase, index) => `
80
+ <div class="test-case remove" data-index="${index}" data-type="remove">
81
+ <div class="test-case-header">
82
+ <span class="test-id">${testCase.id}</span>
83
+ <span class="test-type">Remove</span>
84
+ </div>
85
+ <div class="test-description">
86
+ <div>${testCase.description}</div>
87
+ </div>
88
+ </div>
89
+ `).join('');
90
+ }
91
+
92
+ function removeTestCase(type, index) {
93
+ if (confirm('Are you sure you want to remove this test case?')) {
94
+ testCasesData[type].splice(index, 1);
95
+
96
+ if (type === 'new') renderNewTestCases();
97
+ else if (type === 'modify') renderModifiedTestCases();
98
+
99
+ toggleSectionVisibility();
100
+ }
101
+ }
102
+
103
+ function updateTestCase(type, index, value) {
104
+ testCasesData[type][index] = value;
105
+ }
106
+
107
+ function updateModifiedTestCase(index, value) {
108
+ testCasesData.modify[index].modified = value;
109
+ }
110
+
111
+ function toggleSectionVisibility() {
112
+ const newSection = document.getElementById('new-testcases-section');
113
+ const modifySection = document.getElementById('modified-testcases-section');
114
+ const removeSection = document.getElementById('remove-testcases-section');
115
+
116
+ newSection.classList.toggle('hidden', !testCasesData.new || testCasesData.new.length === 0);
117
+ modifySection.classList.toggle('hidden', !testCasesData.modify || testCasesData.modify.length === 0);
118
+ removeSection.classList.toggle('hidden', !testCasesData.remove || testCasesData.remove.length === 0);
119
+ }
120
+
121
+ function approveTestCases() {
122
+ const approveBtn = document.getElementById('approve-btn');
123
+ const cancelBtn = document.getElementById('cancel-btn');
124
+ const status = document.getElementById('status');
125
+
126
+ approveBtn.disabled = true;
127
+ cancelBtn.disabled = true;
128
+ approveBtn.innerHTML = 'Processing...';
129
+ approveBtn.style.background = '#6c757d';
130
+
131
+ status.style.display = 'block';
132
+ status.className = 'status success';
133
+ status.innerHTML = 'Test cases approved! Processing...';
134
+
135
+ fetch(`/approve/${sessionId}`, {
136
+ method: 'POST',
137
+ headers: {
138
+ 'Content-Type': 'application/json',
139
+ },
140
+ body: JSON.stringify(testCasesData)
141
+ })
142
+ .then(response => response.text())
143
+ .then(data => {
144
+ status.innerHTML = data + ' You can close this window.';
145
+ setTimeout(() => {
146
+ window.close();
147
+ }, 3000);
148
+ })
149
+ .catch(error => {
150
+ status.className = 'status error';
151
+ status.innerHTML = 'Error: ' + error.message;
152
+ approveBtn.disabled = false;
153
+ cancelBtn.disabled = false;
154
+ });
155
+ }
156
+
157
+ function cancelReview() {
158
+ if (confirm('Are you sure you want to cancel the review? All changes will be lost.')) {
159
+ fetch(`/cancel/${sessionId}`, { method: 'POST' })
160
+ .then(() => {
161
+ window.close();
162
+ });
163
+ }
164
+ }
165
+
166
+ // Load initial data when page loads
167
+ window.addEventListener('DOMContentLoaded', function() {
168
+ fetch('/api/testcases')
169
+ .then(response => response.json())
170
+ .then(data => {
171
+ initializeTestCases(data);
172
+ })
173
+ .catch(error => {
174
+ console.error('Error loading test cases:', error);
175
+ });
176
+ });
@@ -0,0 +1,244 @@
1
+ body {
2
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
3
+ margin: 0;
4
+ padding: 20px;
5
+ background-color: #f8f9fa;
6
+ line-height: 1.6;
7
+ }
8
+
9
+ .container {
10
+ max-width: 1400px;
11
+ margin: 0 auto;
12
+ background: white;
13
+ padding: 30px;
14
+ border-radius: 12px;
15
+ box-shadow: 0 4px 20px rgba(0,0,0,0.1);
16
+ }
17
+
18
+ h1 {
19
+ color: #2c3e50;
20
+ text-align: center;
21
+ border-bottom: 3px solid #3498db;
22
+ padding-bottom: 15px;
23
+ margin-bottom: 30px;
24
+ }
25
+
26
+ h2 {
27
+ color: #34495e;
28
+ border-left: 4px solid #3498db;
29
+ padding-left: 15px;
30
+ margin-top: 30px;
31
+ }
32
+
33
+ .section {
34
+ margin-bottom: 40px;
35
+ padding: 20px;
36
+ border: 1px solid #e9ecef;
37
+ border-radius: 8px;
38
+ background: #fdfdfd;
39
+ }
40
+
41
+ .test-case {
42
+ margin: 15px 0;
43
+ padding: 20px;
44
+ border: 1px solid #dee2e6;
45
+ border-radius: 8px;
46
+ background: white;
47
+ position: relative;
48
+ }
49
+
50
+ .test-case.new {
51
+ border-left: 4px solid #28a745;
52
+ }
53
+
54
+ .test-case.modify {
55
+ border-left: 4px solid #ffc107;
56
+ }
57
+
58
+ .test-case.remove {
59
+ border-left: 4px solid #dc3545;
60
+ background: #fff5f5;
61
+ }
62
+
63
+ .test-case-header {
64
+ display: flex;
65
+ justify-content: space-between;
66
+ align-items: center;
67
+ margin-bottom: 15px;
68
+ }
69
+
70
+ .test-id {
71
+ font-weight: bold;
72
+ color: #3498db;
73
+ font-size: 14px;
74
+ background: #ecf0f1;
75
+ padding: 4px 8px;
76
+ border-radius: 4px;
77
+ }
78
+
79
+ .test-type {
80
+ padding: 4px 12px;
81
+ border-radius: 20px;
82
+ font-size: 12px;
83
+ font-weight: bold;
84
+ text-transform: uppercase;
85
+ }
86
+
87
+ .test-type.new {
88
+ background: #d4edda;
89
+ color: #155724;
90
+ }
91
+
92
+ .test-type.modify {
93
+ background: #fff3cd;
94
+ color: #856404;
95
+ }
96
+
97
+ .remove-btn {
98
+ background: #dc3545;
99
+ color: white;
100
+ border: none;
101
+ padding: 6px 12px;
102
+ border-radius: 4px;
103
+ cursor: pointer;
104
+ font-size: 12px;
105
+ }
106
+
107
+ .remove-btn:hover {
108
+ background: #c82333;
109
+ }
110
+
111
+ .test-description {
112
+ margin: 10px 0;
113
+ }
114
+
115
+ .test-description textarea {
116
+ width: 100%;
117
+ min-height: 60px;
118
+ padding: 10px;
119
+ border: 1px solid #ced4da;
120
+ border-radius: 4px;
121
+ font-family: inherit;
122
+ resize: vertical;
123
+ }
124
+
125
+ .test-description textarea:focus {
126
+ outline: none;
127
+ border-color: #3498db;
128
+ box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
129
+ }
130
+
131
+ .before-after {
132
+ display: grid;
133
+ grid-template-columns: 1fr 1fr;
134
+ gap: 15px;
135
+ margin-top: 15px;
136
+ }
137
+
138
+ .before-content, .after-content {
139
+ padding: 10px;
140
+ border-radius: 4px;
141
+ }
142
+
143
+ .before-content {
144
+ background: #f8f9fa;
145
+ border: 1px solid #dee2e6;
146
+ }
147
+
148
+ .after-content {
149
+ background: #fff;
150
+ border: 1px solid #ced4da;
151
+ }
152
+
153
+ .before-content h4, .after-content h4 {
154
+ margin: 0 0 8px 0;
155
+ font-size: 14px;
156
+ color: #495057;
157
+ }
158
+
159
+ .after-content textarea {
160
+ width: 100%;
161
+ min-height: 50px;
162
+ border: 1px solid #ced4da;
163
+ border-radius: 4px;
164
+ padding: 8px;
165
+ font-family: inherit;
166
+ }
167
+
168
+ .button-container {
169
+ text-align: center;
170
+ margin-top: 40px;
171
+ padding-top: 30px;
172
+ border-top: 2px solid #e9ecef;
173
+ }
174
+
175
+ button {
176
+ padding: 15px 30px;
177
+ margin: 0 10px;
178
+ border: none;
179
+ border-radius: 6px;
180
+ cursor: pointer;
181
+ font-size: 16px;
182
+ font-weight: bold;
183
+ transition: all 0.3s ease;
184
+ }
185
+
186
+ #approve-btn {
187
+ background: #28a745;
188
+ color: white;
189
+ }
190
+
191
+ #approve-btn:hover {
192
+ background: #218838;
193
+ transform: translateY(-1px);
194
+ }
195
+
196
+ #cancel-btn {
197
+ background: #6c757d;
198
+ color: white;
199
+ }
200
+
201
+ #cancel-btn:hover {
202
+ background: #5a6268;
203
+ }
204
+
205
+ .status {
206
+ text-align: center;
207
+ margin-top: 20px;
208
+ font-weight: bold;
209
+ display: none;
210
+ padding: 15px;
211
+ border-radius: 6px;
212
+ }
213
+
214
+ .status.success {
215
+ background: #d4edda;
216
+ color: #155724;
217
+ border: 1px solid #c3e6cb;
218
+ }
219
+
220
+ .status.error {
221
+ background: #f8d7da;
222
+ color: #721c24;
223
+ border: 1px solid #f5c6cb;
224
+ }
225
+
226
+ .hidden {
227
+ display: none !important;
228
+ }
229
+
230
+ @media (max-width: 768px) {
231
+ .before-after {
232
+ grid-template-columns: 1fr;
233
+ }
234
+
235
+ .container {
236
+ padding: 15px;
237
+ }
238
+
239
+ button {
240
+ display: block;
241
+ width: 100%;
242
+ margin: 5px 0;
243
+ }
244
+ }
package/lib/server.js CHANGED
@@ -799,23 +799,48 @@ let approvalSessions = new Map();
799
799
 
800
800
  tool(
801
801
  "review_testcases",
802
- "Open JSON test cases in browser for manual approval",
802
+ "Open test cases in browser for manual approval. Accepts test cases in format: [description, type, id?]",
803
803
  {
804
- testCases: zod_1.z.array(zod_1.z.object({
805
- id: zod_1.z.string(),
806
- title: zod_1.z.string(),
807
- description: zod_1.z.string(),
808
- })).describe("Array of test cases to review")
804
+ testCases: zod_1.z.array(zod_1.z.array(zod_1.z.string())).describe("Array of test case arrays: [description, type, id?] where type is 'New', 'Modify', or 'Remove'")
809
805
  },
810
806
  async ({ testCases }) => {
811
807
  try {
812
808
  const express = require('express');
809
+ const path = require('path');
813
810
  const sessionId = Date.now().toString();
814
811
 
812
+ // Parse test cases into categories
813
+ const parsedTestCases = {
814
+ new: [],
815
+ modify: [],
816
+ remove: []
817
+ };
818
+
819
+ testCases.forEach(tc => {
820
+ const [description, type, id] = tc;
821
+ const typeKey = type.toLowerCase();
822
+
823
+ if (typeKey === 'new') {
824
+ parsedTestCases.new.push(description);
825
+ } else if (typeKey === 'modify') {
826
+ parsedTestCases.modify.push({
827
+ id: id || 'N/A',
828
+ original: description,
829
+ modified: description // Default to original, user can edit
830
+ });
831
+ } else if (typeKey === 'remove') {
832
+ parsedTestCases.remove.push({
833
+ id: id || 'N/A',
834
+ description: description
835
+ });
836
+ }
837
+ });
838
+
815
839
  // Initialize session state
816
840
  approvalSessions.set(sessionId, {
817
841
  status: 'pending',
818
- testCases: testCases,
842
+ testCases: parsedTestCases,
843
+ originalTestCases: JSON.parse(JSON.stringify(parsedTestCases)), // Deep copy
819
844
  server: null,
820
845
  startTime: Date.now()
821
846
  });
@@ -823,157 +848,55 @@ tool(
823
848
  const app = express();
824
849
  const port = 3001;
825
850
 
826
- // Serve a simple HTML page with test cases
851
+ // Middleware for JSON parsing
852
+ app.use(express.json());
853
+ app.use(express.static(path.join(__dirname, 'review-ui')));
854
+
855
+ // Main page
827
856
  app.get("/", (req, res) => {
828
- let html = `
829
- <html>
830
- <head>
831
- <title>Test Case Approval</title>
832
- <style>
833
- body {
834
- font-family: Arial, sans-serif;
835
- margin: 20px;
836
- background-color: #f5f5f5;
837
- }
838
- .container {
839
- max-width: 1200px;
840
- margin: 0 auto;
841
- background: white;
842
- padding: 20px;
843
- border-radius: 8px;
844
- box-shadow: 0 2px 10px rgba(0,0,0,0.1);
845
- }
846
- h1 {
847
- color: #333;
848
- text-align: center;
849
- border-bottom: 2px solid #007cba;
850
- padding-bottom: 10px;
851
- }
852
- .test-case {
853
- margin: 15px 0;
854
- padding: 15px;
855
- border: 1px solid #ddd;
856
- border-radius: 8px;
857
- background: #fafafa;
858
- }
859
- .test-id {
860
- font-weight: bold;
861
- color: #007cba;
862
- font-size: 16px;
863
- }
864
- .test-title {
865
- font-weight: bold;
866
- margin: 5px 0;
867
- color: #333;
868
- }
869
- .test-description {
870
- color: #666;
871
- line-height: 1.4;
872
- }
873
- .button-container {
874
- text-align: center;
875
- margin-top: 30px;
876
- padding-top: 20px;
877
- border-top: 1px solid #ddd;
878
- }
879
- button {
880
- padding: 15px 30px;
881
- background: #28a745;
882
- color: white;
883
- border: none;
884
- border-radius: 5px;
885
- cursor: pointer;
886
- font-size: 16px;
887
- font-weight: bold;
888
- }
889
- button:hover {
890
- background: #218838;
891
- }
892
- .status {
893
- text-align: center;
894
- margin-top: 20px;
895
- font-weight: bold;
896
- display: none;
897
- }
898
- </style>
899
- </head>
900
- <body>
901
- <div class="container">
902
- <h1>Review Test Cases</h1>
903
- <div id="test-cases">
904
- `;
905
-
906
- testCases.forEach(tc => {
907
- html += `
908
- <div class="test-case">
909
- <div class="test-id">${tc.id}</div>
910
- <div class="test-title">${tc.title}</div>
911
- <div class="test-description">${tc.description}</div>
912
- </div>
913
- `;
914
- });
857
+ res.sendFile(path.join(__dirname, 'review-ui', 'index.html'));
858
+ });
915
859
 
916
- html += `
917
- </div>
918
- <div class="button-container">
919
- <button onclick="approveTestCases()">✓ Approve Test Cases</button>
920
- <div id="status" class="status"></div>
921
- </div>
922
- </div>
923
-
924
- <script>
925
- function approveTestCases() {
926
- document.querySelector('button').disabled = true;
927
- document.querySelector('button').style.background = '#6c757d';
928
- document.querySelector('button').innerHTML = 'Processing...';
929
-
930
- const status = document.getElementById('status');
931
- status.style.display = 'block';
932
- status.style.color = '#28a745';
933
- status.innerHTML = 'Test cases approved! You can close this window.';
934
-
935
- fetch('/approve/${sessionId}')
936
- .then(response => response.text())
937
- .then(data => {
938
- status.innerHTML = data + ' You can close this window.';
939
- setTimeout(() => {
940
- window.close();
941
- }, 2000);
942
- })
943
- .catch(error => {
944
- status.style.color = '#dc3545';
945
- status.innerHTML = 'Error: ' + error.message;
946
- });
947
- }
948
- </script>
949
- </body>
950
- </html>
951
- `;
952
- res.send(html);
860
+ // API to get test cases data
861
+ app.get("/api/testcases", (req, res) => {
862
+ const session = approvalSessions.get(sessionId);
863
+ res.json({
864
+ sessionId: sessionId,
865
+ testCases: session ? session.testCases : {}
866
+ });
953
867
  });
954
868
 
955
869
  // Approval endpoint
956
- app.get(`/approve/${sessionId}`, (req, res) => {
870
+ app.post(`/approve/${sessionId}`, (req, res) => {
957
871
  const session = approvalSessions.get(sessionId);
958
872
  if (session) {
959
873
  session.status = 'approved';
874
+ session.finalTestCases = req.body; // Store the final approved test cases
960
875
  approvalSessions.set(sessionId, session);
961
876
  }
962
877
  res.send("✓ Test cases approved successfully!");
963
878
  });
964
879
 
880
+ // Cancel endpoint
881
+ app.post(`/cancel/${sessionId}`, (req, res) => {
882
+ const session = approvalSessions.get(sessionId);
883
+ if (session) {
884
+ session.status = 'cancelled';
885
+ approvalSessions.set(sessionId, session);
886
+ }
887
+ res.send("Review cancelled");
888
+ });
889
+
965
890
  // Start server
966
891
  const server = app.listen(port, async () => {
967
892
  console.log(`Test case review server started on http://localhost:${port}`);
968
893
 
969
894
  try {
970
- // Use dynamic import for the open package (ES module)
971
895
  const { default: open } = await import('open');
972
896
  await open(`http://localhost:${port}`);
973
897
  console.log('Browser opened successfully');
974
898
  } catch (openError) {
975
899
  console.log('Failed to open browser automatically:', openError.message);
976
- console.log(`Please manually open: http://localhost:${port}`);
977
900
  }
978
901
  });
979
902
 
@@ -1000,7 +923,7 @@ tool(
1000
923
  message: "Test case review interface opened in browser. Use check_approval_status tool to poll for approval.",
1001
924
  testCasesCount: testCases.length,
1002
925
  browserUrl: `http://localhost:${port}`,
1003
- instructions: "Poll every 10 seconds using check_approval_status tool until approved or timeout (5 minutes)"
926
+ instructions: "Poll every 25 seconds using check_approval_status tool until approved or timeout (5 minutes)"
1004
927
  });
1005
928
 
1006
929
  } catch (err) {
@@ -1014,14 +937,14 @@ tool(
1014
937
 
1015
938
  tool(
1016
939
  "check_approval_status",
1017
- "Check the approval status of test cases review session",
940
+ "Check the approval status of test cases review session with 25 second wait",
1018
941
  {
1019
942
  sessionId: zod_1.z.string().describe("The session ID returned from review_testcases tool")
1020
- },
1021
- async ({ sessionId }) => {
943
+
1022
944
  const session = approvalSessions.get(sessionId);
1023
945
 
1024
946
  if (!session) {
947
+ },
1025
948
  return JSON.stringify({
1026
949
  status: "error",
1027
950
  message: "Session not found. Invalid session ID."
@@ -1032,42 +955,50 @@ tool(
1032
955
  const elapsedTime = Math.floor((currentTime - session.startTime) / 1000);
1033
956
 
1034
957
  if (session.status === 'approved') {
958
+
959
+ const approvedTestCases = session.finalTestCases || session.testCases;
960
+ approvalSessions.delete(sessionId);
961
+
1035
962
  // Clean up session and close server
1036
963
  if (session.server) {
1037
964
  session.server.close();
1038
965
  }
966
+ return `Test cases have been approved by the user!
967
+ message: "Test cases have been approved by the user.",
968
+ approvedTestCases: approvedTestCases,
969
+ elapsedTime: elapsedTime
970
+ session.server.close();
971
+ }
1039
972
  approvalSessions.delete(sessionId);
1040
973
 
1041
- return JSON.stringify({
1042
- status: "approved",
1043
- message: "Test cases have been approved by the user. Continuing with next operations...",
1044
- testCasesCount: session.testCases.length,
1045
- elapsedTime: elapsedTime
1046
974
  });
1047
- } else if (session.status === 'timeout' || elapsedTime > 300) { // 5 minutes
975
+ } else if (session.status === 'cancelled') {
1048
976
  // Clean up session and close server
1049
977
  if (session.server) {
978
+ status: "cancelled",
979
+ message: "Review was cancelled by the user.",
980
+ elapsedTime: elapsedTime
1050
981
  session.server.close();
1051
982
  }
1052
983
  approvalSessions.delete(sessionId);
1053
984
 
1054
- return JSON.stringify({
1055
- status: "timeout",
1056
- message: "Review session timed out after 5 minutes. Test cases were not approved.",
1057
- testCasesCount: session.testCases.length,
1058
- elapsedTime: elapsedTime
1059
985
  });
986
+ } else if (session.status === 'timeout' || elapsedTime > 300) { // 5 minutes
987
+ // Clean up session and close server
988
+ if (session.server) {
1060
989
  } else {
1061
- return JSON.stringify({
1062
- status: "pending",
990
+ Status: timeout
991
+ Elapsed time: ${elapsedTime} seconds`;
992
+
993
+ status: "timeout",
1063
994
  message: "Test cases are still pending approval. Continue polling.",
1064
- testCasesCount: session.testCases.length,
1065
995
  elapsedTime: elapsedTime,
1066
996
  remainingTime: Math.max(0, 300 - elapsedTime)
1067
997
  });
1068
998
  }
1069
999
  }
1070
1000
  );
1001
+
1071
1002
  return server;
1072
1003
  };
1073
1004
 
@@ -7,7 +7,7 @@ final output should be test in following format
7
7
  "Verify pay on credit banner exits on PDP", "Existing"
8
8
  "Verify overview tab on PDP", "New"
9
9
  "Verify financial services are displayed under financial tab", "Remove", "SCRUM-TC-2"
10
- "Verify xyz is moved to sja ", "Modify", "SCRUM-TC-2"
10
+ "Verify xyz is present in overview section ", "Verify xyz is moved from overview to property tour section ", "Modify", "SCRUM-TC-2"
11
11
  Existing - already exists in TCMS and no changes needed
12
12
  New - doesn't exist in TCMS and needs to be created
13
13
  Remove - to remove test cases from TCMS because it is no longer valid
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nbakka/mcp-appium",
3
- "version": "2.0.81",
3
+ "version": "2.0.83",
4
4
  "description": "Appium MCP",
5
5
  "engines": {
6
6
  "node": ">=18"