WebMCP 上了 Playwright:页面给 Agent 的工具怎么测

简介: Playwright v1.64 新增实验性 WebMCP 测试能力:`page.webmcp.tools()` 可枚举页面向智能体注册的工具,`callTool()` 支持直调验证。需启用 `--enable-features=WebMCP`,目前仅 Chromium 等主流内核部分支持。填补了传统测试无法覆盖的“机器可读工具面板”盲区,助力智能体能力契约化回归。

image.png

页面用 WebMCP 把能力端给智能体,可这张工具面板此前不在任何一条用例里。

凌晨一点,值班群里弹出一条告警:客服侧的智能体在商品目录页上「找不到搜索入口」,整夜只回人工。前端把截图甩了过来——搜索框在,接口 200,DOM 里的搜索语义节点一个不少。翻到智能体自己那份执行日志才看明白:它读的根本不是像素和标签,而是页面注册给它的工具列表;昨晚那次发布,列表里少了一个 search_catalog,多了一个改了参数名的新条目。页面上没有任何东西坏掉,坏掉的是页面端给智能体的那张工具面板,而它不在我们任何一条用例的覆盖面上。这个盲区现在有了官方出口:据 Playwright 官方 Release Notes(v1.64),浏览器侧第一次给出了枚举并直接调用页面工具的接口,page.webmcp.tools() 与 page.webmcp.callTool(name, params),把「页面把哪些能力交给了智能体」变成像按钮一样可以断言的东西。

两个方法,一个前提:这是实验性开关后的事

先把官方事实钉住,不带修饰。据 Playwright 官方 Release Notes(v1.64)WebMCP 条目:新增 page.webmcp 与 frame.webmcp 两个入口;webmcp.tools() 用于枚举页面通过「实验性 WebMCP 浏览器 API」注册的工具;webmcp.callTool(name, params) 用于直接调用其中某个工具。官方给出的最小示例长这样:

// 官方 Release Notes(v1.64)示例口径:需要特性开关,工具 add 返回 "42"
import {
    chromium } from 'playwright';

const browser = await chromium.launch({
   
  args: ['--enable-features=WebMCP'], // 前提:实验性浏览器 API 必须显式开启
});
const page = await browser.newPage();
await page.goto(CATALOG_URL);

const result = await page.webmcp.callTool('add', {
    a: 2, b: 40 });
// result 的内容是 "42"

三件事必须写在脸上,否则这篇会被读成「智能体测试已经标准化」。第一,这是实验性 API,官方自己的示例就带着 --enable-features=WebMCP 启动参数,参数与命名在后续版本都可能变;第二,页面得自己先把工具注册进那套浏览器 API,没有注册就没有可枚举项,这条用例不会凭空长出能力;第三,这条能力目前只在 Chromium 通道被官方示例明确演示,同一份 Release Notes 的浏览器内核条目给出的是 Chromium 156.0.8078.4、Mozilla Firefox 157.0、WebKit 27.2 三个内核版本,并说明另在 Google Chrome 155 / Microsoft Edge 155 稳定通道做过测试——这些是版本事实,不等于 WebMCP 在所有内核上都已可用。

除测试 API 之外,官方条目还提到 playwright-cli 侧有 webmcp-list 与 webmcp-call 两个子命令,示例形态是 playwright-cli webmcp-call search_catalog --params '{"query":"cats"}'。对还没搭测试工程的同学,这是成本最低的探路方式:先在命令行把某个页面的工具清单打出来,再决定要不要为它写回归。

image.png

为什么以前的用例一条都摸不到这张面板

答案摆在这:这张面板既不是可见元素,也不是后端接口,它是第三种接口面,而我们的用例资产只覆盖了前两种。

可断言的接口面 谁在消费它 现有用例通常怎么覆盖 漏掉的部分
DOM 与可见元素 人眼、屏幕阅读器 定位器断言、可见性与文案断言 看不见「注册为工具但不在界面上」的能力
后端接口 前端、其它服务 状态码、字段、契约测试 不知道页面把哪几个接口包装成了工具
工具面板(WebMCP) 智能体 / Agent 客户端 v1.64 之前没有官方测试入口 名称增删、参数改名、schema 收紧全都无人值守

传统自动化对页面的假设是「用户看见什么,就测什么」。工具面板打破了这个假设:它是给机器读的,页面上可能一个像素都不体现。前端同学改了一个参数名,视觉回归不会红,接口测试不会红,端到端流程如果没人再点一遍那条搜索路径也不会红——但消费这张面板的智能体当场就找不到入口。这类缺陷的可怕之处在于它的反馈方是外部系统:页面自己的 CI 全绿,问题在别人的日志里爆炸。

这也解释了为什么这件事值得测试团队提前占位。据 Playwright 官方 Release Notes(v1.64),官方把枚举与调用做成了页面级与帧级两个入口(page.webmcp / frame.webmcp),意味着工具面板从「浏览器新特性」变成了「可回归对象」;对测试团队来说,新接口面出现的第一时间把它纳入契约基线,成本最低,因为此时页面注册的工具数量还很少,清单还短。

商品目录页的契约:枚举、schema、直调三段

场景按在行业务写:一个商品目录页注册了 search_catalog 工具,供站外智能体直接按关键词查商品;这次迭代前端把参数 query 改成了 keyword,并顺手上了一个还在开发中的 recommend_similar。业务后果不是页面坏了,而是智能体侧的搜索静默失效、未上线工具被外部提前消费。

契约测试就三段,顺序不能反。

// catalog-tools.contract.spec.ts —— 页面工具面板的契约回归
import {
    test, expect } from '@playwright/test';

const CONTRACT = {
   
  search_catalog: {
    required: ['query'], optional: ['page', 'sort'] },
  get_product_detail: {
    required: ['sku'], optional: [] },
}; // 工具契约基线:与代码同仓,改动必须走评审

test.use({
   
  launchOptions: {
    args: ['--enable-features=WebMCP'] }, // 前提显式进配置
});

test('第一段:清单不多不少,没被偷偷增删', async ({
    page }) => {
   
  await page.goto('/catalog');
  const names = (await page.webmcp.tools()).map((t) => t.name).sort();
  expect(names).toEqual(Object.keys(CONTRACT).sort());
});

test('第二段:参数 schema 不许偷偷改', async ({
    page }) => {
   
  await page.goto('/catalog');
  const tools = await page.webmcp.tools();
  for (const [name, want] of Object.entries(CONTRACT)) {
   
    const tool = tools.find((t) => t.name === name);
    expect(tool, `工具 ${
     name} 不见了`).toBeDefined();
    const schema = tool!.inputSchema as {
   
      required?: string[];
      properties?: Record<string, unknown>;
    };
    expect(schema.required ?? []).toEqual(expect.arrayContaining(want.required));
    const props = Object.keys(schema.properties ?? {
   });
    for (const p of [...want.required, ...want.optional]) {
   
      expect(props, `参数 ${
     name}.${
     p} 被改名或删除`).toContain(p);
    }
  }
});

test('第三段:直调返回值可校验', async ({
    page }) => {
   
  await page.goto('/catalog');
  const res = await page.webmcp.callTool('search_catalog', {
    query: '机械键盘' });
  const text = JSON.stringify(res);
  expect(text).toContain('items');            // 关键字段必须存在
  expect(text).not.toContain('InternalError'); // 工具内部报错不能当成功返回
});

为什么这么写,三个坑都在里面。第一段用集合等值而不是 toContain:等值断言同时管「少工具」和「多工具」两种方向,query→keyword 那次改名会在这里以「search_catalog 消失」现形,而 toContain 只拦得住删除,拦不住把一个还在开发中的工具顺手暴露给外部智能体。第二段用基线常量而不是硬编码字符串,是为了让「谁能改契约」这件事在 PR diff 里可见——改这段 JSON 的人必须写清楚为什么,因为这等于改对外契约。第三段刻意只断结构存在性、不断具体商品数量:工具的真实返回受数据和排序影响,把它写成死数字,两周后这条用例只会贡献一条假红。

还要补一句诚实的:callTool 是绕过智能体直接打到工具上的。它证明「页面确实提供了这个能力、且能被调通」,不证明「智能体会选它、会传对参数」。这条边界放到后面细说。

image.png

落进回归与 CI:把工具清单当快照管

枚举结果天然适合按快照基线跑。推荐落法三层,全部是本文的推荐做法。

基线层:把 tools() 的名称与参数 schema 导出成一份 JSON 契约文件,与代码同仓(示例形态:{ "search_catalog": { "required": ["query"] } })。这份文件是页面与智能体之间的对外契约,改它的 PR 必须附消费方确认,跟改接口字段一个级别。

门禁层:PR 流水线跑契约文件与实测清单的一致性比对——清单少了条目或参数改了名,直接红;多了条目,先黄并阻塞合并,要求提交人说明这是新契约还是没关掉的实验特性。这里有个可以直接照搬的分法:把「允许写基线」和「只读校验」拆成两条 job,前者人工触发、产物提 MR,后者挂在 PR 路径上、缺失即红——一条命令同时兼任两种意图,是清单类基线最常见的失效方式。

矩阵层:WebMCP 依赖浏览器内核与特性开关,跨内核结论要分开报。同一份契约用例,Chromium 通道带开关跑、Firefox 与 WebKit 通道单独记录支持状态,报告里把「工具契约不匹配」和「内核不支持该实验特性」分成两类结论——把它们混成一条红,是最快让整条用例被静音的做法。官方 CLI 的 webmcp-list / webmcp-call 可以顺手做成夜间巡检脚本,专门扫那些还没写契约用例的新页面,把「有工具注册但无人测试」的页面清单交出来。

事故回灌这条老规矩同样适用:值班那晚的故障,落地方式就是往基线里补一条 search_catalog.required 包含 query,从此它由 CI 守着,不再靠人的记性。报告口径也要提前定好:工具契约失败必须单独立一类,写清「页面少了哪个工具、哪个参数改了名」,不要并进「UI 自动化失败」那个大桶——前者要找前端改声明,后者往往只在等一次重跑,混在一起,这类缺陷会被统计平均掉。

边界:这套测法现在能带走多远

四句,别越界。第一,这是实验性 API:入口命名、启动参数、注册方式都可能随版本变化,把它当成已经普及的生产能力写进年度规划,是这篇最想拦住的误读。第二,工具注册不等于智能体真会用。callTool 是测试直调,绕过了模型的意图理解与工具选择;要覆盖「智能体到底会不会挑这个工具、参数传得对不对」,仍需端到端与模型层评测,本篇的契约测试只保证「能力面稳定」。第三,清单与 schema 全过,不等于返回内容正确——它管的是接口形状,不是搜索结果相关性;把它当质量结论报出去,就重演了「接口 200 所以一切正常」的老错。第四,文中出现的工具名、参数名、契约文件形态、告警分级均为本文构造的示例方案,官方条目里能直接引用的只有 API 名称、启动参数、add 示例返回 "42"、CLI 子命令与内核版本号;这些不是任何团队的效果数据,更不是行业基准。

下一步

本周只做一件事:挑一个你们确定会被智能体消费的页面,用带 --enable-features=WebMCP 的 Chromium 通道把 page.webmcp.tools() 打出来。清单是空的,就把结论记下来——这个页面还没有对外能力面;清单不是空的,就把这份 JSON 提交进仓库,给它加一条等值断言。新接口面出现的第一周就把它纳入回归,是测试团队成本最低的一次抢跑。

看不见消费方的接口面,才是最容易裸奔的接口面。

本文部分内容参考了霍格沃兹测试开发学社整理的相关技术资料,主要涉及软件测试、自动化测试、测试开发及 AI 测试等内容,侧重测试实践、工具应用与工程经验整理。

相关文章
|
5天前
|
云安全 人工智能 运维
当攻击全面Agent化,你的安全防御能否跟上AI Speed?
多起客户侧AK泄露事件应急的真实观察
1241 4
|
28天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
9785 32
|
8天前
|
存储 人工智能 安全
千问办公官网入口网页版登录:qwenwork.cn 注册送2000积分、登录送100积分
阿里云千问办公(QwenWork)是AI智能工作平台,支持一句话生成PPT、表格、网页、视频及数据分析。个人免费版送2000积分+每日登录赠100分,含1GB存储、5个发布页;企业版198元/席/月起。阿里千问办公QwenWork官网:https://t.aliyun.com/U/0VCTGt 阿里AI工作平台,一句话完成数据分析、PPT 生成、视频剪辑、网页搭建等复杂任务
|
3天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
|
14天前
|
存储 人工智能 并行计算
大模型本地部署终端选型方法论:以 Qwen3.8-27B 为例的四档分层完整流程
本文提出一套大模型本地部署终端选型方法论:定约束、定档位、定框架、定参数四步决策法,配合入门、主力、质量、无损四档分层模型。以 Qwen3.8-27B 实测数据为例,逐环节解读显存、带宽、存储、散热、系统、预算等要素,给出面向不同预算的优选方案、决策自查清单与市场观察框架。文末前瞻 AI 笔记本的 CPU+GPU 与统一内存两条路线,论证四步决策法在新品类上的延续性。
|
5天前
|
Web App开发 人工智能 JavaScript
太猛了,一个月干到15W+,给大家推荐一个最近爆火的开源逆向工具:REA
REA(Reverse Engineer Anything)是近期爆火的开源AI逆向工具,4月发布,1个月内斩获15万+ Star。它让AI Agent无需源码即可分析二进制、APK、JS/Electron、HAR包等17类目标,自动反编译、生成可运行代码,并强制返回带证据与局限的结论。全本地执行,MIT协议,支持Hopper/Ghidra/IDA等引擎,一行命令即可上手。
625 1
太猛了,一个月干到15W+,给大家推荐一个最近爆火的开源逆向工具:REA
|
13天前
|
人工智能 JSON 自然语言处理
2026 年 Jev 决策模型深度拆解:原理解读、实战测评与保姆级落地教程
有一款特殊AI模型在开发者圈子刷屏,它摒弃传统大模型擅长的对话聊天能力,专注做高速结构化决策,它就是TypeSafe AI推出的Jev模型。该模型由ChatGPT共同发明人Diogo Almeida主导研发,定位为**System One Model(系统一模型)**,对标人类大脑快速直觉判断的思维模式,在响应延迟、调用成本、结构化输出稳定性上相比传统生成式大模型有着巨大差异。本文会完整拆解Jev底层原理、三大核心原语能力、适用业务场景,同时提供可直接运行的curl、Python代码示例,并且结合多组实测数据,客观分析模型优势与能力边界,帮助普通开发者和AI应用从业者快速上手落地。
928 1
|
9天前
|
人工智能 JSON 自然语言处理
2026 年 Jev 决策模型全解析:核心原理拆解,性能实战测评与落地部署教程
有一款特殊AI模型在开发者圈子刷屏,它摒弃传统大模型擅长的对话聊天能力,专注做高速结构化决策,它就是TypeSafe AI推出的Jev模型。该模型由ChatGPT共同发明人Diogo Almeida主导研发,定位为System One Model(系统一模型),对标人类大脑快速直觉判断的思维模式,在响应延迟、调用成本、结构化输出稳定性上相比传统生成式大模型有着巨大差异。本文会完整拆解Jev底层原理、三大核心原语能力、适用业务场景,同时提供可直接运行的curl、Python代码示例,并且结合多组实测数据,客观分析模型优势与能力边界,帮助普通开发者和AI应用从业者快速上手落地。
592 0

热门文章

最新文章