必须继承PantherTestCase而非TestCase或WebTestCase,因其提供WebDriver支持、自动管理浏览器生命周期,并确保JS执行与真实渲染;其他做法会导致客户端失效或断言不准。

Panther 测试写得像 BrowserKit 就会失败——它不跑 JS、不等渲染、不维持会话,根本不是一回事。
用 PantherTestCase 而不是 TestCase 或 WebTestCase
Panther 不是内核模拟器,它启动真实浏览器进程,必须走专用基类。直接继承 PHPUnit\Framework\TestCase 或 WebTestCase 会导致 createPantherClient() 方法不可用、$client 没有 WebDriver 支持、JS 执行静默失效。
- 必须继承
PantherTestCase(来自symfony/panther),它自动注入 Chrome/Firefox 客户端并管理生命周期 - 测试方法里不能调用
static::createClient()—— 那是 BrowserKit 的,和 Panther 无关 - 若需复用 Symfony 服务(如 Doctrine EntityManager),仍可通过
static::$container访问,但注意:Panther 客户端发的请求不经过 Symfony 内核路由层,而是直连 Web 服务器(如 localhost:8000)
waitForElementVisible 为什么总超时?
waitForElementVisible 只检查 DOM 存在 + CSS visible 属性 + 尺寸非零,但它对 Vue/React 的异步挂载、CSS 动画延迟显示、条件渲染区块完全无感知。
- 别用
id="submit-btn"这类易变 selector;改用稳定属性,如[data-testid="login-submit"]或[aria-label="Sign in"] - 目标元素由 JS 插入?优先用
$client->waitForText('Welcome back')或$client->executeScript("return document.querySelector('main') !== null") - 点击后跳转新页,别立刻
waitForElementVisible;先$client->wait(1000)或$client->waitForNavigation()(Panther 1.x+ 支持) - Vue Router 懒加载页面可能触发两次
pushState,建议加断言:$this->assertStringContainsString('/dashboard', $client->getCurrentURL())
登录态丢失:Panther 不共享你的 dev session
你在浏览器里已登录 /admin,但 Panther 启动的是干净 Chrome 实例,没带任何 cookie,访问 /admin/dashboard 必然被重定向到登录页。
- 不要硬编码
PHPSESSID;用ini_get('session.name')动态获取键名 - 正确做法是走完整登录流程:
$client->submitForm('Login', ['email' => 'a@b.c', 'password' => 'xxx']),再断言跳转或文案 - 若需跨多个测试复用登录态(比如避免重复提交表单),可在
setUp()中执行登录,并确保$client是实例变量($this->client),而非局部变量 - CI 环境中,Chrome 启动参数必须含
--no-sandbox和--headless=new,否则 session cookie 可能被拒绝存储
截图空白、按钮点不到:viewport 尺寸没设
Headless Chrome 默认 viewport 是 800×600,很多响应式前端会据此隐藏侧边栏、折叠导航、甚至跳过 JS 初始化逻辑,导致关键元素不渲染或位置偏移。
- 初始化客户端时显式设置尺寸:
Client::createChromeClient(['window-size' => '1440,900']) - Docker 环境下还必须挂载
/dev/shm(否则共享内存不足,页面卡死或截图全白):docker run --shm-size=2gb ... - 截图前可主动执行缩放:
$client->executeScript('document.body.style.zoom = "1";'),避免高 DPI 设备下像素错位 - 点击失败时,先用
$client->takeScreenshot('debug.png')看实际渲染结果,再比对 selector 是否真在视口内
最常被忽略的一点:Panther 测试不是“增强版功能测试”,它是独立进程 + 真实网络 + JS 引擎的组合体。任何依赖内核行为(如事件监听器、容器服务钩子、profiler 数据)的断言,在 Panther 里都得换思路——要么通过 HTTP 响应验证,要么用 executeScript 读取前端状态。


















