Laravel框架中Dusk浏览器测试具体步骤详解是怎样的?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1052个文字,预计阅读时间需要5分钟。
Dusk 无法直接在 CI 环境或无图形界面的服务器上运行 Chrome,必须显式配置 headless 模式或使用 Docker 容器化。
怎么启动 Dusk 测试环境并避免 Chrome 启动失败
默认 dusk 命令会尝试打开 GUI 版 Chrome,这在大多数部署环境(如 GitHub Actions、GitLab CI、Ubuntu server)下必然失败。必须强制启用无头模式,并确认 ChromeDriver 版本与系统 Chrome 兼容。
- 运行前确保已安装匹配的
chromedriver(推荐用laravel/dusk自带的二进制:执行php artisan dusk:install) - 在
tests/DuskTestCase.php的driver()方法中,把ChromeOptions显式设为 headless:$options = (new ChromeOptions)->addArguments([ '--headless', '--no-sandbox', '--disable-dev-shm-usage', '--disable-gpu', '--window-size=1920,1080' ])
- 若仍报
session not created,检查 Chrome 是否真的存在:在 CI 中运行google-chrome --version或chromium-browser --version,并调整ChromeOptions->setBinary()指向正确路径(如/usr/bin/chromium-browser)
如何写一个能真正点击并等待页面响应的测试用例
Dusk 的 click() 不会自动等待后续加载完成,容易因 DOM 未更新导致断言失败。必须配合显式等待(waitUntil() 或 assertSee() 等阻塞方法)。
- 不要这样写:
$browser->click('@login-button')->assertSee('Dashboard')(可能在跳转前就执行断言)
- 应该这样写:
$browser->click('@login-button') ->waitForLocation('/dashboard') ->assertSee('Welcome back');
- 对异步内容(如 Vue 渲染的列表),优先用
waitForText()或waitFor('.item-list li', 5),而不是依赖assertSee() - 若元素有动画或延迟渲染,加
pause(500)是临时解法,但应优先用waitFor系列代替
为什么 see() / assertSee() 总是失败,即使页面明明有文字
根本原因:Dusk 默认在页面 DOMContentLoaded 触发后即开始查找,但现代前端框架(如 Inertia、Livewire、Vue)的内容往往由 JS 异步注入,DOM 就绪 ≠ 内容就绪。
-
assertSee('Hello')查找的是 纯文本内容,不区分是否在<span>或v-if块里;如果该文本被 JS 动态插入,且没等 JS 执行完,就会找不到 - 更可靠的方式是结合选择器和可见性:
$browser->assertSeeIn('@welcome-message', 'Hello') // 要求元素存在且含该文本
- 或者用
waitForText('Hello')—— 它内部轮询document.body.innerText,比assertSee()更健壮 - 注意:所有
assert*方法都要求元素「已渲染且可见」,隐藏元素(display: none或visibility: hidden)不会被匹配
如何让 Dusk 测试不干扰本地开发数据库
Dusk 使用自己的 .env.dusk.<code> 环境文件,但很多人忽略它仍会读取 <code>DB_DATABASE,导致测试清空开发库。
- 务必在
.env.dusk.local中覆盖数据库配置:DB_CONNECTION=sqlite DB_DATABASE=:memory:(内存 SQLite 最安全)
- 如果非要用 MySQL,至少隔离库名:
DB_DATABASE=testing_app,并确保该库存在且可写
- 运行时必须指定环境:
php artisan dusk --env=dusk.local,否则会 fallback 到默认.env - 别在
DuskTestCase.php中手动调用Artisan::call('migrate:fresh')—— Dusk 已在每个测试前自动重置迁移(前提是usesDatabase()trait 已启用)
最常被跳过的一步是验证 chromedriver 和 Chrome 主版本号是否一致(比如 Chrome 124 需要 chromedriver 124.x),差一个小版本都可能静默失败;另外,waitForLocation() 对 SPA 路由(如 Vue Router history 模式)无效,得改用 waitForUrl() 或监听 window.location.pathname 变化。
本文共计1052个文字,预计阅读时间需要5分钟。
Dusk 无法直接在 CI 环境或无图形界面的服务器上运行 Chrome,必须显式配置 headless 模式或使用 Docker 容器化。
怎么启动 Dusk 测试环境并避免 Chrome 启动失败
默认 dusk 命令会尝试打开 GUI 版 Chrome,这在大多数部署环境(如 GitHub Actions、GitLab CI、Ubuntu server)下必然失败。必须强制启用无头模式,并确认 ChromeDriver 版本与系统 Chrome 兼容。
- 运行前确保已安装匹配的
chromedriver(推荐用laravel/dusk自带的二进制:执行php artisan dusk:install) - 在
tests/DuskTestCase.php的driver()方法中,把ChromeOptions显式设为 headless:$options = (new ChromeOptions)->addArguments([ '--headless', '--no-sandbox', '--disable-dev-shm-usage', '--disable-gpu', '--window-size=1920,1080' ])
- 若仍报
session not created,检查 Chrome 是否真的存在:在 CI 中运行google-chrome --version或chromium-browser --version,并调整ChromeOptions->setBinary()指向正确路径(如/usr/bin/chromium-browser)
如何写一个能真正点击并等待页面响应的测试用例
Dusk 的 click() 不会自动等待后续加载完成,容易因 DOM 未更新导致断言失败。必须配合显式等待(waitUntil() 或 assertSee() 等阻塞方法)。
- 不要这样写:
$browser->click('@login-button')->assertSee('Dashboard')(可能在跳转前就执行断言)
- 应该这样写:
$browser->click('@login-button') ->waitForLocation('/dashboard') ->assertSee('Welcome back');
- 对异步内容(如 Vue 渲染的列表),优先用
waitForText()或waitFor('.item-list li', 5),而不是依赖assertSee() - 若元素有动画或延迟渲染,加
pause(500)是临时解法,但应优先用waitFor系列代替
为什么 see() / assertSee() 总是失败,即使页面明明有文字
根本原因:Dusk 默认在页面 DOMContentLoaded 触发后即开始查找,但现代前端框架(如 Inertia、Livewire、Vue)的内容往往由 JS 异步注入,DOM 就绪 ≠ 内容就绪。
-
assertSee('Hello')查找的是 纯文本内容,不区分是否在<span>或v-if块里;如果该文本被 JS 动态插入,且没等 JS 执行完,就会找不到 - 更可靠的方式是结合选择器和可见性:
$browser->assertSeeIn('@welcome-message', 'Hello') // 要求元素存在且含该文本
- 或者用
waitForText('Hello')—— 它内部轮询document.body.innerText,比assertSee()更健壮 - 注意:所有
assert*方法都要求元素「已渲染且可见」,隐藏元素(display: none或visibility: hidden)不会被匹配
如何让 Dusk 测试不干扰本地开发数据库
Dusk 使用自己的 .env.dusk.<code> 环境文件,但很多人忽略它仍会读取 <code>DB_DATABASE,导致测试清空开发库。
- 务必在
.env.dusk.local中覆盖数据库配置:DB_CONNECTION=sqlite DB_DATABASE=:memory:(内存 SQLite 最安全)
- 如果非要用 MySQL,至少隔离库名:
DB_DATABASE=testing_app,并确保该库存在且可写
- 运行时必须指定环境:
php artisan dusk --env=dusk.local,否则会 fallback 到默认.env - 别在
DuskTestCase.php中手动调用Artisan::call('migrate:fresh')—— Dusk 已在每个测试前自动重置迁移(前提是usesDatabase()trait 已启用)
最常被跳过的一步是验证 chromedriver 和 Chrome 主版本号是否一致(比如 Chrome 124 需要 chromedriver 124.x),差一个小版本都可能静默失败;另外,waitForLocation() 对 SPA 路由(如 Vue Router history 模式)无效,得改用 waitForUrl() 或监听 window.location.pathname 变化。

