// electron/test.js - ESM 模块版本 // Monkey Testing 和开发工具模块 import { writeLog } from '../src/log/log-writer.js'; import { BrowserWindow, ipcMain, Menu, globalShortcut } from 'electron'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; // 工具函数:安全的 JSON 序列化 function safeStringify(obj) { const cache = new Set(); return JSON.stringify(obj, (key, value) => { if (typeof value === 'object' && value !== null) { if (cache.has(value)) { return '[Circular]'; } cache.add(value); } return value; }); } // -------------- 命令行参数解析 -------------- /** * 解析命令行参数 * @returns {Object} 解析后的选项 */ export function parseCommandLineArgs() { const args = process.argv; return { enableMonkeyTesting: args.includes('--enable-monkey-testing'), enableDevMenu: args.includes('--enable-dev-menu'), enableDevTools: args.includes('--enable-dev-tools') }; } // -------------- Monkey Testing 功能类 -------------- /** * Monkey Testing 测试器 * 用于模拟随机的用户操作,进行压力测试 */ export class MonkeyTester { /** * 创建 MonkeyTester 实例 * @param {BrowserWindow} win - Electron 窗口实例 * @param {boolean} isMac - 是否为macOS平台 * @param {BrowserWindow} mainWindow - 主窗口实例 */ constructor(win, isMac = false, mainWindow = null) { this.win = win; this.isMac = isMac; this.mainWindow = mainWindow; this.active = false; this.interval = null; this.originalMenu = null; // 保存原始菜单 } /** * 获取随机位置(在窗口内容区域内) * @returns {Object} {x, y} 坐标 */ getRandomPosition() { const bounds = this.win.getContentBounds(); const margin = 5; // 安全边距,避免点击到窗口边缘 return { x: Math.floor(Math.random() * (bounds.width - 2 * margin)) + margin, y: Math.floor(Math.random() * (bounds.height - 2 * margin)) + margin }; } /** * 移动鼠标到指定位置 */ moveMouseTo(x, y) { if (this.win && !this.win.isDestroyed()) { this.win.webContents.sendInputEvent({ type: 'mouseMove', x: x, y: y }); } } /** * 模拟点击操作 */ performClick(x, y, button = 'left') { if (this.win && !this.win.isDestroyed()) { // 鼠标按下 this.win.webContents.sendInputEvent({ type: 'mouseDown', x: x, y: y, button: button }); // 短暂延迟后释放 setTimeout(() => { if (this.win && !this.win.isDestroyed()) { this.win.webContents.sendInputEvent({ type: 'mouseUp', x: x, y: y, button: button }); } }, 50); } } /** * 模拟键盘输入 */ simulateKeyPress(key) { if (this.win && !this.win.isDestroyed()) { this.win.webContents.sendInputEvent({ type: 'keyDown', keyCode: key }); setTimeout(() => { if (this.win && !this.win.isDestroyed()) { this.win.webContents.sendInputEvent({ type: 'keyUp', keyCode: key }); } }, 50); } } /** * 执行随机操作 */ performRandomOperation() { if (!this.win || this.win.isDestroyed()) return; const operations = ['move', 'click', 'doubleClick', 'rightClick', 'keyPress']; const operation = operations[Math.floor(Math.random() * operations.length)]; const pos = this.getRandomPosition(); switch (operation) { case 'move': this.moveMouseTo(pos.x, pos.y); break; case 'click': this.performClick(pos.x, pos.y); break; case 'doubleClick': this.performClick(pos.x, pos.y); this.performClick(pos.x, pos.y); break; case 'rightClick': this.performClick(pos.x, pos.y, 'right'); break; case 'keyPress': const keys = ['a', 'b', 'c', 'Enter', 'Space', 'Tab']; const key = keys[Math.floor(Math.random() * keys.length)]; this.simulateKeyPress(key); break; } } /** * 启动 Monkey Testing * @param {Object} options - 配置选项 * @param {number} options.interval - 操作间隔(ms) * @param {number} options.duration - 持续时间(ms) * @param {number} options.maxOperations - 最大操作次数 */ start(options = {}) { if (this.active) return; const { interval = 100, duration = 2147483646, maxOperations = 600000 } = options; this.active = true; let operationCount = 0; writeLog('info', `启动monkey testing: 间隔${interval}ms, 持续${duration}ms, 最大操作${maxOperations}次`); // 保存原始菜单并隐藏菜单 this.originalMenu = Menu.getApplicationMenu(); Menu.setApplicationMenu(null); writeLog('info', '菜单已隐藏,测试期间不可见'); // 注册全局快捷键 Ctrl+Alt+M 来显示菜单 globalShortcut.register('CommandOrControl+Alt+M', () => { if (this.originalMenu) { Menu.setApplicationMenu(this.originalMenu); writeLog('info', '菜单已通过快捷键显示'); // 5秒后自动隐藏菜单 setTimeout(() => { if (this.active) { Menu.setApplicationMenu(null); writeLog('info', '菜单已自动隐藏'); } }, 5000); } }); writeLog('info', '全局快捷键 Ctrl+Alt+M 已注册,可用于临时显示菜单'); this.interval = setInterval(() => { if (!this.active || operationCount >= maxOperations) { this.stop(); return; } this.performRandomOperation(); operationCount++; }, interval); // 超时自动停止 setTimeout(() => { this.stop(); }, duration); } /** * 停止 Monkey Testing */ stop() { if (!this.active) return; this.active = false; if (this.interval) { clearInterval(this.interval); this.interval = null; } // 恢复菜单 if (this.originalMenu) { Menu.setApplicationMenu(this.originalMenu); this.originalMenu = null; writeLog('info', '菜单已恢复显示'); } // 注销全局快捷键 globalShortcut.unregister('CommandOrControl+Alt+M'); writeLog('info', '全局快捷键已注销'); writeLog('info', '停止monkey testing'); } /** * 检查是否正在运行 */ isActive() { return this.active; } } /** * 输出调试信息 * @param {Object} options - 解析后的命令行选项 */ export function logDebugInfo(options) { writeLog('log', '=== Electron Debug Info ==='); writeLog('log', `Command line args: ${safeStringify(process.argv)}`); writeLog('log', `Parsed options: ${safeStringify(options)}`); writeLog('log', '==========================='); } /** * 显示Monkey Test参数输入对话框 * @param {BrowserWindow} mainWindow - 主窗口实例 */ export function showMonkeyInputDialog(mainWindow) { const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const inputWindow = new BrowserWindow({ width: 400, height: 300, parent: mainWindow, modal: true, show: false, webPreferences: { nodeIntegration: true, // 允许输入窗口使用 require contextIsolation: false }, resizable: false, title: 'Monkey Test Parameters' }); const htmlContent = `