4、页面导航与菜单解析:菜单树结构分析、动态菜单加载处理、导航到规则管理页面

在IDP自助门户的自动化验证方案中,页面导航与菜单解析是脚本与UI交互的第一步。自动化测试脚本需要准确理解门户的菜单树结构,处理动态加载的菜单项,并最终可靠地导航到“准入控制规则管理”页面。本章将深入分析菜单树的DOM结构、动态加载机制以及自动化定位策略。

4.1 菜单树结构分析

IDP自助门户的左侧导航菜单采用多级树形结构,通常由 <ul> / <li> 嵌套列表实现,每个菜单项包含图标、文本标签和展开/折叠箭头。菜单树的核心层级关系如下表所示:

层级 DOM 元素特征 CSS 选择器示例 说明
一级菜单 <li class="nav-item level-1"> .nav-item.level-1 顶级导航入口,如“安全策略”、“审计日志”
二级菜单 <li class="nav-item level-2"> .nav-item.level-2 一级菜单下的子分类,如“准入控制”、“流量过滤”
三级菜单 <li class="nav-item level-3"> .nav-item.level-3 具体功能页面入口,如“规则管理”、“黑白名单”
展开/折叠触发器 <span class="toggle-icon"> .toggle-icon 点击后展开或收起子菜单列表
菜单文本标签 <span class="menu-label"> .menu-label 菜单项显示的文字内容
自动化定位建议: 优先使用菜单文本标签(.menu-label)结合层级关系进行定位,避免依赖可能变化的图标类名或索引位置。例如,定位“规则管理”可使用 //span[@class='menu-label' and text()='规则管理']。
IDP自助门户菜单树结构 安全策略 准入控制 规则管理 系统管理 用户管理 角色配置 审计日志 操作日志 图例说明: 一级菜单(顶级导航) 二级菜单(子分类) 三级菜单(功能页面) 父子关系

4.2 动态菜单加载处理

现代IDP门户的菜单通常采用异步加载(AJAX)方式,页面初始化时只渲染一级菜单,子菜单在用户点击展开后才从后端获取并动态插入DOM。这种机制给自动化测试带来两个核心挑战:

  • 元素可见性延迟: 子菜单的DOM节点在点击展开前不存在,脚本需要等待异步请求完成。
  • 加载状态判断: 展开动画或加载指示器(如旋转图标)可能干扰点击操作。
自动化处理策略:
  1. 显式等待(Explicit Wait): 使用 WebDriverWait 配合 expected_conditions.presence_of_element_located 或 visibility_of_element_located,等待目标菜单项出现在DOM中。
  2. 展开父级菜单: 在定位子菜单前,先确保其所有父级菜单已处于展开状态。可通过点击父级菜单的 .toggle-icon 触发展开。
  3. 等待加载完成: 观察加载指示器(如 class="loading-spinner")的消失,或等待菜单容器内出现特定子节点。

以下是一个典型的动态菜单加载流程代码示例:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def expand_menu_and_navigate(driver, menu_path):
    """
    展开菜单路径并导航到目标页面
    :param driver: WebDriver 实例
    :param menu_path: 菜单文本列表,如 ["安全策略", "准入控制", "规则管理"]
    """
    for index, menu_text in enumerate(menu_path):
        # 构造当前层级的菜单项定位器
        if index == 0:
            # 一级菜单直接可见
            menu_item = WebDriverWait(driver, 10).until(
                EC.presence_of_element_located((By.XPATH, f"//span[@class='menu-label' and text()='{menu_text}']"))
            )
        else:
            # 子菜单需要等待父级展开后出现
            menu_item = WebDriverWait(driver, 10).until(
                EC.visibility_of_element_located((By.XPATH, f"//span[@class='menu-label' and text()='{menu_text}']"))
            )

        # 如果是最后一个菜单项,直接点击导航
        if index == len(menu_path) - 1:
            menu_item.click()
            print(f"已导航到: {menu_text}")
        else:
            # 非最后一项,点击展开子菜单
            # 查找父级 li 元素中的展开图标
            parent_li = menu_item.find_element(By.XPATH, "./ancestor::li[contains(@class, 'nav-item')]")
            toggle_icon = parent_li.find_element(By.CLASS_NAME, "toggle-icon")
            toggle_icon.click()
            print(f"已展开菜单: {menu_text}")
            # 等待子菜单加载完成
            WebDriverWait(driver, 5).until(
                EC.presence_of_element_located((By.XPATH, f"//li[contains(@class, 'level-{index+2}')]"))
            )

4.3 导航到规则管理页面

“规则管理”页面是准入控制规则自动化验证的核心操作界面。导航到该页面的标准路径为:安全策略 → 准入控制 → 规则管理。自动化脚本需要确保每一步都正确执行,并验证页面加载完成。

导航成功后的页面验证要点:

验证项 预期结果 自动化检查方式
页面标题 包含“规则管理”或“Rule Management” driver.title 或页面内 <h1> 标签文本
URL路径 包含 /policy/access-control/rules 等特征路径 driver.current_url 正则匹配
页面关键元素 规则列表表格、新增规则按钮、搜索框可见 EC.visibility_of_element_located 检查
面包屑导航 显示“安全策略 > 准入控制 > 规则管理” 定位面包屑容器,验证文本顺序
常见陷阱: 部分IDP门户在导航到规则管理页面时,会弹出“加载中”遮罩层或短暂的重定向。脚本在点击菜单后,应等待页面完全加载(如等待 document.readyState === 'complete' 或特定元素出现),再执行后续操作,避免因页面未就绪导致元素定位失败。
导航到规则管理页面流程状态 初始页面 展开安全策略 展开准入控制 点击规则管理 页面加载验证 规则管理页面 流程说明: 每个状态转换后需等待对应菜单项加载完成;页面加载验证通过后,脚本方可执行规则增删改查操作。

4.4 菜单解析最佳实践总结

综合以上分析,在自动化验证方案中处理页面导航与菜单解析时,应遵循以下原则:

  • 结构化定位: 基于菜单文本和层级关系构建XPath,避免使用路径或索引。
  • 显式等待优先: 对每个动态加载的菜单项使用 WebDriverWait,设置合理的超时时间(通常5-10秒)。
  • 逐层展开: 从一级菜单开始,逐级展开并等待子菜单加载,最后点击目标菜单项。
  • 页面验证: 导航后立即验证页面标题、URL或关键元素,确保导航成功。
  • 异常处理: 捕获 TimeoutException 和 ElementClickInterceptedException,并加入重试机制。
扩展思考: 如果IDP门户使用了前端框架(如React、Vue)的虚拟DOM,菜单的DOM结构可能在每次展开时重新渲染。此时,建议在每次点击操作后重新获取元素引用,避免使用过时的 WebElement 对象。