@nbakka/mcp-appium 2.0.98 → 2.0.99
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/review-ui/index.html +60 -39
- package/lib/server.js +15 -3
- package/package.json +1 -1
package/lib/review-ui/index.html
CHANGED
|
@@ -497,28 +497,28 @@
|
|
|
497
497
|
return;
|
|
498
498
|
}
|
|
499
499
|
|
|
500
|
-
container.innerHTML = cases.map((tc
|
|
501
|
-
<div class="test-case" id="new-${
|
|
500
|
+
container.innerHTML = cases.map((tc) => `
|
|
501
|
+
<div class="test-case" id="new-${tc.id}">
|
|
502
502
|
<div class="test-case-header">
|
|
503
503
|
<span class="test-case-id">${tc.id}</span>
|
|
504
504
|
<div class="test-case-actions">
|
|
505
|
-
<button class="btn btn-edit" onclick="startEdit('new', ${
|
|
505
|
+
<button class="btn btn-edit" onclick="startEdit('new', '${tc.id}')">✏️ Edit</button>
|
|
506
506
|
<button class="btn btn-delete" onclick="deleteTestCase('new', '${tc.id}')">🗑️ Delete</button>
|
|
507
507
|
</div>
|
|
508
508
|
</div>
|
|
509
509
|
<div class="test-case-content">
|
|
510
|
-
<div id="new-${
|
|
510
|
+
<div id="new-${tc.id}-display">
|
|
511
511
|
<div class="description-text">${escapeHtml(tc.description)}</div>
|
|
512
512
|
</div>
|
|
513
|
-
<div id="new-${
|
|
513
|
+
<div id="new-${tc.id}-edit" style="display: none;">
|
|
514
514
|
<div class="edit-form">
|
|
515
515
|
<div class="form-group">
|
|
516
516
|
<label class="form-label">Description:</label>
|
|
517
|
-
<textarea class="form-control" id="new-${
|
|
517
|
+
<textarea class="form-control" id="new-${tc.id}-desc">${escapeHtml(tc.description)}</textarea>
|
|
518
518
|
</div>
|
|
519
519
|
<div class="test-case-actions">
|
|
520
|
-
<button class="btn btn-save" onclick="saveEdit('new', ${
|
|
521
|
-
<button class="btn btn-cancel" onclick="cancelEdit('new', ${
|
|
520
|
+
<button class="btn btn-save" onclick="saveEdit('new', '${tc.id}')">💾 Save</button>
|
|
521
|
+
<button class="btn btn-cancel" onclick="cancelEdit('new', '${tc.id}')">❌ Cancel</button>
|
|
522
522
|
</div>
|
|
523
523
|
</div>
|
|
524
524
|
</div>
|
|
@@ -536,17 +536,17 @@
|
|
|
536
536
|
return;
|
|
537
537
|
}
|
|
538
538
|
|
|
539
|
-
container.innerHTML = cases.map((tc
|
|
540
|
-
<div class="test-case" id="modify-${
|
|
539
|
+
container.innerHTML = cases.map((tc) => `
|
|
540
|
+
<div class="test-case" id="modify-${tc.id}">
|
|
541
541
|
<div class="test-case-header">
|
|
542
542
|
<span class="test-case-id">${tc.id}</span>
|
|
543
543
|
<div class="test-case-actions">
|
|
544
|
-
<button class="btn btn-edit" onclick="startEdit('modify', ${
|
|
544
|
+
<button class="btn btn-edit" onclick="startEdit('modify', '${tc.id}')">✏️ Edit</button>
|
|
545
545
|
<button class="btn btn-delete" onclick="deleteTestCase('modify', '${tc.id}')">🗑️ Delete</button>
|
|
546
546
|
</div>
|
|
547
547
|
</div>
|
|
548
548
|
<div class="test-case-content">
|
|
549
|
-
<div id="modify-${
|
|
549
|
+
<div id="modify-${tc.id}-display">
|
|
550
550
|
<div class="original-text">
|
|
551
551
|
<strong>Original:</strong><br>${escapeHtml(tc.original)}
|
|
552
552
|
</div>
|
|
@@ -554,7 +554,7 @@
|
|
|
554
554
|
<strong>Modified:</strong><br>${escapeHtml(tc.modified)}
|
|
555
555
|
</div>
|
|
556
556
|
</div>
|
|
557
|
-
<div id="modify-${
|
|
557
|
+
<div id="modify-${tc.id}-edit" style="display: none;">
|
|
558
558
|
<div class="edit-form">
|
|
559
559
|
<div class="form-group">
|
|
560
560
|
<label class="form-label">Original (Read-only):</label>
|
|
@@ -562,11 +562,11 @@
|
|
|
562
562
|
</div>
|
|
563
563
|
<div class="form-group">
|
|
564
564
|
<label class="form-label">Modified:</label>
|
|
565
|
-
<textarea class="form-control" id="modify-${
|
|
565
|
+
<textarea class="form-control" id="modify-${tc.id}-mod">${escapeHtml(tc.modified)}</textarea>
|
|
566
566
|
</div>
|
|
567
567
|
<div class="test-case-actions">
|
|
568
|
-
<button class="btn btn-save" onclick="saveEdit('modify', ${
|
|
569
|
-
<button class="btn btn-cancel" onclick="cancelEdit('modify', ${
|
|
568
|
+
<button class="btn btn-save" onclick="saveEdit('modify', '${tc.id}')">💾 Save</button>
|
|
569
|
+
<button class="btn btn-cancel" onclick="cancelEdit('modify', '${tc.id}')">❌ Cancel</button>
|
|
570
570
|
</div>
|
|
571
571
|
</div>
|
|
572
572
|
</div>
|
|
@@ -584,8 +584,8 @@
|
|
|
584
584
|
return;
|
|
585
585
|
}
|
|
586
586
|
|
|
587
|
-
container.innerHTML = cases.map((tc
|
|
588
|
-
<div class="test-case" id="remove-${
|
|
587
|
+
container.innerHTML = cases.map((tc) => `
|
|
588
|
+
<div class="test-case" id="remove-${tc.id}">
|
|
589
589
|
<div class="test-case-header">
|
|
590
590
|
<span class="test-case-id">${tc.id}</span>
|
|
591
591
|
<div class="test-case-actions">
|
|
@@ -603,50 +603,63 @@
|
|
|
603
603
|
}
|
|
604
604
|
|
|
605
605
|
// Edit functions
|
|
606
|
-
function startEdit(type,
|
|
607
|
-
const editKey = `${type}-${
|
|
606
|
+
function startEdit(type, id) {
|
|
607
|
+
const editKey = `${type}-${id}`;
|
|
608
608
|
if (editingStates.has(editKey)) return;
|
|
609
609
|
|
|
610
610
|
editingStates.add(editKey);
|
|
611
|
-
document.getElementById(`${type}-${
|
|
612
|
-
document.getElementById(`${type}-${
|
|
611
|
+
document.getElementById(`${type}-${id}-display`).style.display = 'none';
|
|
612
|
+
document.getElementById(`${type}-${id}-edit`).style.display = 'block';
|
|
613
613
|
}
|
|
614
614
|
|
|
615
|
-
function cancelEdit(type,
|
|
616
|
-
const editKey = `${type}-${
|
|
615
|
+
function cancelEdit(type, id) {
|
|
616
|
+
const editKey = `${type}-${id}`;
|
|
617
617
|
editingStates.delete(editKey);
|
|
618
|
-
document.getElementById(`${type}-${
|
|
619
|
-
document.getElementById(`${type}-${
|
|
618
|
+
document.getElementById(`${type}-${id}-display`).style.display = 'block';
|
|
619
|
+
document.getElementById(`${type}-${id}-edit`).style.display = 'none';
|
|
620
620
|
|
|
621
621
|
// Reset form values
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
622
|
+
const testCase = findTestCase(type, id);
|
|
623
|
+
if (testCase) {
|
|
624
|
+
if (type === 'new') {
|
|
625
|
+
document.getElementById(`new-${id}-desc`).value = testCase.description;
|
|
626
|
+
} else if (type === 'modify') {
|
|
627
|
+
document.getElementById(`modify-${id}-mod`).value = testCase.modified;
|
|
628
|
+
}
|
|
626
629
|
}
|
|
627
630
|
}
|
|
628
631
|
|
|
629
|
-
|
|
632
|
+
function findTestCase(type, id) {
|
|
633
|
+
return testCases[type]?.find(tc => tc.id === id);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
async function saveEdit(type, id) {
|
|
630
637
|
try {
|
|
631
|
-
const editKey = `${type}-${
|
|
638
|
+
const editKey = `${type}-${id}`;
|
|
632
639
|
let updatedData = {};
|
|
633
640
|
|
|
641
|
+
const testCase = findTestCase(type, id);
|
|
642
|
+
if (!testCase) {
|
|
643
|
+
showStatus('Test case not found', 'error');
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
|
|
634
647
|
if (type === 'new') {
|
|
635
|
-
const newDesc = document.getElementById(`new-${
|
|
648
|
+
const newDesc = document.getElementById(`new-${id}-desc`).value.trim();
|
|
636
649
|
if (!newDesc) {
|
|
637
650
|
showStatus('Description cannot be empty', 'error');
|
|
638
651
|
return;
|
|
639
652
|
}
|
|
640
653
|
updatedData = { description: newDesc };
|
|
641
|
-
|
|
654
|
+
testCase.description = newDesc;
|
|
642
655
|
} else if (type === 'modify') {
|
|
643
|
-
const newMod = document.getElementById(`modify-${
|
|
656
|
+
const newMod = document.getElementById(`modify-${id}-mod`).value.trim();
|
|
644
657
|
if (!newMod) {
|
|
645
658
|
showStatus('Modified description cannot be empty', 'error');
|
|
646
659
|
return;
|
|
647
660
|
}
|
|
648
661
|
updatedData = { modified: newMod };
|
|
649
|
-
|
|
662
|
+
testCase.modified = newMod;
|
|
650
663
|
}
|
|
651
664
|
|
|
652
665
|
// Send update to server
|
|
@@ -654,14 +667,14 @@
|
|
|
654
667
|
method: 'POST',
|
|
655
668
|
body: JSON.stringify({
|
|
656
669
|
type,
|
|
657
|
-
id:
|
|
670
|
+
id: id,
|
|
658
671
|
data: updatedData
|
|
659
672
|
})
|
|
660
673
|
});
|
|
661
674
|
|
|
662
675
|
editingStates.delete(editKey);
|
|
663
|
-
document.getElementById(`${type}-${
|
|
664
|
-
document.getElementById(`${type}-${
|
|
676
|
+
document.getElementById(`${type}-${id}-display`).style.display = 'block';
|
|
677
|
+
document.getElementById(`${type}-${id}-edit`).style.display = 'none';
|
|
665
678
|
|
|
666
679
|
// Re-render the specific section
|
|
667
680
|
if (type === 'new') renderNewCases();
|
|
@@ -687,9 +700,17 @@
|
|
|
687
700
|
|
|
688
701
|
if (result.testCases) {
|
|
689
702
|
testCases = result.testCases;
|
|
703
|
+
|
|
704
|
+
// Ensure all arrays exist after update
|
|
705
|
+
if (!testCases.new) testCases.new = [];
|
|
706
|
+
if (!testCases.modify) testCases.modify = [];
|
|
707
|
+
if (!testCases.remove) testCases.remove = [];
|
|
708
|
+
|
|
690
709
|
renderAllSections();
|
|
691
710
|
updateCounts();
|
|
692
711
|
showStatus('Test case deleted successfully!', 'success');
|
|
712
|
+
} else {
|
|
713
|
+
showStatus('Unexpected response from server', 'error');
|
|
693
714
|
}
|
|
694
715
|
} catch (error) {
|
|
695
716
|
showStatus(`Error deleting test case: ${error.message}`, 'error');
|
package/lib/server.js
CHANGED
|
@@ -1014,7 +1014,7 @@ tool(
|
|
|
1014
1014
|
const now = Date.now();
|
|
1015
1015
|
const elapsed = Math.floor((now - session.startTime) / 1000);
|
|
1016
1016
|
|
|
1017
|
-
// Check if already approved
|
|
1017
|
+
// Check if already approved BEFORE waiting
|
|
1018
1018
|
if (session.status === 'approved') {
|
|
1019
1019
|
const approvedTestCases = session.finalTestCases || session.testCases;
|
|
1020
1020
|
session.server?.close();
|
|
@@ -1022,10 +1022,22 @@ tool(
|
|
|
1022
1022
|
return `✅ Test cases approved. Elapsed: ${elapsed}s\n${JSON.stringify(approvedTestCases, null, 2)}`;
|
|
1023
1023
|
}
|
|
1024
1024
|
|
|
1025
|
-
|
|
1025
|
+
if (session.status === 'cancelled') {
|
|
1026
|
+
session.server?.close();
|
|
1027
|
+
approvalSessions.delete(sessionId);
|
|
1028
|
+
return `❌ Review cancelled. Elapsed: ${elapsed}s`;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
if (session.status === 'timeout' || elapsed > 300) {
|
|
1032
|
+
session.server?.close();
|
|
1033
|
+
approvalSessions.delete(sessionId);
|
|
1034
|
+
return `⏰ Review session timed out. Elapsed: ${elapsed}s`;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// Wait 20 seconds before checking status again
|
|
1026
1038
|
await new Promise(r => setTimeout(r, 20000));
|
|
1027
1039
|
|
|
1028
|
-
// Re-fetch session after wait
|
|
1040
|
+
// Re-fetch session after wait to check for status changes
|
|
1029
1041
|
const refreshed = approvalSessions.get(sessionId);
|
|
1030
1042
|
if (!refreshed) return `❌ Session expired during wait`;
|
|
1031
1043
|
|