import time import random from framework.core.logger import get_logger logger = get_logger("MonkeyTester") def run_monkey_testing(page, action_count=1000): """ 全屏幕 Monkey 稳定性测试 (随机流操作) 利用 JS 提取网页内所有的安全交互元素(避开退出、注销、删除等敏感操作), 然后执行随机规模的乱序点击和键盘输入,最后伴随鼠标抛掷。 """ logger.info(f"🐒 开始执行全局 Monkey 测试,计划乱序攻击交互 {action_count} 次...") # 增加捕捉页面底层级 JS 控制台报错的能力 def log_page_error(err): logger.error(f"💥 [Monkey 探测到前端崩溃]: {err}") # 监听未捕获异常 page.on("pageerror", log_page_error) # 危险词汇,避免退出登录或产生破坏性删除导致平台主干链路被污染 forbidden_keywords = ['退出', '注销', 'logout', '删除', 'delete', '清理'] # JS 提取页面上的活动区域 js_get_random_element = """ (forbidden) => { // 大面积收割所有可能挂载事件的锚点 const interactables = Array.from(document.querySelectorAll("button, a, input, textarea, [role='button'], div.p-dropdown, li.p-menuitem")); const visible = interactables.filter(el => { const rect = el.getBoundingClientRect(); const style = window.getComputedStyle(el); return rect.width > 0 && rect.height > 0 && style.visibility !== 'hidden' && style.opacity !== '0'; }); const safeElements = visible.filter(el => { const text = (el.innerText || el.value || el.placeholder || '').toLowerCase(); return !forbidden.some(kw => text.includes(kw)); }); if (safeElements.length > 0) { const randomIndex = Math.floor(Math.random() * safeElements.length); return safeElements[randomIndex]; } return null; } """ success_actions = 0 for i in range(action_count): try: # 高频发起,给予微小缓冲节奏 time.sleep(0.3) # 使用 evaluate_handle 将 JS 节点句柄传回到 Python element_handle = page.evaluate_handle(js_get_random_element, forbidden_keywords) # null 在 Python 端 json_value 会被转换为 None,但在 Handle 里需谨慎评估 is_valid = page.evaluate("(el) => el !== null && typeof el === 'object' && el.tagName", element_handle) if is_valid: tag_name = page.evaluate("el => el.tagName", element_handle).lower() # 开始随机交互分发 if tag_name in ['input', 'textarea']: # 随机混沌输入 random_txt = str(random.randint(100, 99999)) element_handle.fill(random_txt, force=True, timeout=1000) logger.debug(f"[Monkey] ⌨️ 乱序输入框写入: {random_txt}") else: # 强硬暴力点击 (抛弃边界验证强制触发底层事件) element_handle.click(force=True, timeout=1000) logger.debug(f"[Monkey] 🖱️ 盲击了元素节点: <{tag_name}>") success_actions += 1 else: # 找不到靶点则强制滚屏扰动页面布局重绘 distance = random.choice([-600, -300, 300, 600]) page.mouse.wheel(0, distance) logger.debug(f"[Monkey] 📜 随机视差滚屏了 {distance} px") except Exception as e: # Monkey 理念:容忍动作失败,但如果抛出的是框架级失去连接则需汇报 if "Target page, context or browser has been closed" in str(e): logger.error("🚨 浏览器实例被截断,Monkey 测试提前终止!") break # logger.debug(f"⚠️ Monkey 第 {i+1} 次挥拍落空: {e}") pass # 卸载挂载的全局异常监听,避免影响后续的常规测试 page.remove_listener("pageerror", log_page_error) logger.info(f"✅ Monkey 测试执行完毕!成功施加了 {success_actions}/{action_count} 次有效随机压力。未探测到毁灭性 Crash。") return True