从 BLOCKED 到真实浏览器验证:华为云 ARM64 环境下 Playwright 与 Chromium 兼容性问题排查实践
前言
在使用华为云开发者空间进行 AI 应用开发时,我们经常需要借助自动化工具完成页面截图、中文字体检查、项目测试和发布前验证。
其中,Playwright 是一个非常实用的浏览器自动化工具,可以帮助我们验证网页是否能够正常打开、页面是否正确渲染,以及截图结果是否符合预期。
但在一次实际开发过程中,我遇到了一个有意思的问题:
系统中明明存在可以运行的 Chromium 浏览器,Playwright 却提示浏览器不可用,导致发布验证流程被阻断。
最初,我怀疑是 ARM64 架构缺乏浏览器支持。经过逐步排查,最终发现问题并不在 ARM64 架构本身,而在于 Playwright 版本与本地 Chromium 浏览器构建版本不匹配。
本文将结合这次实践,分享问题定位、解决方案、验证方法,以及如何在自动化发布流程中确保检查结果真实可信。
一、问题背景:为什么发布流程被阻断?
在 AI 应用的自动化发布过程中,通常需要完成以下检查:
-
确认浏览器环境可用。
-
使用真实浏览器加载应用页面。
-
生成页面截图。
-
检查中文字体、Emoji 等字符的显示情况。
-
通过发布前的验证门禁。
这些检查的意义不仅是保证截图文件存在,更重要的是验证页面在真实浏览器中的显示效果。
然而,在 ARM64 开发环境中执行 Playwright 时,却出现了浏览器无法启动的问题。
最初的现象表现为:
-
Playwright 默认启动 Chromium 失败。
-
自动化截图任务无法继续。
-
页面字体检查无法完成。
-
发布流程被标记为
BLOCKED。
为了避免在未验证页面实际渲染效果的情况下继续发布,自动化流程选择了阻止后续操作。
从安全性角度看,这个行为是合理的,但如果环境中实际上已经存在可用浏览器,就有必要进一步排查原因。
二、定位根因:不是 ARM64 不支持,而是版本不匹配
排查时,我首先检查了环境中的 Playwright 版本和 Chromium 浏览器缓存。
结果发现:
| 检查项目 | 实际情况 |
|---|---|
| Node.js Playwright | 1.64.0 |
| Node.js Playwright 期望的 Chromium build | 1248 |
| 已缓存 Chromium build | 1243 |
| Python Playwright | 1.63.0 |
| Python Playwright 对应 Chromium build | 1243 |
由此可以看出,同一个开发环境内,Node.js Playwright 和 Python Playwright 使用的版本并不完全一致。
Node.js Playwright 期望 build 1248,而缓存中已有的是 build 1243。
这就导致一个容易被忽略的问题:
浏览器二进制文件明明存在,但 Playwright 按照当前版本所对应的路径查找时,仍然可能提示浏览器不存在。
进一步检查 Chromium 缓存目录后,发现 ARM64 浏览器二进制实际上能够运行。
于是尝试显式指定浏览器可执行文件。
JavaScript 示例:
const { chromium } = require('playwright');
async function main() {
const browser = await chromium.launch({
headless: true,
executablePath: '/path/to/chromium'
});
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({
path: 'test.png',
fullPage: true
});
await browser.close();
}
main().catch(console.error);
其中,/path/to/chromium 应替换为经过验证的实际浏览器路径。
测试结果表明,显式指定已有的完整 Chromium 二进制后,浏览器能够正常启动并生成截图。
这说明问题的根源不是 ARM64 架构完全无法运行 Chromium,而是浏览器定位及版本匹配机制。
需要注意的是,Playwright 与浏览器的构建版本不一致时,即使能够启动,也不意味着所有自动化能力都一定兼容。因此仍然需要执行实际功能测试。
三、尝试解决:从默认启动到自动发现浏览器
确定根因后,下一步就是考虑如何让自动化流程更加稳定。
最直接的方式是在启动代码中指定 executablePath。
但如果将浏览器路径写死,例如:
/root/.cache/ms-playwright/chromium-1243/chrome-linux-arm64/chrome
后续浏览器升级或缓存目录发生变化时,仍然可能导致启动失败。
因此,更合理的方案是增加浏览器自动发现机制。
基本思路如下:
-
优先尝试 Playwright 默认启动方式。
-
默认启动失败后,检查本地是否存在其他 Chromium 二进制。
-
对找到的候选浏览器逐个执行启动测试。
-
使用真正能够启动的浏览器完成后续任务。
-
如果所有候选都不可用,则停止流程并报告错误。
这里有一个重要细节:
不能只判断文件是否存在,也不能仅凭执行 --version 成功就认定浏览器可用。
因为某个程序即使能够输出版本信息,也未必可以正常运行 Playwright 的浏览器自动化操作。
更可靠的验证方式应该包括:
-
真实启动浏览器。
-
创建浏览器页面。
-
加载测试 HTML。
-
执行 JavaScript。
-
生成有效的 PNG 截图。
-
正常关闭浏览器。
只有通过实际启动测试的浏览器,才能被视为有效候选。
四、容易忽略的问题:环境变量无法自动跨 Shell 传递
在解决浏览器定位问题的过程中,还发现了另一个值得注意的细节。
假设在预检脚本中执行:
export PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/path/to/chromium
在当前 Shell 及其子进程中,这个环境变量可以使用。
但是,如果预检脚本结束后,自动化发布流程通过另一个独立 Shell 启动,那么先前设置的变量并不会自动保留下来。
这属于 Linux 进程环境变量的正常行为。
因此,仅仅在预检脚本中设置 export,并不能保证后续独立运行的发布命令能够读取到相同的浏览器路径。
针对这个问题,我们尝试了状态文件 + 启动包装脚本的解决思路。
具体流程是:
预检脚本首先定位并验证浏览器,然后将浏览器路径保存到受控的状态文件。
后续发布命令不再直接启动,而是先通过包装脚本读取状态文件,验证其有效性,再设置环境变量并执行真正的发布命令。
例如:
# 示意代码,省略路径验证与安全检查
export PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH="$CHROME_BIN"
exec "$@"
这里的 exec "$@" 可以将当前包装进程替换为目标命令,并让目标命令继承已设置的环境变量。
需要特别说明:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH 在本次特定环境中经过了实际兼容性测试,但不应未经验证就假设所有 Playwright 版本及运行环境都支持相同的环境变量行为。
如果可以直接控制 Playwright 的启动代码,使用其明确提供的 executablePath 或 executable_path 参数通常更加直接。
五、截图成功,不代表验证已经完成
这次排障带给我最重要的经验之一,就是需要区分:
生成了一张图片,与真实完成浏览器验证,是两回事。
例如,使用 Pillow 等图像处理工具,也可以绘制出包含文字、背景和图形的 PNG 文件。
但这样的图片无法证明:
-
Chromium 已经成功启动。
-
页面 HTML 和 CSS 已正常渲染。
-
中文字体没有发生替换或缺失。
-
浏览器 JavaScript 已正常执行。
-
实际页面与预期结果一致。
因此,在自动化发布流程中,不能使用一张手工生成的图片代替真实浏览器截图。
同样,也不能为了让流程通过,就手动创建验证成功的标记文件。
更加可靠的做法是:
由真正执行验证的脚本自行生成结果,并保留对应的测试证据。
本次实践中,在完成浏览器兼容性适配后,华为云环境中的官方截图验证脚本报告能够正常执行,并生成真实 PNG 截图。
测试记录包括:
| 验证项目 | 测试记录 |
|---|---|
| Chromium 启动 | 成功 |
| 页面加载 | 成功 |
| 中文文本读取 | 成功 |
| PNG 截图 | 1280 × 720 |
| 字形检测 | glyphs=ok |
| 缺失字体检查 | missing_fonts=none |
| 截图门禁 | 由官方验证脚本生成 |
需要注意,document.fonts.check() 等字体接口可以辅助验证字体可用性,但单独依靠一个布尔返回值,并不足以证明所有字符的实际视觉效果都完全正确。
对于重要页面,仍然建议结合真实截图和必要的视觉检查进行确认。
六、如何验证优化后的自动化流程?
在解决兼容性问题后,还需要确认修复没有破坏原有功能。
我们对 Huawei Gallery Workflow V2.1.3 进行了多轮回归测试。
最终,华为云环境中的测试报告给出了以下结果:
| 测试套件 | 执行次数 | 通过 |
|---|---|---|
| V2.1.1 | 34 | 34 |
| V2.1.2 | 15 | 15 |
| V2.1.3 | 19 | 19 |
| 原始测试 | 55 | 55 |
| 合计 | 123 | 123 |
需要说明的是,原始测试文件中存在对部分历史测试的重新导入,因此 123 表示测试执行次数,不代表 123 个完全不同的测试用例。
除了正常场景,还应该重点覆盖异常场景,例如:
-
第一个 Chromium 候选损坏,但第二个候选可用。
-
所有 Chromium 候选均无法启动。
-
状态文件已过期。
-
状态文件中的路径被篡改。
-
路径指向并非 Chromium 的程序。
-
浏览器可以启动,但页面截图失败。
-
原有验证进程仍在执行,避免重复启动。
-
官方验证失败时,发布流程仍然能够正确阻断。
这些异常测试的价值,有时甚至高于重复执行正常流程。
因为一个稳定的自动化工具,不只是要在理想环境中成功,更应该在异常环境中给出正确、明确的失败结果。
七、实践中的几点经验总结
通过本次 ARM64 环境排障,我总结了几个值得借鉴的经验。
第一,遇到浏览器启动失败,不要立即认定平台不支持。
先检查 Playwright 版本、浏览器缓存目录、系统架构以及实际二进制能否启动。
有时问题只是版本和路径不匹配。
第二,自动发现机制应该验证真实能力。
找到浏览器文件只是第一步,只有完成启动、页面操作和截图测试,才能确认该浏览器适合当前任务。
第三,自动化工作流必须考虑进程边界。
一个 Shell 中设置的环境变量,不会自动传递到另一个独立启动的 Shell。复杂的 AI 自动化任务尤其容易遇到此类问题。
第四,发布验证不能只追求 PASS。
如果通过伪造截图、写入标记文件等方式让验证通过,就失去了自动化质量检查的意义。
第五,异常场景必须成为回归测试的一部分。
自动化工具的可靠性,不只是由成功次数决定,也取决于失败时能否及时、准确地停止错误操作。
八、结语
本次问题最初表现为 ARM64 环境中 Playwright 无法启动 Chromium,导致发布流程被阻断。
经过逐步排查,最终找到了版本与缓存构建不匹配的问题,并通过显式浏览器路径、自动发现机制以及跨 Shell 环境传递完成了相应适配。
这一过程也让我对 AI 自动化开发有了新的认识:
真正可靠的自动化,不应该为了完成任务而绕过验证,而应该通过定位根因,让验证能够真实、正确地执行。
随着 AI Agent 越来越多地参与代码开发、测试、构建和发布,浏览器兼容性、运行环境一致性、验证证据可信度等工程细节,将变得越来越重要。
希望本文的排查思路能够帮助同样在 ARM64、Playwright 或云端开发环境中遇到浏览器自动化问题的开发者。
- 点赞
- 收藏
- 关注作者
评论(0)