@nbakka/mcp-appium 2.0.69 → 2.0.71
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 +69 -37
- package/lib/testcases-generation-context.txt +11 -0
- package/package.json +1 -1
package/lib/server.js
CHANGED
|
@@ -509,13 +509,13 @@ function extractFileAndNodeId(url) {
|
|
|
509
509
|
}
|
|
510
510
|
|
|
511
511
|
// ----------------------
|
|
512
|
-
// TOOL 1: Export Figma to
|
|
512
|
+
// TOOL 1: Export Figma to PNG
|
|
513
513
|
// ----------------------
|
|
514
514
|
tool(
|
|
515
|
-
"
|
|
516
|
-
"Export Figma file as
|
|
515
|
+
"mobile_export_figma_png",
|
|
516
|
+
"Export Figma file as PNG",
|
|
517
517
|
{
|
|
518
|
-
figmaUrl: zod_1.z.string().describe("The Figma file URL to export as
|
|
518
|
+
figmaUrl: zod_1.z.string().describe("The Figma file URL to export as PNG")
|
|
519
519
|
},
|
|
520
520
|
async ({ figmaUrl }) => {
|
|
521
521
|
try {
|
|
@@ -552,24 +552,22 @@ tool(
|
|
|
552
552
|
throw new Error("No frames found in Figma file");
|
|
553
553
|
}
|
|
554
554
|
|
|
555
|
-
// Request
|
|
555
|
+
// Request PNG export with higher scale for better quality
|
|
556
556
|
const exportResponse = await axios.get(
|
|
557
557
|
`https://api.figma.com/v1/images/${fileId}`,
|
|
558
558
|
{
|
|
559
559
|
headers: { "X-Figma-Token": figmaToken },
|
|
560
|
-
params: {
|
|
560
|
+
params: {
|
|
561
|
+
ids: idsToExport.join(","),
|
|
562
|
+
format: "png",
|
|
563
|
+
scale: "2" // 2x scale for better quality
|
|
564
|
+
}
|
|
561
565
|
}
|
|
562
566
|
);
|
|
563
567
|
|
|
564
|
-
const pdfUrl = Object.values(exportResponse.data.images)[0];
|
|
565
|
-
if (!pdfUrl) throw new Error("No PDF export URL returned from Figma");
|
|
566
|
-
|
|
567
|
-
// Download PDF
|
|
568
|
-
const pdfResponse = await axios.get(pdfUrl, { responseType: "arraybuffer" });
|
|
569
|
-
|
|
570
568
|
const exportPath = path.join(os.homedir(), "Desktop", "figma");
|
|
571
569
|
|
|
572
|
-
// Clear the folder before creating new
|
|
570
|
+
// Clear the folder before creating new PNGs
|
|
573
571
|
try {
|
|
574
572
|
// Check if folder exists
|
|
575
573
|
await fs.access(exportPath);
|
|
@@ -588,19 +586,35 @@ tool(
|
|
|
588
586
|
await fs.mkdir(exportPath, { recursive: true });
|
|
589
587
|
|
|
590
588
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, -5);
|
|
591
|
-
const pdfPath = path.join(exportPath, `figma-export-${timestamp}.pdf`);
|
|
592
|
-
await fs.writeFile(pdfPath, pdfResponse.data);
|
|
593
589
|
|
|
594
|
-
|
|
590
|
+
// Download all PNG images
|
|
591
|
+
const downloadPromises = Object.entries(exportResponse.data.images).map(
|
|
592
|
+
async ([nodeId, pngUrl], index) => {
|
|
593
|
+
if (!pngUrl) throw new Error(`No PNG export URL returned for node ${nodeId}`);
|
|
594
|
+
|
|
595
|
+
const pngResponse = await axios.get(pngUrl, { responseType: "arraybuffer" });
|
|
596
|
+
const filename = idsToExport.length > 1
|
|
597
|
+
? `figma-export-${timestamp}-${index + 1}.png`
|
|
598
|
+
: `figma-export-${timestamp}.png`;
|
|
599
|
+
const pngPath = path.join(exportPath, filename);
|
|
600
|
+
|
|
601
|
+
await fs.writeFile(pngPath, pngResponse.data);
|
|
602
|
+
return pngPath;
|
|
603
|
+
}
|
|
604
|
+
);
|
|
605
|
+
|
|
606
|
+
const savedPaths = await Promise.all(downloadPromises);
|
|
607
|
+
|
|
608
|
+
return `✅ PNG Export Complete: ${savedPaths.length} file(s) saved to ${exportPath}`;
|
|
595
609
|
} catch (err) {
|
|
596
|
-
return `❌ Error exporting Figma
|
|
610
|
+
return `❌ Error exporting Figma PNG: ${err.message}`;
|
|
597
611
|
}
|
|
598
612
|
}
|
|
599
613
|
);
|
|
600
614
|
|
|
601
615
|
tool(
|
|
602
|
-
"
|
|
603
|
-
"Generate manual test cases by analyzing
|
|
616
|
+
"upload_png_to_openai",
|
|
617
|
+
"Generate manual test cases by analyzing PNG design with JIRA requirements",
|
|
604
618
|
{
|
|
605
619
|
jiraSummary: zod_1.z.string().describe("Jira issue summary"),
|
|
606
620
|
jiraDescription: zod_1.z.string().describe("Jira issue description")
|
|
@@ -612,41 +626,59 @@ tool(
|
|
|
612
626
|
const configContent = await fs.readFile(openaiConfigPath, "utf-8");
|
|
613
627
|
const { apiKey } = JSON.parse(configContent);
|
|
614
628
|
|
|
629
|
+
// Load test case generation guidelines
|
|
630
|
+
const guidelinesPath = path.join(__dirname, 'testcases-generation-context.txt');
|
|
631
|
+
const guidelines = await fs.readFile(guidelinesPath, "utf-8");
|
|
632
|
+
|
|
615
633
|
const figmaDir = path.join(os.homedir(), "Desktop", "figma");
|
|
616
634
|
const files = await fs.readdir(figmaDir);
|
|
617
|
-
const
|
|
635
|
+
const pngFiles = files.filter(file => file.toLowerCase().endsWith('.png'));
|
|
618
636
|
|
|
619
|
-
if (
|
|
637
|
+
if (pngFiles.length === 0) throw new Error("No PNG files found in figma folder");
|
|
620
638
|
|
|
621
|
-
|
|
622
|
-
const
|
|
639
|
+
// Get the latest PNG file
|
|
640
|
+
const latestPng = pngFiles.sort((a, b) => b.localeCompare(a))[0];
|
|
641
|
+
const pngPath = path.join(figmaDir, latestPng);
|
|
623
642
|
|
|
624
643
|
const client = new OpenAI({ apiKey });
|
|
625
644
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
});
|
|
645
|
+
// Convert PNG to base64 for vision API
|
|
646
|
+
const pngBuffer = await fs.readFile(pngPath);
|
|
647
|
+
const base64Image = pngBuffer.toString('base64');
|
|
630
648
|
|
|
631
649
|
const completion = await client.chat.completions.create({
|
|
632
|
-
model: "gpt-5",
|
|
650
|
+
model: "gpt-5", // Use GPT-5 model for image analysis
|
|
633
651
|
messages: [{
|
|
634
652
|
role: "user",
|
|
635
|
-
content: [
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
653
|
+
content: [
|
|
654
|
+
{
|
|
655
|
+
type: "text",
|
|
656
|
+
text: `Generate manual test cases based on the following:
|
|
657
|
+
|
|
658
|
+
JIRA Summary: ${jiraSummary}
|
|
659
|
+
|
|
660
|
+
JIRA Description: ${jiraDescription}
|
|
661
|
+
|
|
662
|
+
Test Case Generation Guidelines:
|
|
663
|
+
${guidelines}`
|
|
664
|
+
},
|
|
665
|
+
{
|
|
666
|
+
type: "image_url",
|
|
667
|
+
image_url: {
|
|
668
|
+
url: `data:image/png;base64,${base64Image}`,
|
|
669
|
+
detail: "high"
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
]
|
|
673
|
+
}],
|
|
674
|
+
max_completion_tokens: 10000
|
|
643
675
|
});
|
|
644
676
|
|
|
645
677
|
const testCases = completion.choices[0].message.content;
|
|
646
678
|
|
|
647
679
|
return testCases;
|
|
648
680
|
} catch (err) {
|
|
649
|
-
return
|
|
681
|
+
return `❌ Error generating test cases: ${err.message}`;
|
|
650
682
|
}
|
|
651
683
|
}
|
|
652
684
|
);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
generate test cases using jira summary, description and figma image,
|
|
2
|
+
don't take any extra user input,
|
|
3
|
+
final output should be test in following format
|
|
4
|
+
"Verify pay on credit banner exits on PDP", "Existing"
|
|
5
|
+
"Verify overview tab on PDP", "New"
|
|
6
|
+
"Verify financial services are displayed under financial tab", "Remove"
|
|
7
|
+
"Verify xyz is moved to sja ", "Modify"
|
|
8
|
+
here existing means the test case is already present in the repo
|
|
9
|
+
new means the test case is not present in the repo and needs to be added
|
|
10
|
+
remove means the test case is present in the repo but is not required and needs to be removed
|
|
11
|
+
modify means the test case is present in the repo but needs some modification
|