Laravel 12 中使用 PEST 4 测试基于 Fetch API 提交 FormData 的表单时数据丢失问题求助
我之前遇到过类似的问题,Laravel Dusk(PEST浏览器测试底层基于它)在处理通过Fetch API提交的FormData时偶尔会出现后端无法解析数据的情况,结合你的场景,这里有几个排查和解决的方向:
1. 先确认后端端点本身是否正常
首先排除后端代码的问题,写一个简单的单元测试直接POST请求端点:
it('test backend endpoint directly', function () { $response = $this->post('/test', ['test_input' => 'Hello from JS!']); $response->assertJson(['message' => 'Hello from JS!']); });
如果这个测试通过,说明后端逻辑没问题,问题出在浏览器测试的JS交互模拟上。
2. 确保测试等待异步请求完成
Fetch是异步操作,点击按钮后立即执行assertSee会导致断言在AJAX响应返回前执行。修改测试代码,添加等待逻辑:
it('test js fetch', function () { $page = visit('/test'); $page->click('Test') ->waitFor('#response', 5) // 等待5秒,直到响应元素加载或更新 ->assertSee('Hello from JS!') ->screenshot(); });
不过从你的截图看,页面已经显示了"No input provided",说明后端已经返回了响应,这个可能不是核心问题,但加上等待逻辑能避免异步时序问题。
3. 检查ChromeDriver版本兼容性
Dusk依赖ChromeDriver,版本不匹配会导致各种JS交互异常。运行Laravel自带的命令更新ChromeDriver:
php artisan dusk:chrome-driver
确保ChromeDriver版本和你本地安装的Chrome浏览器版本一致(可以在Chrome的chrome://version/查看版本号)。
4. 处理CSRF Token(虽然浏览器中正常,但测试环境可能需要)
你的视图中没有添加CSRF meta标签,虽然浏览器中可能通过Cookie自动传递XSRF-TOKEN,但Dusk的模拟环境偶尔会出现问题。修改视图添加CSRF标签:
<head> <title>Test page</title> <meta name="csrf-token" content="{{ csrf_token() }}"> </head>
然后在JS代码中手动带上CSRF头:
document.getElementById('test_btn').addEventListener('click', () => { const formData = new FormData(); formData.append('test_input', 'Hello from JS!'); const csrfToken = document.querySelector('meta[name="csrf-token"]').content; fetch('/test', { method: 'POST', headers: { 'X-CSRF-TOKEN': csrfToken }, body: formData }) .then(async response => { const respJson = await response.json(); document.getElementById('response').innerHTML = respJson.message; }); });
5. 尝试关闭Headless模式
Chrome的Headless模式偶尔会有兼容性问题,修改config/dusk.php中的Chrome配置,注释掉Headless参数:
'chrome' => [ 'driver' => 'chrome', 'options' => [ '--disable-gpu', // '--headless=new', // 暂时注释这行 ], ],
重新运行测试,看看是否正常。
6. 换用$request->input()代替$request->get()
虽然get()方法通常能获取到数据,但在multipart/form-data请求下,input()方法的解析逻辑可能更稳定:
public function test(Request $request): View|JsonResponse { if ($request->isMethod('POST')) { return response()->json(['message' => $request->input('test_input', 'No input provided')]); } return view('test'); }
如果以上方法都不行,可以在控制器中输出请求的详细信息,帮助排查:
public function test(Request $request): View|JsonResponse { if ($request->isMethod('POST')) { return response()->json([ 'message' => $request->input('test_input', 'No input provided'), 'request_all' => $request->all(), 'content_type' => $request->header('Content-Type'), 'post_data' => $request->post() ]); } return view('test'); }
然后查看测试截图中的response元素内容,就能知道后端到底收到了什么请求数据,从而定位问题。
内容的提问来源于stack exchange,提问作者constantin.iordan

