laravel dusk本质是封装facebook webdriver的php客户端,后台启动真实浏览器进行端到端测试,需显式处理加载延迟、元素可见性及环境匹配;常见失败源于chromedriver与chrome主版本不匹配、visit后未等待页面就绪、ci中未启用headless模式或测试间状态残留。

别指望 Dusk 像单元测试一样“秒断言”——它操作的是真实浏览器,所有失败几乎都卡在等待时机、环境错配或元素不可见上。
ChromeDriver 与 Chrome 版本不匹配导致 SessionNotCreatedException
这是本地跑 dusk 时最常遇到的报错,典型错误信息:Facebook\WebDriver\Exception\SessionNotCreatedException。根本原因不是 Dusk 写错了,而是底层 ChromeDriver 启动 Chrome 失败。
- 运行
chrome --version查看 Chrome 实际版本(如124.0.6367.78) - 运行
chromedriver --version,确认输出的主版本号(如124.0.6367.78)完全一致;小版本号不同通常可接受,主版本必须对齐 - 若不一致:删掉旧驱动,用
php artisan dusk:install重装,或手动下载对应版本的chromedriver替换vendor/laravel/dusk/bin/chromedriver-mac(mac)、-linux或-win.exe - Mac 上通过 Homebrew 安装的 Chrome,其二进制路径可能不是默认位置,需在
DuskTestCase::driver()中显式指定:$options->addBinary('/opt/homebrew/bin/chrome')
visit() 后直接 assertSee() 总失败
visit() 只发导航请求,不等页面加载完、不等 JS 渲染、不等 Vue/React 挂载,此时 DOM 可能还是空的或未就绪。
- 改用
$browser->visit('/login')->waitForText('登录')或->waitFor('.submit-btn', 10),显式等待文本或选择器出现 -
assertSee()检查的是 DOM 文本节点,对display: none、visibility: hidden或尚未挂载的组件无效;优先用assertVisible('@submit-button')配合元素属性定位 - Vue/React 页面建议加一层
->pause(500)或->script('return window.appReady || false')等待应用就绪信号
CI 环境(GitHub Actions / GitLab CI)中 Dusk 启动白屏或超时
CI 默认无图形界面,Dusk 尝试启动 GUI Chrome 必然失败,且默认不启用 headless 模式。
- 必须在
tests/DuskTestCase.php的driver()方法中强制配置 headless 参数,例如:--headless=new(Chrome 116+ 推荐)、--no-sandbox、--disable-gpu - GitHub Actions 示例中需显式安装 Chrome:
uses: actions/setup-node@v3后加uses: browser-actions/setup-chrome@latest - 不要依赖
static::startChromeDriver()—— CI 中应关闭它,在prepare()里注释掉该行,并确保系统已全局安装并可执行chromedriver - 设置超时时间避免卡死:
DesiredCapabilities::chrome()->setCapability('pageLoadStrategy', 'eager')
多个测试间状态残留导致断言误判
Dusk 默认复用同一个浏览器会话(session),前一个测试留下的 cookies、localStorage、路由状态会影响后一个测试。
- 在
tearDown()中主动清理:$this->browse(function ($browser) { $browser->driver->manage()->deleteAllCookies(); }); - 更彻底的做法是每次测试后
quit()浏览器,但会显著拖慢速度;可在DuskTestCase::driver()返回前加atExit(function () { /* quit logic */ }) - 避免在测试中用
loginAs()后不登出,尤其涉及权限跳转时,残留 session 可能绕过预期的 403 断言 - 动态生成的 ID 或时间戳类元素(如
id="user-123")不要硬写在 selector 里,改用含语义的 attribute(如[data-testid="user-card"])
真实浏览器测试的复杂点不在语法,而在时机判断和环境隔离——Dusk 不会替你决定“什么时候元素算真正可用”,这点必须由你用 waitFor、whenAvailable 或 JS 脚本亲手控制。稍不注意,就会把环境问题误判成逻辑缺陷。











