@@ -77,7 +77,7 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
7777 await this . _handleBrowseBlueprint ( ) ;
7878 break ;
7979 case "copyBlueprintPrompt" :
80- await this . _handleCopyBlueprintPrompt ( ) ;
80+ await this . _handleCopyBlueprintPrompt ( msg . platform || "web" ) ;
8181 break ;
8282 case "platformPrecheck" :
8383 await this . _handlePlatformPrecheck ( msg ) ;
@@ -372,7 +372,7 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
372372 ] ;
373373 const seen = new Set < string > ( ) ;
374374 for ( const pattern of patterns ) {
375- const files = await vscode . workspace . findFiles ( pattern , "**/node_modules/**" , 50 ) ;
375+ const files = await vscode . workspace . findFiles ( pattern , "{ **/node_modules/**,**/test_fixtures/**,**/.venv/**} " , 50 ) ;
376376 for ( const f of files ) {
377377 if ( seen . has ( f . fsPath ) ) { continue ; }
378378 seen . add ( f . fsPath ) ;
@@ -429,8 +429,156 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
429429 }
430430 }
431431
432- private async _handleCopyBlueprintPrompt ( ) : Promise < void > {
433- const prompt = `请帮我为当前项目生成测试蓝本文件,放在项目的 testpilot/ 文件夹下。
432+ private async _handleCopyBlueprintPrompt ( platform : string ) : Promise < void > {
433+ const commonRules = `要求:
434+ 1. 分析源代码中所有可操作 UI 元素(按钮/表单/导航/弹窗)
435+ 2. 选择器使用代码中的真实 id(如 #login-btn)或稳定 class,禁止用 div:nth-child(3) 这类脆弱选择器
436+ 3. 每个功能页面对应一个场景,覆盖正常流程和异常场景(空表单提交、错误输入)
437+ 4. 每个 fill 操作后必须有 assert_text 或 screenshot 验证
438+ 5. 每次导航后必须有断言验证页面已正确加载
439+ 6. 如果应用需要命令行启动(如 npm start、python app.py),必须填写 start_command 字段;纯HTML静态应用留空
440+
441+ 重要提醒:以后修改代码时,主动审视并更新对应模块的蓝本,无需用户提醒!` ;
442+
443+ let prompt = "" ;
444+ if ( platform === "miniprogram" ) {
445+ prompt = `请帮我为当前【微信小程序】项目生成测试蓝本文件 testpilot/testpilot.json。
446+
447+ ⚠️ 小程序蓝本与Web蓝本完全不同!必须严格遵守以下铁律:
448+
449+ 【铁律1】evaluate 的 value 必须是可被 new Function(code) 包裹的纯JS代码字符串
450+ ✅ "value": "(() => { const app = getApp(); return app.globalData.cart.length; })()"
451+ ❌ "value": "() => getApp().globalData.cart.length"(箭头函数不能被new Function直接执行)
452+
453+ 【铁律2】小程序没有 document 对象!evaluate 里只能用:
454+ ✅ getApp() / getCurrentPages() / wx.xxx / Page方法
455+ ❌ document.querySelector / window.location(这些在小程序里不存在)
456+
457+ 【铁律3】每个场景的第一步必须是 reset_state(清空购物车等全局状态+reLaunch回首页)
458+ {"action": "reset_state", "description": "重置状态回首页"}
459+
460+ 【铁律4】跨页面导航必须用 navigate_to,不能用 navigate
461+ {"action": "navigate_to", "value": "/pages/cart/cart", "description": "跳转到购物车页"}
462+
463+ 【铁律5】call_method 的参数必须用 JSON 格式
464+ {"action": "call_method", "target": "onCategoryTap", "value": "{\\"detail\\": {\\"dataset\\": {\\"cat\\": \\"水果\\"}}}"}
465+
466+ 【铁律6】assert_compare 的 value 格式为 "操作符 期望值"
467+ {"action": "assert_compare", "target": "#cartCount", "value": "> 0"}
468+ {"action": "assert_compare", "target": "#total", "value": "== 100"}
469+
470+ 【铁律7】page_query 读取DOM文本/数量时用 value 指定返回类型
471+ {"action": "page_query", "target": ".product", "value": "count"} → 返回元素数量
472+ {"action": "page_query", "target": "#price", "value": "text"} → 返回文本内容
473+
474+ 支持的 action(15种):
475+ reset_state / navigate_to / click / fill / call_method / evaluate / read_text / assert_text / assert_compare / page_query / tap_multiple / screenshot / wait / select / scroll
476+
477+ 蓝本格式:
478+ {
479+ "app_name": "小程序名称",
480+ "description": "功能说明",
481+ "base_url": "miniprogram://项目绝对路径",
482+ "version": "1.0",
483+ "platform": "miniprogram",
484+ "pages": [
485+ {
486+ "url": "/pages/index/index",
487+ "title": "首页",
488+ "elements": { "元素描述": "CSS选择器(来自wxml)" },
489+ "scenarios": [
490+ {
491+ "name": "场景名",
492+ "steps": [
493+ {"action": "reset_state", "description": "重置状态回首页"},
494+ {"action": "read_text", "target": "#price", "description": "读取价格"},
495+ {"action": "evaluate", "value": "(() => { return getApp().globalData.isVip; })()", "expected": "true", "description": "验证会员状态"}
496+ ]
497+ }
498+ ]
499+ }
500+ ]
501+ }
502+
503+ 请先阅读项目中所有 .wxml 和 .js 文件,提取选择器和业务逻辑,再生成蓝本。
504+
505+ ${ commonRules } `;
506+ } else if ( platform === "android" ) {
507+ prompt = `请帮我为当前【Android】项目生成测试蓝本文件 testpilot/testpilot.json。
508+
509+ 蓝本格式:
510+ {
511+ "app_name": "应用名称",
512+ "description": "功能说明",
513+ "base_url": "http://被测网页URL(手机浏览器测试)",
514+ "version": "1.0",
515+ "platform": "android",
516+ "pages": [
517+ {
518+ "url": "/",
519+ "title": "页面标题",
520+ "elements": { "元素描述": "#CSS选择器" },
521+ "scenarios": [
522+ {
523+ "name": "场景名",
524+ "steps": [
525+ {"action": "navigate", "value": "http://被测URL"},
526+ {"action": "click", "target": "#btn"},
527+ {"action": "assert_text", "target": "#result", "expected": "预期文本"}
528+ ]
529+ }
530+ ]
531+ }
532+ ]
533+ }
534+
535+ 注意:Android测试通过手机浏览器执行,选择器与Web相同(CSS选择器)。
536+ 如果是原生App测试,target改用 resource-id 格式(如 com.app:id/btnLogin)。
537+
538+ 支持的 action:navigate / click / fill / select / wait / screenshot / assert_text / assert_visible / hover / scroll
539+
540+ ${ commonRules } `;
541+ } else if ( platform === "desktop" ) {
542+ prompt = `请帮我为当前【Windows桌面应用】项目生成测试蓝本文件 testpilot/testpilot.json。
543+
544+ 蓝本格式:
545+ {
546+ "app_name": "桌面应用名称",
547+ "description": "功能说明",
548+ "base_url": "desktop://应用名称",
549+ "version": "1.0",
550+ "platform": "desktop",
551+ "pages": [
552+ {
553+ "url": "/",
554+ "title": "主窗口",
555+ "elements": { "元素描述": "选择器" },
556+ "scenarios": [
557+ {
558+ "name": "场景名",
559+ "steps": [
560+ {"action": "click", "target": "name:按钮名称"},
561+ {"action": "fill", "target": "automationid:inputField", "value": "测试值"},
562+ {"action": "assert_text", "target": "name:结果标签", "expected": "预期文本"}
563+ ]
564+ }
565+ ]
566+ }
567+ ]
568+ }
569+
570+ 桌面选择器格式(4种):
571+ - name:XXX — 按UI元素Name属性查找
572+ - automationid:XXX — 按AutomationId查找(最稳定)
573+ - class:XXX — 按ClassName查找
574+ - point:X,Y — 按屏幕坐标点击(兜底方案)
575+
576+ 支持的 action:click / fill / assert_text / screenshot / wait
577+
578+ ${ commonRules } `;
579+ } else {
580+ // Web(默认)
581+ prompt = `请帮我为当前【Web】项目生成测试蓝本文件,放在项目的 testpilot/ 文件夹下。
434582
435583重要:按功能模块拆分成多个蓝本文件,不要创建单一的 testpilot.json!
436584
@@ -440,26 +588,15 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
440588- testpilot/order.testpilot.json(订单管理)
441589- testpilot/cart.testpilot.json(购物车)
442590
443- 要求:
444- 1. 分析源代码中所有可操作 UI 元素(按钮/表单/导航/弹窗)
445- 2. 选择器使用代码中的真实 id(如 #login-btn)或稳定 class,禁止用 div:nth-child(3) 这类脆弱选择器
446- 3. 每个功能页面对应一个场景,覆盖正常流程和异常场景(空表单提交、错误输入)
447- 4. 每个 fill 操作后必须有 assert_text 或 screenshot 验证
448- 5. 每次 navigate 必须有断言验证页面已正确加载
449- 6. 如果应用需要命令行启动(如 npm start、python app.py),必须填写 start_command 字段;纯HTML静态应用留空
450- 7. 如果 platform 是 miniprogram,必须固定自动化端口,不要依赖动态端口:
451- - 在蓝本中写: "start_command": "cli auto --project . --auto-port 9420"
452- - 或等效命令,核心是固定 --auto-port 9420
453-
454- 每个蓝本文件格式:
591+ 蓝本文件格式:
455592{
456- "app_name": "模块名称(如:用户认证模块) ",
457- "description": "蓝本功能说明(50-200字,描述本蓝本覆盖哪些功能和测试范围 )",
593+ "app_name": "模块名称",
594+ "description": "蓝本功能说明(50-200字)",
458595 "base_url": "http://localhost:端口",
459596 "version": "1.0",
460597 "platform": "web",
461598 "start_command": "npm start 或 python app.py(纯HTML留空)",
462- "start_cwd": "./(启动命令的工作目录,默认项目根目录) ",
599+ "start_cwd": "./",
463600 "pages": [
464601 {
465602 "url": "/",
@@ -482,9 +619,13 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
482619
483620支持的 action:navigate / click / fill / select / wait / screenshot / assert_text / assert_visible / hover / scroll
484621
485- 重要提醒:以后修改代码时,主动审视并更新对应模块的蓝本,无需用户提醒!` ;
622+ ${ commonRules } `;
623+ }
624+
486625 await vscode . env . clipboard . writeText ( prompt ) ;
487- vscode . window . showInformationMessage ( "✅ 提示词已复制!请粘贴到 Cursor / Windsurf,让编程AI读取源码生成蓝本。" ) ;
626+ const platformNames : Record < string , string > = { web : "Web" , miniprogram : "微信小程序" , android : "Android" , desktop : "Windows桌面" , ios : "iOS" } ;
627+ const pName = platformNames [ platform ] || "Web" ;
628+ vscode . window . showInformationMessage ( `✅ ${ pName } 蓝本提示词已复制!请粘贴到 Cursor / Windsurf,让编程AI读取源码生成蓝本。` ) ;
488629 }
489630
490631 private _guessProjectPathFromBlueprint ( blueprintPath : string ) : string {
@@ -1163,9 +1304,11 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
11631304 vscode.postMessage({ command: "platformPrecheck", platform: platform, blueprint_path: firstPath });
11641305 });
11651306
1166- // 复制蓝本生成提示词
1307+ // 复制蓝本生成提示词(根据当前选中项目的平台生成不同提示词)
11671308 document.getElementById("btnCopyBlueprintPrompt").addEventListener("click", () => {
1168- vscode.postMessage({ command: "copyBlueprintPrompt" });
1309+ const sel = document.getElementById("projectSelect");
1310+ const platform = sel && sel.selectedOptions[0] ? (sel.selectedOptions[0].dataset.platform || "web") : "web";
1311+ vscode.postMessage({ command: "copyBlueprintPrompt", platform: platform });
11691312 });
11701313
11711314 // 探索测试
@@ -1295,6 +1438,7 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
12951438 allProjects.forEach(function(proj, i) {
12961439 var opt = document.createElement("option");
12971440 opt.value = String(i);
1441+ opt.dataset.platform = proj.platform || "web";
12981442 var pName = platformNames[proj.platform] || proj.platform || "Web";
12991443 // iOS项目在Windows下灰色不可选
13001444 if (proj.platform === "ios" && isWindows) {
0 commit comments