@nbakka/mcp-appium 2.0.54 → 2.0.56
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 +52 -269
- package/package.json +1 -1
package/lib/server.js
CHANGED
|
@@ -565,6 +565,25 @@ tool(
|
|
|
565
565
|
const pdfResponse = await axios.get(pdfUrl, { responseType: "arraybuffer" });
|
|
566
566
|
|
|
567
567
|
const exportPath = path.join(os.homedir(), "Desktop", "figma");
|
|
568
|
+
|
|
569
|
+
// Clear the folder before creating new PDF
|
|
570
|
+
try {
|
|
571
|
+
// Check if folder exists
|
|
572
|
+
await fs.access(exportPath);
|
|
573
|
+
// If folder exists, remove all contents
|
|
574
|
+
const files = await fs.readdir(exportPath);
|
|
575
|
+
await Promise.all(
|
|
576
|
+
files.map(file => fs.unlink(path.join(exportPath, file)))
|
|
577
|
+
);
|
|
578
|
+
console.log("✅ Cleared existing files in figma folder");
|
|
579
|
+
} catch (err) {
|
|
580
|
+
// Folder doesn't exist or is empty, no need to clear
|
|
581
|
+
if (err.code !== 'ENOENT') {
|
|
582
|
+
console.log("⚠️ Warning: Could not clear folder:", err.message);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Ensure directory exists
|
|
568
587
|
await fs.mkdir(exportPath, { recursive: true });
|
|
569
588
|
|
|
570
589
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, -5);
|
|
@@ -578,300 +597,64 @@ tool(
|
|
|
578
597
|
}
|
|
579
598
|
);
|
|
580
599
|
|
|
581
|
-
|
|
582
|
-
// ----------------------
|
|
583
|
-
// TOOL: Generate Manual Test Cases from PDF + JIRA
|
|
584
|
-
// ----------------------
|
|
585
600
|
tool(
|
|
586
601
|
"upload_pdf_to_openai",
|
|
587
602
|
"Generate manual test cases by analyzing PDF design with JIRA requirements",
|
|
588
603
|
{
|
|
589
604
|
jiraSummary: zod_1.z.string().describe("Jira issue summary"),
|
|
590
|
-
jiraDescription: zod_1.z.string().describe("Jira issue description")
|
|
591
|
-
pdfPath: zod_1.z.string().describe("Path to PDF file from tool 1")
|
|
605
|
+
jiraDescription: zod_1.z.string().describe("Jira issue description")
|
|
592
606
|
},
|
|
593
|
-
async ({ jiraSummary, jiraDescription
|
|
607
|
+
async ({ jiraSummary, jiraDescription }) => {
|
|
594
608
|
try {
|
|
595
|
-
// Load OpenAI API key
|
|
609
|
+
// Load OpenAI API key from Desktop/openai.json
|
|
596
610
|
const openaiConfigPath = path.join(os.homedir(), "Desktop", "openai.json");
|
|
597
|
-
const configContent =
|
|
598
|
-
const { apiKey
|
|
611
|
+
const configContent = fs.readFileSync(openaiConfigPath, "utf-8");
|
|
612
|
+
const { apiKey } = JSON.parse(configContent);
|
|
599
613
|
|
|
600
|
-
|
|
614
|
+
const figmaDir = path.join(os.homedir(), "Desktop", "figma");
|
|
615
|
+
const files = fs.readdirSync(figmaDir);
|
|
616
|
+
const pdfFiles = files.filter(file => file.toLowerCase().endsWith('.pdf'));
|
|
601
617
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
// Validate file exists
|
|
605
|
-
if (!await fs.access(pdfPath).then(() => true).catch(() => false)) {
|
|
606
|
-
throw new Error(`PDF file not found at path: ${pdfPath}`);
|
|
607
|
-
}
|
|
618
|
+
if (pdfFiles.length === 0) throw new Error("No PDF files found in figma folder");
|
|
608
619
|
|
|
609
|
-
const
|
|
610
|
-
const
|
|
620
|
+
const latestPdf = pdfFiles.sort((a, b) => b.localeCompare(a))[0];
|
|
621
|
+
const pdfPath = path.join(figmaDir, latestPdf);
|
|
611
622
|
|
|
612
|
-
|
|
623
|
+
const client = new OpenAI({ apiKey });
|
|
613
624
|
|
|
614
|
-
|
|
615
|
-
const fileUpload = await client.files.create({
|
|
625
|
+
const file = await client.files.create({
|
|
616
626
|
file: fs.createReadStream(pdfPath),
|
|
617
|
-
purpose: "
|
|
627
|
+
purpose: "user_data",
|
|
618
628
|
});
|
|
619
629
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
file_search: {
|
|
636
|
-
vector_stores: [{
|
|
637
|
-
file_ids: [fileUpload.id]
|
|
638
|
-
}]
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
});
|
|
642
|
-
|
|
643
|
-
// Create comprehensive test case generation prompt
|
|
644
|
-
const testCasePrompt = `
|
|
645
|
-
**JIRA REQUIREMENTS:**
|
|
646
|
-
**Summary:** ${jiraSummary}
|
|
647
|
-
**Description:** ${jiraDescription}
|
|
648
|
-
|
|
649
|
-
**TASK:** Generate comprehensive manual test cases based on the attached PDF design and above JIRA requirements.
|
|
650
|
-
|
|
651
|
-
**OUTPUT FORMAT REQUIRED:**
|
|
652
|
-
Please structure your response as follows:
|
|
653
|
-
|
|
654
|
-
## MANUAL TEST CASES
|
|
655
|
-
|
|
656
|
-
### 1. FUNCTIONAL TEST CASES
|
|
657
|
-
**TC-F-001: [Test Case Title]**
|
|
658
|
-
- **Objective:** What this test validates
|
|
659
|
-
- **Preconditions:** Setup required before testing
|
|
660
|
-
- **Test Steps:**
|
|
661
|
-
1. Step 1 action
|
|
662
|
-
2. Step 2 action
|
|
663
|
-
3. Step 3 action
|
|
664
|
-
- **Expected Result:** What should happen
|
|
665
|
-
- **Priority:** High/Medium/Low
|
|
666
|
-
|
|
667
|
-
### 2. UI/UX TEST CASES
|
|
668
|
-
**TC-UI-001: [Test Case Title]**
|
|
669
|
-
[Same format as above]
|
|
670
|
-
|
|
671
|
-
### 3. EDGE CASE & NEGATIVE TEST CASES
|
|
672
|
-
**TC-E-001: [Test Case Title]**
|
|
673
|
-
[Same format as above]
|
|
674
|
-
|
|
675
|
-
### 4. COMPATIBILITY TEST CASES
|
|
676
|
-
**TC-C-001: [Test Case Title]**
|
|
677
|
-
[Same format as above]
|
|
678
|
-
|
|
679
|
-
### 5. ACCESSIBILITY TEST CASES
|
|
680
|
-
**TC-A-001: [Test Case Title]**
|
|
681
|
-
[Same format as above]
|
|
682
|
-
|
|
683
|
-
**IMPORTANT GUIDELINES:**
|
|
684
|
-
1. Create 15-25 test cases total covering all aspects
|
|
685
|
-
2. Reference specific UI elements from the PDF design
|
|
686
|
-
3. Include both positive and negative test scenarios
|
|
687
|
-
4. Consider different user roles if applicable
|
|
688
|
-
5. Include performance and usability aspects
|
|
689
|
-
6. Make test steps specific and actionable
|
|
690
|
-
7. Consider mobile/responsive design if shown in PDF
|
|
691
|
-
8. Include data validation test cases
|
|
692
|
-
9. Cover error handling scenarios
|
|
693
|
-
10. Include integration testing if multiple components interact
|
|
694
|
-
|
|
695
|
-
Generate detailed test cases now based on the PDF design and JIRA requirements.
|
|
696
|
-
`;
|
|
697
|
-
|
|
698
|
-
// Create thread and run analysis
|
|
699
|
-
const thread = await client.beta.threads.create({
|
|
700
|
-
messages: [
|
|
701
|
-
{
|
|
702
|
-
role: "user",
|
|
703
|
-
content: testCasePrompt
|
|
704
|
-
}
|
|
705
|
-
]
|
|
630
|
+
const completion = await client.chat.completions.create({
|
|
631
|
+
model: "gpt-4o",
|
|
632
|
+
messages: [{
|
|
633
|
+
role: "user",
|
|
634
|
+
content: [{
|
|
635
|
+
type: "file",
|
|
636
|
+
file: { file_id: file.id }
|
|
637
|
+
}, {
|
|
638
|
+
type: "text",
|
|
639
|
+
text: `Generate test cases based on this PDF design and JIRA requirements:
|
|
640
|
+
|
|
641
|
+
Summary: ${jiraSummary}
|
|
642
|
+
Description: ${jiraDescription}`
|
|
643
|
+
}]
|
|
644
|
+
}]
|
|
706
645
|
});
|
|
707
646
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
const run = await client.beta.threads.runs.create(thread.id, {
|
|
711
|
-
assistant_id: assistant.id,
|
|
712
|
-
});
|
|
713
|
-
|
|
714
|
-
// Wait for completion with progress tracking
|
|
715
|
-
let runStatus = await client.beta.threads.runs.retrieve(thread.id, run.id);
|
|
716
|
-
let attempts = 0;
|
|
717
|
-
const maxAttempts = 60; // 60 seconds for complex test case generation
|
|
718
|
-
|
|
719
|
-
while (runStatus.status !== 'completed' && attempts < maxAttempts) {
|
|
720
|
-
if (runStatus.status === 'failed') {
|
|
721
|
-
throw new Error(`Test case generation failed: ${runStatus.last_error?.message}`);
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
if (attempts % 5 === 0) {
|
|
725
|
-
console.log(`⏳ Still generating... (${attempts}s elapsed)`);
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
729
|
-
runStatus = await client.beta.threads.runs.retrieve(thread.id, run.id);
|
|
730
|
-
attempts++;
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
if (runStatus.status !== 'completed') {
|
|
734
|
-
throw new Error('Test case generation timed out after 60 seconds');
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
// Get the generated test cases
|
|
738
|
-
const messages = await client.beta.threads.messages.list(thread.id);
|
|
739
|
-
const testCases = messages.data
|
|
740
|
-
.filter(msg => msg.role === 'assistant')
|
|
741
|
-
.map(msg => msg.content[0]?.text?.value)
|
|
742
|
-
.join('\n\n');
|
|
647
|
+
const testCases = completion.choices[0].message.content;
|
|
743
648
|
|
|
744
|
-
|
|
745
|
-
const testCaseCount = (testCases.match(/\*\*TC-/g) || []).length;
|
|
746
|
-
|
|
747
|
-
// Clean up assistant
|
|
748
|
-
try {
|
|
749
|
-
await client.beta.assistants.del(assistant.id);
|
|
750
|
-
} catch (cleanupError) {
|
|
751
|
-
console.warn('⚠️ Assistant cleanup failed:', cleanupError.message);
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
// Save test cases to file for easy reference
|
|
755
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
756
|
-
const outputFileName = `test_cases_${timestamp.substring(0, 19)}.md`;
|
|
757
|
-
const outputPath = path.join(path.dirname(pdfPath), outputFileName);
|
|
758
|
-
|
|
759
|
-
const fileContent = `# Manual Test Cases
|
|
760
|
-
Generated on: ${new Date().toLocaleString()}
|
|
761
|
-
|
|
762
|
-
## Source Information
|
|
763
|
-
- **JIRA Summary:** ${jiraSummary}
|
|
764
|
-
- **JIRA Description:** ${jiraDescription}
|
|
765
|
-
- **Design File:** ${fileName}
|
|
766
|
-
- **Total Test Cases:** ${testCaseCount}
|
|
767
|
-
|
|
768
|
-
---
|
|
769
|
-
|
|
770
|
-
${testCases}
|
|
771
|
-
|
|
772
|
-
---
|
|
773
|
-
|
|
774
|
-
## Test Execution Notes
|
|
775
|
-
- Execute test cases in the order listed
|
|
776
|
-
- Log defects with screenshots when issues found
|
|
777
|
-
- Update test results in your test management tool
|
|
778
|
-
- Verify on multiple browsers/devices for compatibility tests
|
|
779
|
-
`;
|
|
780
|
-
|
|
781
|
-
await fs.writeFile(outputPath, fileContent, 'utf-8');
|
|
782
|
-
|
|
783
|
-
console.log(`✅ Test cases generated and saved!`);
|
|
784
|
-
|
|
785
|
-
return {
|
|
786
|
-
success: true,
|
|
787
|
-
message: `✅ Successfully generated ${testCaseCount} manual test cases!`,
|
|
788
|
-
results: {
|
|
789
|
-
testCases: testCases,
|
|
790
|
-
summary: {
|
|
791
|
-
totalTestCases: testCaseCount,
|
|
792
|
-
categories: [
|
|
793
|
-
"Functional Test Cases",
|
|
794
|
-
"UI/UX Test Cases",
|
|
795
|
-
"Edge Case & Negative Test Cases",
|
|
796
|
-
"Compatibility Test Cases",
|
|
797
|
-
"Accessibility Test Cases"
|
|
798
|
-
],
|
|
799
|
-
generatedFrom: {
|
|
800
|
-
jiraSummary: jiraSummary,
|
|
801
|
-
designFile: fileName,
|
|
802
|
-
fileSize: `${(stats.size / 1024).toFixed(2)} KB`
|
|
803
|
-
}
|
|
804
|
-
},
|
|
805
|
-
outputs: {
|
|
806
|
-
savedToFile: outputPath,
|
|
807
|
-
fileName: outputFileName,
|
|
808
|
-
generatedAt: new Date().toISOString()
|
|
809
|
-
},
|
|
810
|
-
execution: {
|
|
811
|
-
processingTime: `${attempts} seconds`,
|
|
812
|
-
model: "gpt-4o",
|
|
813
|
-
pdfAnalyzed: true
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
};
|
|
649
|
+
await client.files.del(file.id);
|
|
817
650
|
|
|
651
|
+
return testCases;
|
|
818
652
|
} catch (err) {
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
let errorMessage = "❌ Failed to generate test cases: ";
|
|
822
|
-
|
|
823
|
-
if (err.message?.includes('quota')) {
|
|
824
|
-
errorMessage += "OpenAI quota exceeded. Check billing.";
|
|
825
|
-
} else if (err.message?.includes('timeout')) {
|
|
826
|
-
errorMessage += "Generation took too long. Try with smaller PDF.";
|
|
827
|
-
} else if (err.message?.includes('file')) {
|
|
828
|
-
errorMessage += "PDF processing error. Check file format.";
|
|
829
|
-
} else if (err.message?.includes('API key')) {
|
|
830
|
-
errorMessage += "Invalid OpenAI API key.";
|
|
831
|
-
} else {
|
|
832
|
-
errorMessage += err.message || "Unknown error occurred.";
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
return {
|
|
836
|
-
success: false,
|
|
837
|
-
message: errorMessage,
|
|
838
|
-
error: {
|
|
839
|
-
message: err.message,
|
|
840
|
-
timestamp: new Date().toISOString(),
|
|
841
|
-
attempted: {
|
|
842
|
-
jiraSummary: jiraSummary,
|
|
843
|
-
pdfPath: pdfPath
|
|
844
|
-
}
|
|
845
|
-
},
|
|
846
|
-
troubleshooting: [
|
|
847
|
-
"Verify OpenAI API key in ~/Desktop/openai.json",
|
|
848
|
-
"Check PDF file exists and is readable",
|
|
849
|
-
"Ensure sufficient OpenAI credits",
|
|
850
|
-
"Try with smaller PDF if timeout occurs"
|
|
851
|
-
]
|
|
852
|
-
};
|
|
653
|
+
return `Error: ${err.message}`;
|
|
853
654
|
}
|
|
854
655
|
}
|
|
855
656
|
);
|
|
856
657
|
|
|
857
|
-
// ----------------------
|
|
858
|
-
// USAGE EXAMPLE
|
|
859
|
-
// ----------------------
|
|
860
|
-
|
|
861
|
-
/*
|
|
862
|
-
const result = await tools.uploadPdfToOpenai({
|
|
863
|
-
jiraSummary: "User Login Page Implementation",
|
|
864
|
-
jiraDescription: "Create a responsive login page with email/password fields, remember me checkbox, forgot password link, and social login options. Must support mobile and desktop views.",
|
|
865
|
-
pdfPath: "/path/to/login-design.pdf"
|
|
866
|
-
});
|
|
867
|
-
|
|
868
|
-
// Expected Output:
|
|
869
|
-
// - 15-25 detailed manual test cases
|
|
870
|
-
// - Categories: Functional, UI/UX, Edge Cases, Compatibility, Accessibility
|
|
871
|
-
// - Saved to markdown file for easy reference
|
|
872
|
-
// - Structured format ready for test management tools
|
|
873
|
-
*/
|
|
874
|
-
|
|
875
658
|
return server;
|
|
876
659
|
};
|
|
877
660
|
|