diff --git a/package.json b/package.json index d73ed34..96604c6 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "preview": "electron-vite preview", "typecheck": "tsc --noEmit -p tsconfig.json", "catalog": "node scripts/build-catalog.mjs", + "snapshot": "vitest run scripts/capability-snapshot.test.ts", "package": "node scripts/package.mjs", "test": "vitest run", "test:e2e": "node scripts/demo-e2e.mjs" diff --git a/resources/capability-snapshot.json b/resources/capability-snapshot.json new file mode 100644 index 0000000..b514967 --- /dev/null +++ b/resources/capability-snapshot.json @@ -0,0 +1,915 @@ +{ + "generatedAt": "2026-11-04T03:53:23.689Z", + "count": 909, + "ids": [ + "App_GetPid", + "App_GetPids", + "App_Kill", + "App_KillV1", + "App_Run", + "App_Start", + "Array_Reshape2Dim", + "Basic_BusinessOrderCount", + "Basic_Clone", + "Basic_ConvertBool", + "Basic_ConvertInt", + "Basic_ConvertNumber", + "Basic_ConvertString", + "Basic_DataTypeConversion", + "Basic_DebugOutput", + "Basic_Delay", + "Basic_Delay_V1", + "Basic_Delay_V2", + "Basic_Dodecryption", + "Basic_GetProcessInfo", + "Basic_IsArray", + "Basic_IsDictionary", + "Basic_IsNull", + "Basic_IsNumber", + "Basic_JudgeDataType", + "Basic_RandomInt", + "Basic_Rnd", + "Basic_SetVariable", + "Basic_SetVariable_V1", + "Basic_StringToNum", + "Basic_Type", + "Bivartable_ColumnOperationDf", + "Bivartable_CreateDf", + "Bivartable_CreateDfV1", + "Bivartable_DelDfColRow", + "Bivartable_DeleteDuplicateRow", + "Bivartable_DfWriteToFile", + "Bivartable_DoCal", + "Bivartable_DoCreate", + "Bivartable_DoFilter", + "Bivartable_DoJoint", + "Bivartable_DoMerge", + "Bivartable_DoOpenExcel", + "Bivartable_DoSave", + "Bivartable_DoSort", + "Bivartable_Dtype", + "Bivartable_FilterDf", + "Bivartable_GetAvgValue", + "Bivartable_GetMaxValue", + "Bivartable_GetMinValue", + "Bivartable_GetSumValue", + "Bivartable_HandleDfMissValue", + "Bivartable_InsertDfData", + "Bivartable_MergeDf", + "Bivartable_ModifyColName", + "Bivartable_ModifyDfName", + "Bivartable_PivotDf", + "Bivartable_ReadDfData", + "Bivartable_ReadDfData_V1", + "Bivartable_ReadDfIndexColumns", + "Bivartable_ReadDfShape", + "Bivartable_ReadTable", + "Bivartable_SortDf", + "Bivartable_SpliceColData", + "Bivartable_SummaryCalculationDf", + "Bivartable_WriteDfData", + "Bivartable_WriteTable", + "CSV_Read", + "CSV_ReadNew", + "CSV_Write", + "CSV_WriteNew", + "CV_GetText", + "CV_MouseClick", + "CV_MouseHover", + "CV_SetText", + "Clipboard_ClearClipboard", + "Clipboard_GetText", + "Clipboard_GetTextV1", + "Clipboard_SaveImage", + "Clipboard_SaveImageV1", + "Clipboard_SetImage", + "Clipboard_SetImageV1", + "Clipboard_SetText", + "Clipboard_SetTextV1", + "Collection_Add", + "Collection_Count", + "Collection_Create", + "Collection_HasItem", + "Collection_Remove", + "CustomConfig_GetConfig", + "DataService_AIGenTxt", + "DataService_AgentCall", + "DataService_ChatBot", + "DataService_Correct", + "DataService_Diff", + "DataService_KeyWord", + "DataService_LargeModel", + "DataService_Review", + "DataService_TextComparison", + "DataService_WorkingDay", + "DataService_ZBrain", + "Database_AllSQLQuery", + "Database_AllSQLQuery_V1", + "Database_BatchInsertExecute", + "Database_BatchSQLExecute", + "Database_CloseDBConnect", + "Database_DBConnect", + "Database_SQLExecute", + "Database_SingleSQLQuery", + "Databook_Clear", + "Databook_DeleteColumn", + "Databook_DeleteRow", + "Databook_Export", + "Databook_GetColumnInfo", + "Databook_GetRowAndColCount", + "Databook_Import", + "Databook_ReadContent", + "Databook_SetColumnInfo", + "Databook_WriteContent", + "Dialog_CsInputBox", + "Dialog_CsMsgBox", + "Dialog_GetConfig", + "Dialog_GetConfigV1", + "Dialog_GetConfigV2", + "Dialog_GetConfigV3", + "Dialog_GetConfigV4", + "Dialog_GetConfigV5", + "Dialog_GetConfigV6", + "Dialog_GetConfigV7", + "Dialog_GetConfigV8", + "Dialog_InputBox", + "Dialog_MsgBox", + "Dialog_Notice", + "Dialog_Notice_V1", + "Dialog_Notice_V2", + "Dialog_OpenFile", + "Dialog_OpenFiles", + "Dialog_SaveFile", + "Dict_Clear", + "Dict_Create", + "Dict_Delete", + "Dict_GetItem", + "Dict_Items", + "Dict_Keys", + "Dict_SetItem", + "Dict_Update", + "Dict_Values", + "Element_ActivateWindowGround", + "Element_CheckBoxOperation", + "Element_CheckBoxOperation_v1", + "Element_CheckBoxOperation_v2", + "Element_CheckBoxOperation_v3", + "Element_Children", + "Element_ChildrenGround", + "Element_ChildrenV1", + "Element_Children_V1", + "Element_Children_V2", + "Element_Click", + "Element_ClickGround", + "Element_Click_V1", + "Element_Click_V2", + "Element_Click_V3", + "Element_Click_V4", + "Element_Click_V5", + "Element_Click_V6", + "Element_DesktopChildren", + "Element_ElementAarray", + "Element_ElementCaptureSimilar", + "Element_ElementExists", + "Element_Exists", + "Element_ExistsGround", + "Element_ExistsV1", + "Element_FileUploader", + "Element_GetAttribute", + "Element_GetAttributeGround", + "Element_GetAttribute_v1", + "Element_GetAttribute_v2", + "Element_GetAttribute_v3", + "Element_GetButtonEnable", + "Element_GetButtonEnableGround", + "Element_GetButtonEnable_v1", + "Element_GetButtonEnable_v2", + "Element_GetButtonEnable_v3", + "Element_GetButtonEnable_v4", + "Element_GetCheck", + "Element_GetCheckGround", + "Element_GetElement", + "Element_GetElementInfo", + "Element_GetElementInfo_V1", + "Element_GetElementNew", + "Element_GetElementV1", + "Element_GetElementV2", + "Element_GetHtml", + "Element_GetLineBarChartData", + "Element_GetPieChartData", + "Element_GetSelect", + "Element_GetSelectGround", + "Element_GetTableData", + "Element_GetText", + "Element_GetText_V1", + "Element_GetText_V2", + "Element_GetText_V3", + "Element_GetText_V4", + "Element_GetText_V5", + "Element_GetValue", + "Element_GetValueGround", + "Element_MouseTo", + "Element_MouseToGround", + "Element_MouseTo_V1", + "Element_MouseTo_V2", + "Element_MouseTo_V3", + "Element_MouseTo_V4", + "Element_MoveWindowGround", + "Element_Parent", + "Element_Parent_V1", + "Element_Parent_V2", + "Element_Region", + "Element_Region2", + "Element_Region2_v1", + "Element_Region2_v2", + "Element_Region2_v3", + "Element_RegionGround", + "Element_RestoreWindowGround", + "Element_ScrollIntoView", + "Element_ScrollIntoViewGround", + "Element_ScrollIntoView_v1", + "Element_ScrollIntoView_v2", + "Element_SelectOperation", + "Element_SelectOperation_v1", + "Element_SelectOperation_v2", + "Element_SelectOperation_v3", + "Element_SetAttribute", + "Element_SetAttributeGround", + "Element_SetAttribute_v1", + "Element_SetAttribute_v2", + "Element_SetCheck", + "Element_SetCheckGround", + "Element_SetSelect", + "Element_SetSelectGround", + "Element_SetValue", + "Element_SetValueGround", + "Element_SetValuePassword", + "Element_SetValuePassword_V1", + "Element_SetValuePassword_V5", + "Element_SetValuePassword_V6", + "Element_SetValue_V1", + "Element_SetValue_V2", + "Element_SetValue_V3", + "Element_SetValue_V4", + "Element_SetValue_V5", + "Element_SetValue_V6", + "Element_Shot", + "Element_ShotGround", + "Element_Shot_V1", + "Element_Shot_V2", + "Element_Sibling", + "Element_Sibling_V1", + "Element_Sibling_V2", + "Element_SimilarElementList", + "Element_SimilarElementList_V1", + "Element_SimilarElementList_V2", + "Element_StartAutoClosePopup", + "Element_StopAutoClosePopup", + "Element_WaitElement", + "Element_WaitElementGround", + "Element_WaitElement_v1", + "Element_WaitElement_v2", + "Element_WaitElement_v3", + "Element_WaitElement_v4", + "Element_WaitElement_v5", + "Element_exception_monitor_v2", + "Excel_ActiveSheet", + "Excel_ClearRange", + "Excel_Close", + "Excel_CopyRange", + "Excel_CopySheet", + "Excel_CreateSheet", + "Excel_Cs_Active", + "Excel_Cs_AutoFill", + "Excel_Cs_AutoFillV2", + "Excel_Cs_ClearExcelFilter", + "Excel_Cs_ClearRange", + "Excel_Cs_ClearRangeV2", + "Excel_Cs_ClearRangeV3", + "Excel_Cs_ClearRangeV4", + "Excel_Cs_Close", + "Excel_Cs_CloseV2", + "Excel_Cs_ColumnSplit", + "Excel_Cs_ColumnSplitV2", + "Excel_Cs_ConvertColumn", + "Excel_Cs_Copy", + "Excel_Cs_CopyRange", + "Excel_Cs_CopyRangeV2", + "Excel_Cs_CopyRangeV3", + "Excel_Cs_CopyV2", + "Excel_Cs_Delete", + "Excel_Cs_DeleteColumn", + "Excel_Cs_DeleteDuplicates", + "Excel_Cs_DeletePicture", + "Excel_Cs_DeletePictureV2", + "Excel_Cs_DeleteRange", + "Excel_Cs_DeleteRangeV2", + "Excel_Cs_DeleteRangeV3", + "Excel_Cs_DeleteRow", + "Excel_Cs_EnableExcelFilter", + "Excel_Cs_Encrypt", + "Excel_Cs_ExcelAddin", + "Excel_Cs_ExcelFilter", + "Excel_Cs_Export", + "Excel_Cs_Filter", + "Excel_Cs_FilterPivotTable", + "Excel_Cs_Find", + "Excel_Cs_FindV2", + "Excel_Cs_GetEditRange", + "Excel_Cs_GetEmptyCell", + "Excel_Cs_GetLastEmptyCell", + "Excel_Cs_GetName", + "Excel_Cs_GetPath", + "Excel_Cs_Group", + "Excel_Cs_Hide", + "Excel_Cs_Insert", + "Excel_Cs_InsertColumn", + "Excel_Cs_InsertColumnV2", + "Excel_Cs_InsertColumnV3", + "Excel_Cs_InsertPicture", + "Excel_Cs_InsertPictureV2", + "Excel_Cs_InsertPivotTable", + "Excel_Cs_InsertPivotView", + "Excel_Cs_InsertRow", + "Excel_Cs_InsertRowV2", + "Excel_Cs_InsertRowV3", + "Excel_Cs_Interop", + "Excel_Cs_Load", + "Excel_Cs_LoadV2", + "Excel_Cs_Merge", + "Excel_Cs_MergeCells", + "Excel_Cs_MergeCellsV2", + "Excel_Cs_Move", + "Excel_Cs_New", + "Excel_Cs_NewV2", + "Excel_Cs_NewV3", + "Excel_Cs_NewV4", + "Excel_Cs_NewV5", + "Excel_Cs_Open", + "Excel_Cs_OpenV2", + "Excel_Cs_OpenV3", + "Excel_Cs_OpenV4", + "Excel_Cs_PastRange", + "Excel_Cs_PastRangeV2", + "Excel_Cs_ReadCell", + "Excel_Cs_ReadCellBackground", + "Excel_Cs_ReadCellFormula", + "Excel_Cs_ReadColumn", + "Excel_Cs_ReadColumnCount", + "Excel_Cs_ReadContent", + "Excel_Cs_ReadContentV2", + "Excel_Cs_ReadContentV3", + "Excel_Cs_ReadContentV4", + "Excel_Cs_ReadRange", + "Excel_Cs_ReadRangeV2", + "Excel_Cs_ReadRow", + "Excel_Cs_ReadRowCount", + "Excel_Cs_RefreshAll", + "Excel_Cs_RefreshPivotTable", + "Excel_Cs_Rename", + "Excel_Cs_RunMacro", + "Excel_Cs_RunMacroV2", + "Excel_Cs_Save", + "Excel_Cs_SaveAs", + "Excel_Cs_Search", + "Excel_Cs_SelectRange", + "Excel_Cs_SelectRangeV2", + "Excel_Cs_SelectRangeV3", + "Excel_Cs_SetCellBackground", + "Excel_Cs_SetCellFont", + "Excel_Cs_SetCellFormat", + "Excel_Cs_SetCellFormat_V2", + "Excel_Cs_SetCellFormat_V3", + "Excel_Cs_SetHeight", + "Excel_Cs_SetHeightV1", + "Excel_Cs_SetRangeBackground", + "Excel_Cs_SetRangeBackgroundV2", + "Excel_Cs_SetRangeFont", + "Excel_Cs_SetRangeFontV2", + "Excel_Cs_SetSlicer", + "Excel_Cs_SetWidth", + "Excel_Cs_SetWidthV1", + "Excel_Cs_ShowTableStyle", + "Excel_Cs_Sort", + "Excel_Cs_SortV1", + "Excel_Cs_WriteCell", + "Excel_Cs_WriteCellV2", + "Excel_Cs_WriteColumn", + "Excel_Cs_WriteContent", + "Excel_Cs_WriteRange", + "Excel_Cs_WriteRangeV2", + "Excel_Cs_WriteRow", + "Excel_Cs_WriteRowV2", + "Excel_DeleteColumn", + "Excel_DeleteImage", + "Excel_DeleteRange", + "Excel_DeleteRow", + "Excel_DeleteSheet", + "Excel_ExecuteMacro", + "Excel_ExportRangeAsPicture", + "Excel_GetColData", + "Excel_GetColDataNew", + "Excel_GetColumnId", + "Excel_GetColumnsCount", + "Excel_GetPath", + "Excel_GetRowData", + "Excel_GetRowDataNew", + "Excel_GetRowsCount", + "Excel_GetSheetNames", + "Excel_GetSheetsName", + "Excel_InsertColumn", + "Excel_InsertImage", + "Excel_InsertRow", + "Excel_InsertSheet", + "Excel_Loop", + "Excel_New", + "Excel_NewExcel", + "Excel_Open", + "Excel_OpenExcel", + "Excel_OpenExcelNew", + "Excel_PasteRange", + "Excel_ReadCell", + "Excel_ReadCellNew", + "Excel_ReadRange", + "Excel_ReadRangeNew", + "Excel_RenameSheet", + "Excel_Save", + "Excel_SaveAs", + "Excel_SaveV2", + "Excel_SelectRange", + "Excel_SetCellColor", + "Excel_SetCellFontColor", + "Excel_SetColumnWidth", + "Excel_SetRangeColor", + "Excel_SetRangeFontColor", + "Excel_SetRowHeight", + "Excel_WriteCell", + "Excel_WriteCellNew", + "Excel_WriteColumn", + "Excel_WriteColumnNew", + "Excel_WriteRange", + "Excel_WriteRangeNew", + "Excel_WriteRow", + "Excel_WriteRowNew", + "ExceptionUtil_Throws", + "FTP_Connect", + "FTP_CreateDir", + "FTP_Cwd", + "FTP_Delete", + "FTP_Disconnect", + "FTP_Download", + "FTP_Exist", + "FTP_GetFileList", + "FTP_Rename", + "FTP_Upload", + "FileTypeConversion_Office2pdf", + "FileTypeConversion_Pdf2image2", + "File_CompressFile", + "File_Copy", + "File_Copy_V1", + "File_CreateFile", + "File_CreateFolder", + "File_DecompressFile", + "File_Delete", + "File_DeleteFile", + "File_EmptyFolder", + "File_FileExists", + "File_File_Move", + "File_GetFileInfo", + "File_GetFileList", + "File_GetFileList_V1", + "File_GetFolderList", + "File_GetFolderList_V1", + "File_MakeDir", + "File_MakeFolder", + "File_Move", + "File_MoveFolder", + "File_OpenFile", + "File_PathExists", + "File_PathSize", + "File_PathSizeNew", + "File_Read", + "File_ReadXml", + "File_Rename", + "File_Rename_V1", + "File_WaitFile", + "File_Write", + "File_Write_V1", + "GoogleTable_ChangeSheet", + "GoogleTable_CopyPasteSheet", + "GoogleTable_DownloadSheets", + "GoogleTable_GetAllData", + "GoogleTable_GetAllSheetsName", + "GoogleTable_GetColumnsByTableTitle", + "GoogleTable_GetSheetRowCount", + "GoogleTable_RenameSheet", + "GoogleTable_WriteToSheetCell", + "GoogleTable_WriteToSheetCellFormula", + "GoogleTable_WriteToSheetRegionColumns", + "GoogleTable_WriteToSheetRegionRows", + "GoogleTable_WriteToSheetRegionregion", + "Http_Get", + "Http_Get_V1", + "Http_Get_V2", + "Http_Http_Request", + "Http_Post", + "Http_Post_V2", + "Http_Post_V3", + "Image_Base64Decode", + "Image_Base64Encode", + "Image_Click", + "Image_Click_V1", + "Image_Click_V2", + "Image_Click_V3", + "Image_CropImg", + "Image_Exists", + "Image_Exists_V1", + "Image_Find", + "Image_Find_V1", + "Image_Location", + "Image_Location_V1", + "Image_Move", + "Image_Move_V1", + "Image_Move_V2", + "Image_RelativePosition", + "Image_Screenshot", + "Image_Wait", + "Image_Wait_V1", + "Ini_DeleteKey", + "Ini_DeleteSection", + "Ini_ListKey", + "Ini_ListSection", + "Ini_Read", + "Ini_Write", + "JSON_Parse", + "JSON_Stringify", + "Keyboard_DisableManualOperation", + "Keyboard_DriveSend", + "Keyboard_DriveSend_V1", + "Keyboard_DriveSend_V2", + "Keyboard_EnableManualOperation", + "Keyboard_Press", + "Keyboard_PressNew", + "Keyboard_Send", + "Keyboard_Send_V1", + "List_ClearList", + "List_CreateList", + "List_DeleteList", + "List_GetIndex", + "List_GetListItem", + "List_InsertList", + "List_ListDuplication", + "List_ListIntersection", + "List_ListLength", + "List_ListMerge", + "List_ListSorted", + "List_SetListItem", + "Log_Error", + "Log_Info", + "Mail_DoGetMailMessage", + "Mail_DoGetMailMessage_v1", + "Mail_DoGetMailMessage_v2", + "Mail_DoMoveMail", + "Mail_DoMoveMail_v1", + "Mail_DoReplyMail", + "Mail_DoReplyMail_v1", + "Mail_DoSendMail", + "Mail_DoSendMail_v1", + "Mail_ExConnect", + "Mail_ExOperateMail", + "Mail_ExSearchMail", + "Mail_ExSendMail", + "Mail_FindMail", + "Mail_FindMail_v1", + "Mail_FindMail_v2", + "Mail_MarkSeen", + "Mail_OperateMail", + "Mail_RecvClose", + "Mail_RecvConnect", + "Mail_RecvCount", + "Mail_RecvGetList", + "Mail_RecvMailGet", + "Mail_ReplyMail", + "Mail_ReplyMail_v1", + "Mail_ReplyMail_v2", + "Mail_Send", + "Mail_Send_V1", + "Mail_UnionConnect", + "Mail_UnionSend", + "Mail_UnionSend_v1", + "Mail_UnmarkSeen", + "Math_Abs", + "Math_Cos", + "Math_Exp", + "Math_Hex", + "Math_Int", + "Math_Oct", + "Math_Pow", + "Math_Round", + "Math_Scale", + "Math_Sgn", + "Math_Sin", + "Math_Sqrt", + "Math_Tan", + "MessageNotification_DingTalk_Message", + "MessageNotification_Feishu_Message", + "MessageNotification_WXWork_Message", + "Mouse_Click", + "Mouse_ClickCombine", + "Mouse_ClickCombine_v1", + "Mouse_ClickCombine_v2", + "Mouse_ClickCombine_v3", + "Mouse_ClickCombine_v4", + "Mouse_ClickNew", + "Mouse_Drag", + "Mouse_DragTo", + "Mouse_DragToNew", + "Mouse_DragToV1", + "Mouse_DragToV2", + "Mouse_Move", + "Mouse_MoveTo", + "Mouse_MoveToV1", + "Mouse_MoveToV2", + "Mouse_RollTo", + "Mouse_Scroll", + "NLP_AnalyseProductReview", + "NLP_BatchAnalyseProductReview", + "NLP_EmotionalAnalysis", + "NLP_KeyWordsAnalysis", + "NLP_PerspectiveAnalysis", + "NLP_SemanticSimilarity", + "NLP_SplitText", + "NLP_SplitWords", + "NLP_XunFei_FeelingAnalysis", + "NLP_XunFei_KeywordExtraction", + "NLP_XunFei_MachineTranslation", + "NLP_XunFei_NLPBaseServer", + "OCR_AccountPageV2", + "OCR_AmountIdentification", + "OCR_BankCardV2", + "OCR_BankCardV3", + "OCR_BusinessCardV2", + "OCR_BusinessLicenseV2", + "OCR_BusinessLicenseV3", + "OCR_CalculationCode", + "OCR_CommonEnglishNumbersCode", + "OCR_DriverLicenseV2", + "OCR_DrivingLicenseV2", + "OCR_GeneralTextV2", + "OCR_HouseCertV2", + "OCR_IdCardV2", + "OCR_IdCardV3", + "OCR_KeyValueIdentification", + "OCR_MergeCarOCR", + "OCR_MergeCardOCR", + "OCR_MergeEducationOCR", + "OCR_MergeGeneralOCR", + "OCR_MergeOtherOCR", + "OCR_MergePaperOCR", + "OCR_OfficialSealV2", + "OCR_PassportV2", + "OCR_PlateLicenseV2", + "OCR_RealEstateCertV2", + "OCR_TaxiInvoiceV2", + "OCR_TrainTicketV2", + "OCR_VatInvoiceV2", + "OCR_VatInvoiceV3", + "OCR_VehicleInvoiceV2", + "OCR_VinV2", + "OcrOffline_GetOcrTable", + "OcrOffline_GetOcrTextNew", + "OcrOffline_GetOcrTextPosition", + "PDF_ConcatPdf", + "PDF_ConcatPdfV1", + "PDF_CreateNewPdf", + "PDF_GetPageCount", + "PDF_GetPdfImg", + "PDF_GetPdfInformation", + "PDF_GetPdfPageNum", + "PDF_GetPdfTable", + "PDF_GetPdfText", + "PDF_PdfEncryption", + "PDF_PdfToImg", + "PDF_SetPdfWaterMark", + "PDF_SetPdfWaterMarkV1", + "Regex_Find", + "Regex_FindAll", + "Regex_FindAllNew", + "Regex_FindNew", + "Regex_FindNew_1", + "Regex_FindStr", + "Regex_FindStrV1", + "Regex_Test", + "Regex_TestNew", + "Scenario_TextComparison", + "ScreenControl_ScreenUnlock", + "ScreenControl_Screenlock", + "StrUtil_AddToStr", + "StrUtil_CaseChange", + "StrUtil_CharAsc", + "StrUtil_CharCode", + "StrUtil_CompleteStr", + "StrUtil_CreateRandomStr", + "StrUtil_CutOutStr", + "StrUtil_CutOutStrV1", + "StrUtil_DelTrim", + "StrUtil_InStr", + "StrUtil_Left", + "StrUtil_Len", + "StrUtil_ListToString", + "StrUtil_LookUpStr", + "StrUtil_LowerCase", + "StrUtil_Ltrim", + "StrUtil_Mid", + "StrUtil_Replace", + "StrUtil_ReverseStr", + "StrUtil_Right", + "StrUtil_Rtrim", + "StrUtil_Split", + "StrUtil_SplitStr", + "StrUtil_Trim", + "StrUtil_UpperCase", + "System_AddCredential", + "System_CloseRemoteDesktop", + "System_ConnectRemoteDesktop", + "System_DeleteCredential", + "System_ExecuteCommand", + "System_ExecuteCommandV1", + "System_GetEnv", + "System_GetHomePath", + "System_GetInputMethodState", + "System_GetSystemPath", + "System_GetTempPath", + "System_PlaySound", + "System_ReadCredential", + "System_ScreenSaverShow", + "System_ScreenSaverShowV1", + "System_ScreenSaverStop", + "System_SetEnv", + "System_SetInputMethodState", + "Time_CalDate", + "Time_Date", + "Time_DateOffset", + "Time_DateOffset_V1", + "Time_DateToTimestamp", + "Time_DatetimeToTimestamp", + "Time_Day", + "Time_Format", + "Time_FormatNew", + "Time_GetDate", + "Time_GetDateV1", + "Time_GetDateV2", + "Time_GetDatetimeObj", + "Time_Hour", + "Time_Minute", + "Time_Month", + "Time_Now", + "Time_Second", + "Time_Time", + "Time_TimeStamp", + "Time_TimeTypeConversion", + "Time_TimeTypeConversion_V1", + "Time_WeekDay", + "Time_Year", + "Trigger.FileArrival", + "Trigger.Manual", + "Trigger.Schedule", + "WebBrowser_BatchDataCrawl", + "WebBrowser_BatchDataCrawlNew", + "WebBrowser_BatchDataCrawlNewV1", + "WebBrowser_Close", + "WebBrowser_CloseWeb", + "WebBrowser_CloseWeb_V1", + "WebBrowser_CloseWeb_V2", + "WebBrowser_Close_V1", + "WebBrowser_Create", + "WebBrowser_CreateBackground", + "WebBrowser_CreateV2", + "WebBrowser_CreateV3", + "WebBrowser_DataCollection", + "WebBrowser_DataCollectionV1", + "WebBrowser_DataCollectionV2", + "WebBrowser_DataCollectionV3", + "WebBrowser_DataCollectionV4", + "WebBrowser_DataCollectionV5", + "WebBrowser_DataCrawl", + "WebBrowser_DataCrawl_software", + "WebBrowser_DataCrawl_web", + "WebBrowser_DataCrawler", + "WebBrowser_DownFile", + "WebBrowser_DownFile_V1", + "WebBrowser_DownloadFile", + "WebBrowser_DownloadFile_V1", + "WebBrowser_GetBrowserPic", + "WebBrowser_GetBrowserPicV1", + "WebBrowser_GetCookie", + "WebBrowser_GetCookieNew", + "WebBrowser_GetCookies", + "WebBrowser_GetDocument", + "WebBrowser_GetScrollPos", + "WebBrowser_GetScrollPos_V1", + "WebBrowser_GetTAB", + "WebBrowser_GetTAB_V1", + "WebBrowser_GetTAB_V2", + "WebBrowser_GetTitle", + "WebBrowser_GetUrl", + "WebBrowser_GetWeblistening", + "WebBrowser_GoBack", + "WebBrowser_GoForward", + "WebBrowser_GoUrl", + "WebBrowser_Maximize", + "WebBrowser_Minimize", + "WebBrowser_Navigate", + "WebBrowser_Reload", + "WebBrowser_RunJs", + "WebBrowser_RunJsInIeBySelector", + "WebBrowser_RunJsInIeBySelectorGround", + "WebBrowser_RunJsInIeBySelector_v1", + "WebBrowser_RunJsInIeBySelector_v2", + "WebBrowser_RunJsInIeBySelector_v3", + "WebBrowser_RunJsInIeByTitle", + "WebBrowser_SaveAs", + "WebBrowser_SaveAs_V1", + "WebBrowser_Screenshot", + "WebBrowser_SetCookies", + "WebBrowser_SetCookies_V1", + "WebBrowser_SetScrollPos", + "WebBrowser_SetScrollPos_V1", + "WebBrowser_StartWeblistening", + "WebBrowser_Stop", + "WebBrowser_StopWeblistening", + "WebBrowser_Switch", + "WebBrowser_Switch_V1", + "WebBrowser_Upload", + "WebBrowser_UploadDialog", + "WebBrowser_Wait", + "Window_Activate", + "Window_ActiveWindow", + "Window_ActiveWindow_v1", + "Window_Close", + "Window_CloseWindow", + "Window_CloseWindow_v1", + "Window_Exists", + "Window_Get", + "Window_GetActive", + "Window_GetActiveWindow", + "Window_GetRect", + "Window_GetScreenSize", + "Window_GetWindow", + "Window_GetWindowMessage", + "Window_GetWindowMessage_v1", + "Window_GetWindowRect", + "Window_GetWindow_v1", + "Window_MaximumSize", + "Window_MoveWindow", + "Window_MoveWindow_v1", + "Window_SetActive", + "Window_SetPos", + "Window_SetWindowShow", + "Window_SetWindowState", + "Window_SetWindowState_v1", + "Window_SizeWindow", + "Window_SizeWindow_v1", + "Window_WaitWindow", + "Window_WindowExists", + "Window_WindowList", + "Word_Close", + "Word_CopySelect", + "Word_CutSelect", + "Word_DeleteSelect", + "Word_Enter", + "Word_GetPath", + "Word_InsertPage", + "Word_InsertPicture", + "Word_MovePosition", + "Word_New", + "Word_New_V1", + "Word_Open", + "Word_PasteSelect", + "Word_PositionToSelect", + "Word_ReadAll", + "Word_ReadSelect", + "Word_ReadTable", + "Word_Replace", + "Word_Save", + "Word_SaveAs", + "Word_SelectAll", + "Word_SelectRow", + "Word_SetAlign", + "Word_SetFontColor", + "Word_SetFontName", + "Word_SetFontSize", + "Word_SetFontStyle", + "Word_SetPosition", + "Word_Write", + "Word_WriteTable", + "child_modules_v1", + "concurrent_child_process_v1", + "logic_control_break_for", + "logic_control_if_ai_vision", + "logic_control_next_for", + "logic_control_stop", + "logic_control_stop_return", + "logic_control_var" + ] +} diff --git a/scripts/capability-snapshot.test.ts b/scripts/capability-snapshot.test.ts new file mode 100644 index 0000000..03e61f8 --- /dev/null +++ b/scripts/capability-snapshot.test.ts @@ -0,0 +1,36 @@ +/** + * 能力注册快照(任务 0.3,见 docs/rpa-core-refactor-tasks.md) + * + * 以与生产完全相同的路径(import "../src/main/capabilities" 的副作用注册) + * 拉起全部能力模块,把运行时注册表的 id 清单写入 + * resources/capability-snapshot.json。 + * + * 用法:npm run snapshot + * 抽离改造各阶段完成后重跑并 git diff,快照变化必须为零(行为回归基准)。 + */ +import { writeFileSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, it } from "vitest"; +import { capabilityCount, capabilityIds } from "../src/main/capabilities"; + +const OUT_FILE = path.join( + path.dirname(fileURLToPath(import.meta.url)), + "..", + "resources", + "capability-snapshot.json" +); + +describe("能力注册快照", () => { + it("全量注册后导出能力 id 清单", () => { + const ids = [...capabilityIds()].sort(); + expect(ids.length).toBeGreaterThan(0); + const snapshot = { + generatedAt: new Date().toISOString(), + count: ids.length, + ids + }; + writeFileSync(OUT_FILE, JSON.stringify(snapshot, null, 2) + "\n", "utf8"); + console.log(`[能力快照] ${capabilityCount()} 个能力已写入 ${path.basename(OUT_FILE)}`); + }); +}); diff --git a/src/main/capabilities/data-file-smoke.test.ts b/src/main/capabilities/data-file-smoke.test.ts index c5487f0..37145d2 100644 --- a/src/main/capabilities/data-file-smoke.test.ts +++ b/src/main/capabilities/data-file-smoke.test.ts @@ -1,9 +1,8 @@ import { mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; -import { readFileSync } from "node:fs"; import { afterAll, describe, expect, it } from "vitest"; -import { getHandler } from "../engine/registry"; +import { capabilityIds, getHandler } from "../engine/registry"; import { RuntimeError } from "../engine/types"; import type { CatalogComponent, FlowNode } from "../../shared/types"; import type { RunContext } from "../engine/types"; @@ -195,10 +194,10 @@ describe("数据处理/文件/编排 冒烟", () => { expect(await run("File_FileExists", { path: copy })).toBe(false); const renamed = await run("File_Rename", { pathSrc: moved, name: "renamed.txt" }); expect(String(renamed)).toContain("renamed.txt"); - const zip = await run("File_CompressFile", { pathSrc: created, pathDest: path.join(sandbox, "pack.zip") }); + const zip = await run("File_CompressFile", { pathSrc: created, pathDest: path.join(sandbox, "pack.zip"), direct_type: "0" }); expect(String(zip)).toContain("pack.zip"); const unzipDir = path.join(sandbox, "unpacked"); - await run("File_DecompressFile", { path: path.join(sandbox, "pack.zip"), target: unzipDir }); + await run("File_DecompressFile", { path: path.join(sandbox, "pack.zip"), target: unzipDir, direct_type: "0" }); expect(await run("File_FileExists", { path: path.join(unzipDir, "a.txt") })).toBe(true); expect(await run("File_WaitFile", { file_path: created, time_out: 1 })).toBe(true); await expect(run("File_WaitFile", { file_path: path.join(dir, "ghost.txt"), time_out: 1 })).rejects.toThrow(/超时/); @@ -252,9 +251,7 @@ describe("数据处理/文件/编排 冒烟", () => { }); it("全量健康检查: 已注册组件空参调用不产生非结构化崩溃", async () => { - const ids: string[] = JSON.parse( - readFileSync("D:/wordkb/2026-10-28-10-36-47/PRA-only-demo/live-ids.json", "utf8") - ) as string[]; + const ids: string[] = capabilityIds(); const skip = new Set([ "FTP_Connect", "FTP_Upload", "FTP_Download", "FTP_Delete", "FTP_Rename", "FTP_Cwd", "FTP_GetFileList", "FTP_CreateDir", "FTP_Exist", "FTP_Disconnect", "Database_DBConnect", "Database_SQLExecute", "Database_SingleSQLQuery", "Database_AllSQLQuery_V1", "Database_BatchSQLExecute", "Database_BatchInsertExecute", "Database_CloseDBConnect", diff --git a/src/main/capabilities/keyboard-send-smoke.test.ts b/src/main/capabilities/keyboard-send-smoke.test.ts index 78c3215..2bdd632 100644 --- a/src/main/capabilities/keyboard-send-smoke.test.ts +++ b/src/main/capabilities/keyboard-send-smoke.test.ts @@ -64,14 +64,29 @@ describe("键盘输入组件真实冒烟", () => { const { promisify } = await import("node:util"); const runPs = promisify(execFile); const ps = (cmd: string) => runPs("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", cmd], { windowsHide: true, timeout: 30000 }); - // Win11 记事本窗口标题是「无标题 - Notepad」; 沙盒内 Start-Process notepad 别名解析失败, 用完整路径 - await ps("Start-Process $env:SystemRoot\\System32\\notepad.exe; $diag=''; $ok=$false; foreach($i in 1..24){ $procs=Get-Process Notepad -ErrorAction SilentlyContinue; if($procs){ $diag=\"procs:$($procs.Count) titles:$(($procs|ForEach-Object{$_.MainWindowTitle}) -join '|')\"; $p=Get-Process | Where-Object {$_.MainWindowTitle -like '*Notepad*'}; if($p){$ok=$true; break} } else { $diag='no-process' }; Start-Sleep -Milliseconds 500 }; if(-not $ok){ throw \"notepad not visible: $diag\" }"); + // 窗口标题随系统语言变化(英文 Notepad / 中文 记事本), 不硬编码, 启动后动态取实际标题 + await ps("Start-Process $env:SystemRoot\\System32\\notepad.exe; $diag=''; $ok=$false; foreach($i in 1..24){ $procs=Get-Process Notepad -ErrorAction SilentlyContinue; if($procs){ $p=$procs | Where-Object {$_.MainWindowTitle}; if($p){$ok=$true; break} } else { $diag='no-process' }; Start-Sleep -Milliseconds 500 }; if(-not $ok){ throw \"notepad not visible: $diag\" }"); try { - await invoke("Keyboard_Send_V1", { words: "目标窗口输入'测试", interval: "5", fuctype: "1", window_title: "Notepad" }); + const titlePs = "[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new($false); (Get-Process Notepad | Where-Object { $_.MainWindowTitle } | Select-Object -First 1).MainWindowTitle"; + const title = (await ps(titlePs)).stdout.trim(); + expect(title.length).toBeGreaterThan(0); + // GUI 焦点抢占受系统前台锁约束, 偶发失败属正常抖动, 有界重试 + let lastErr: unknown; + for (let attempt = 1; attempt <= 3; attempt += 1) { + try { + await invoke("Keyboard_Send_V1", { words: "目标窗口输入'测试", interval: "5", fuctype: "1", window_title: title }); + lastErr = undefined; + break; + } catch (error) { + lastErr = error; + await new Promise((r) => setTimeout(r, 1000)); + } + } + if (lastErr) throw lastErr; await new Promise((r) => setTimeout(r, 300)); - // activateWindowScript 内部已校验前台句柄=目标窗口, 这里再确认记事本进程窗口标题匹配 - const fg = await ps("[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new($false); (Get-Process Notepad | Where-Object { $_.MainWindowTitle } | Select-Object -First 1).MainWindowTitle"); - expect(fg.stdout).toContain("Notepad"); + // activateWindowScript 内部已校验前台句柄=目标窗口, 这里再确认前台标题仍是记事本(输入后标题会带 * 脏标记前缀) + const fg = await ps(titlePs); + expect(fg.stdout.trim()).toContain(title); console.log("[键盘输入] 目标窗口激活 ✓ 前台:", fg.stdout.trim()); } finally { await ps("Get-Process notepad* -ErrorAction SilentlyContinue | Stop-Process -Force").catch(() => {}); diff --git a/src/main/capabilities/mouse-moveto-smoke.test.ts b/src/main/capabilities/mouse-moveto-smoke.test.ts index 2495d6e..5716a0c 100644 --- a/src/main/capabilities/mouse-moveto-smoke.test.ts +++ b/src/main/capabilities/mouse-moveto-smoke.test.ts @@ -30,6 +30,17 @@ async function cursorPos(): Promise<[number, number]> { return stdout.trim().split(",").map(Number) as [number, number]; } +/** 共享桌面环境下光标可能被其他进程短暂挪动,轮询等待落位(容差 px),超时返回最后一次读数 */ +async function waitForCursor(target: [number, number], tolerance = 0, attempts = 10, gapMs = 100): Promise<[number, number]> { + let pos = await cursorPos(); + for (let i = 0; i < attempts; i += 1) { + if (Math.abs(pos[0] - target[0]) <= tolerance && Math.abs(pos[1] - target[1]) <= tolerance) return pos; + await new Promise((r) => setTimeout(r, gapMs)); + pos = await cursorPos(); + } + return pos; +} + async function invoke(componentId: string, args: Record): Promise { const handler = getHandler(componentId); expect(handler).toBeTypeOf("function"); @@ -47,8 +58,7 @@ describe("移动鼠标组件真实冒烟", () => { // 用户屏幕框选生成的浮点对象坐标(此前直接报「鼠标坐标无效」) const out = await invoke("Mouse_MoveToV2", { location: { x: 1397, y: 227.60000610351562 }, position: "0", move_type: "2", speed: 100 }) as { x: number; y: number }; expect(out).toEqual({ x: 1397, y: 228 }); - await new Promise((r) => setTimeout(r, 150)); - const pos = await cursorPos(); + const pos = await waitForCursor([1397, 228]); expect(pos[0]).toBe(1397); expect(pos[1]).toBe(228); console.log("[移动鼠标] 对象坐标解析 + 瞬间移动落位 ✓ 实际光标:", pos); @@ -58,8 +68,7 @@ describe("移动鼠标组件真实冒烟", () => { original = await cursorPos(); const out = await invoke("Mouse_MoveToV2", { location: "[300,300]", position: "0", move_type: "0", speed: 60 }) as { x: number; y: number }; expect(out).toEqual({ x: 300, y: 300 }); - await new Promise((r) => setTimeout(r, 200)); - const pos = await cursorPos(); + const pos = await waitForCursor([300, 300], 2); expect(Math.abs(pos[0] - 300)).toBeLessThanOrEqual(2); expect(Math.abs(pos[1] - 300)).toBeLessThanOrEqual(2); console.log("[移动鼠标] 模拟人工移动 ✓ 实际光标:", pos); @@ -69,7 +78,7 @@ describe("移动鼠标组件真实冒烟", () => { original = await cursorPos(); const out = await invoke("Mouse_MoveToV2", { location: "[500,400]", position: "0", move_type: "1", speed: 80 }) as { x: number; y: number }; expect(out).toEqual({ x: 500, y: 400 }); - const pos = await cursorPos(); + const pos = await waitForCursor([500, 400]); expect(pos[0]).toBe(500); expect(pos[1]).toBe(400); console.log("[移动鼠标] 匀速直线 + 字符串坐标 ✓ 实际光标:", pos); diff --git a/src/main/capabilities/net-message-smoke.test.ts b/src/main/capabilities/net-message-smoke.test.ts index 8c4f7ca..1a2e7f5 100644 --- a/src/main/capabilities/net-message-smoke.test.ts +++ b/src/main/capabilities/net-message-smoke.test.ts @@ -121,21 +121,30 @@ describe("网络与消息组件冒烟", () => { it("Http_Http_Request: PUT方法+Cookie+保存响应", async () => { const { server, port, requests } = await startHttpServer(); - const saveTo = "D:/office-test2/http-smoke-response.json"; - await run("Http_Http_Request", { - url: `http://127.0.0.1:${port}/update`, - method: "PUT", - body: "raw-payload", - cookies: JSON.stringify({ session: "s-77", lang: "zh" }), - file_path: saveTo - }); - server.close(); - expect(requests[0].method).toBe("PUT"); - expect(requests[0].headers.cookie).toBe("session=s-77; lang=zh"); - const { readFileSync } = await import("node:fs"); - const saved = JSON.parse(readFileSync(saveTo, "utf8")) as { echo: string }; - expect(saved.echo).toBe("raw-payload"); - console.log("[Http_Http_Request] 通过: PUT+Cookie+响应落盘均正确"); + // 保存路径用系统临时目录,不硬编码盘符路径(可移植 + 沙盒可写) + const { tmpdir } = await import("node:os"); + const { join } = await import("node:path"); + const { mkdtempSync, rmSync } = await import("node:fs"); + const saveDir = mkdtempSync(join(tmpdir(), "rpa-http-smoke-")); + const saveTo = join(saveDir, "http-smoke-response.json"); + try { + await run("Http_Http_Request", { + url: `http://127.0.0.1:${port}/update`, + method: "PUT", + body: "raw-payload", + cookies: JSON.stringify({ session: "s-77", lang: "zh" }), + file_path: saveTo + }); + server.close(); + expect(requests[0].method).toBe("PUT"); + expect(requests[0].headers.cookie).toBe("session=s-77; lang=zh"); + const { readFileSync } = await import("node:fs"); + const saved = JSON.parse(readFileSync(saveTo, "utf8")) as { echo: string }; + expect(saved.echo).toBe("raw-payload"); + console.log("[Http_Http_Request] 通过: PUT+Cookie+响应落盘均正确"); + } finally { + rmSync(saveDir, { recursive: true, force: true }); + } }); it("Http 错误路径: 5xx 明确报错 + 超时报错", async () => { diff --git a/src/main/capabilities/web-real-smoke.test.ts b/src/main/capabilities/web-real-smoke.test.ts index 29476c8..e923c0f 100644 --- a/src/main/capabilities/web-real-smoke.test.ts +++ b/src/main/capabilities/web-real-smoke.test.ts @@ -1,5 +1,6 @@ import { createServer, type Server } from "node:http"; -import { promises as fs } from "node:fs"; +import { mkdtempSync, promises as fs, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; import path from "node:path"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; import type { CatalogComponent, FlowNode } from "../../shared/types"; @@ -44,7 +45,8 @@ const PAGE_DISABLED = ``; let server: Server; let baseUrl = ""; -const outDir = "D:/office-test2/web-test"; +// 输出目录用系统临时目录,不硬编码盘符路径(可移植 + 沙盒可写) +const outDir = mkdtempSync(path.join(tmpdir(), "rpa-web-smoke-")); const uploadFile = path.join(outDir, "upload-src.txt"); let browser: BrowserLike; let ctx: RunContext; @@ -93,7 +95,8 @@ beforeAll(async () => { afterAll(async () => { try { await browser?.close(); } catch { /* 进程退出兜底 */ } - await new Promise((resolve) => server.close(() => resolve())); + await new Promise((resolve) => { server.close(() => resolve()); }); + rmSync(outDir, { recursive: true, force: true }); }); describe("网页自动化真实冒烟(Chrome 无头 + CDP)", () => { diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..aa3ba6b --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + // 桌面自动化冒烟测试(键盘/鼠标/窗口焦点/剪贴板)共用同一物理桌面, + // 并发执行会互相抢占焦点导致偶发失败,因此测试文件一律串行执行。 + fileParallelism: false + } +});