playwright+ai -> 现代化UI自动化框架

Ryder 2025-9-29 25 9/29

一、MCP的相关知识

1、模型上下文协议

上下文共享:应用程序通过MCP向模型提供所学的上下文信息(如文件内容、数据库记录),增强模型的理解能力。

工具暴露:MCP允许应用程序将功能(如文件读写、API调用)暴露给模型,模型可以调用这些工具完成复杂任务。

工作流:可以利用MCP集成多个服务和组件,可扩展的AI工作流。

安全性:通过本地服务器运行,MCP避免将敏感数据上传至第三方平台,确保数据隐私。

2、MCP架构

客户端:是AI应用程序,负责发起请求并与服务器通信。

服务器:轻量级程序,负责暴露特定的数据源或工具功能,并通过标准化协议与客户端交互。

通信格式:基于JSON-RPC 2.0,支持请求、响应和通知三种消息类型,确保通信的标准化和一致性。、

3.pw+mcp的价值

playwright + mcp 的价值不可靠:

1.不是完全的自动化,需要不停的确认

2.我的描述,需要复制粘贴给大模型(一次,错误)

3.可靠性:有疑问,取决于大模型的能力。

二、playwright

auto-wing 借鉴minsence.js的思路 -> playwright + ai

playwright+ai - srcset= 现代化UI自动化框架" title="playwright+ai -> 现代化UI自动化框架" alt="" width="863" height="391" />

安装 Pytest 插件

pip install pytest-playwright

安装所需的浏览器:

playwright install

第一次测试:test_example.py

import re
from playwright.sync_api import Page, expect

def test_has_title(page: Page):
    page.goto("https://playwright.dev/")
    # Expect a title "to contain" a substring.
    expect(page).to_have_title(re.compile("Playwright"))
def test_get_started_link(page: Page):
    page.goto("https://playwright.dev/")
    # Click the get started link.
    page.get_by_role("link", name="Get started").click()
    # Expects page to have a heading with the name of Installation.
    expect(page.get_by_role("heading", name="Installation")).to_be_visible()

语法结构:

1. 同步与异步模式

# 同步
from playwright.sync_api import sync_playwright

def run_sync():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        page = browser.new_page()
        page.goto('https://example.com')
        browser.close()
run_sync()
# 异步
import asyncio
from playwright.async_api import async_playwright

async def run_async():
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=False)
        page = await browser.new_page()
        await page.goto('https://example.com')
        await browser.close()
asyncio.run(run_async())
# 导航
# 基本导航
page.goto('https://example.com')

# 带选项的导航
page.goto('https://example.com', 
    timeout=30000,           # 超时时间
    wait_until='networkidle', # 等待条件:'load'|'domcontentloaded'|'networkidle'
    referer='https://google.com' # 设置referer
)

# 导航事件处理
page.on('load', lambda: print('Page loaded!'))
# 前进和后退
page.go_back()
page.go_forward()
# 重新加载
page.reload()
# 断言
expect(page.get_by_role("heading",name="Installation")).to_be_visible()
expect(page).to_have_title(re.compile("Playwright"))
# 截图
page.screenshot(path="example.png")

惰性定位:

playwright使用Locator定位元素,但它在创建时并不立即执行查找。只有当该元素需要执行一个动作或断言时,才会根据Locator内容去页面上寻找匹配的元素,即指描述“如何找到元素”。

自动等待:

当Locator去页面上寻找元素时,意味着要对该元素进行实际的使用,那么playwright不会仅仅是找到该元素即止,而是对元素自动等待以下状态就绪,确保寻找到的元素可以进行使用:

三、目的

1.自动化:提高测试执行效率

2.AI自动化:原有的自动化之上,再次提高效率

四、playwright定位选择器的优先级

# 1.首选 - 测试ID (最稳定)
# 测试ID 是专门为自动化测试添加的标识属性,用于稳定地定位元素,不受UI样式或布局变化的影响。
page.get_by_test_id("login-button")
page.locator("[data-testid='submit']")

# 2.其次 - 角色选择器 更容易理解,跨平台稳定
page.get_by_role("button", name="Submit")
 # 示例
# 1.普通按钮
<button>Submit</button> 
# 2.input 类型按钮
<input type="button" value="Submit">
<input type="submit" value="Submit">
# 3.div 模拟按钮
<div role="button" aria-label="Submit">点击提交</div>
# 4. 带aria-label 的按钮
<button aria-label="Submit">提交表单</button>
# 5.通过aria-labelledby关联标签
<button aria-labelledby="submit-label"></button>
<span id="submit-label">Submit</span>

page.get_by_role("textbox", name="Username")
page.get_by_role("radio", name="男")# 单选按钮定位
page.get_by_role("checkbox", name="我同意服务条款")# 复选框
page.get_by_role("combobox", name="国家") # 下拉框
page.get_by_role("dialog", name="注册成功")# 对话框
page.get_by_role("navigation", name="主导航")
page.get_by_role("heading", name="页面标题")
page.get_by_role("list", name="任务列表")
page.get_by_role("progressbar", name="下载进度")
page.get_by_role("alert", name="错误提示")

#3.再次 -文本选择器 依赖文案内容,文案修改即失效
page.locator("text=登录")
page.get_by_text(""Welcome)

#4.CSS选择器 灵活但容易随结构变化失效
page.locator("#username")
page.locator(".submit-btn")

#5. XPath(复杂场景使用)太脆弱异变
page.locator("//button[contains(@class, 'primary) and text()='Save']")

# 避免的选择器
page.locator("div > div > div > button") # 过于依赖结构
page.locator("//div[5]/span[2]") # 依赖位置索引


 

 

 

- THE END -

Ryder

10月28日17:10

最后修改:2025年10月28日
0

非特殊说明,本博所有文章均为博主原创。

共有 0 条评论