Laravel Dusk实现用户快速连续点击测试的方法咨询
我正在用Laravel Dusk测试一个Vue组件,这个组件的作用是防止用户连续点击提交按钮,避免重复提交数据。组件的逻辑是点击后切换成禁用状态的按钮(隐藏原提交按钮,显示一个加载状态的div)。
我尝试模拟用户快速连续点击的测试,但遇到了问题:当我调用$browser->assertSourceHas($buttonEnableSource)->click('@submit-button-component')之后,Dusk会等待浏览器进程完成,要是直接连续调用两次click('@submit-button-component'),就会因为找不到原来的Vue元素而报错。
我的Vue组件代码:
<template> <div> <input type="submit" class="button_orange button_big" :value="value" v-show="!isSubmitting" @click="startSubmit"> <div class="button_white button_big" v-show="isSubmitting">{{ value }}</div> </div> </template> <script> export default { data() { return { isSubmitting: false, }; }, props: { value: { type: String, default: '', }, }, methods: { startSubmit() { this.isSubmitting = true; }, }, }; </script>
我的测试代码:
public function testRegisterDoubleClickNoDuplication() { $this->browse(function (Browser $browser) { $buttonValue = __('common.register'); $buttonEnableSource = "<input type=\"submit\" class=\"button_orange button_big\" value=\"{$buttonValue}\" />"; $browser->visit(route('staffs.create')) ->assertSourceHas($buttonEnableSource) ->click('@submit-button-component') ->assertSourceMissing($buttonEnableSource) ->assertSee('スタッフ詳細'); }); }
解决方案:用JavaScript直接触发原生点击事件
问题出在Dusk的click()方法本身:它会先等待元素处于可见且可交互的状态,第一次点击后原input按钮已经被v-show="!isSubmitting"隐藏了,第二次调用click()自然找不到元素。
要模拟快速连续点击,我们可以绕过Dusk的元素检查机制,直接用JavaScript触发按钮的点击事件——这样不管元素之后是否隐藏,只要第一次点击时它存在,就能连续触发两次点击。
修改后的测试代码如下:
public function testRegisterDoubleClickNoDuplication() { $this->browse(function (Browser $browser) { $buttonValue = __('common.register'); $buttonEnableSource = "<input type=\"submit\" class=\"button_orange button_big\" value=\"{$buttonValue}\" />"; $browser->visit(route('staffs.create')) ->assertSourceHas($buttonEnableSource) // 用JavaScript连续触发两次点击,模拟用户快速操作 ->script("document.querySelector('[data-testid=\"submit-button-component\"] input').click();") ->script("document.querySelector('[data-testid=\"submit-button-component\"] input').click();") // 验证原提交按钮已隐藏 ->assertSourceMissing($buttonEnableSource) // 验证页面跳转到员工详情页 ->assertSee('スタッフ詳細'); }); }
注意:这里我假设你的
@submit-button-component是通过data-testid定义的Dusk选择器,如果是其他类型的选择器(比如class),记得调整querySelector里的内容。
进阶:验证后端只处理一次请求
光验证前端状态还不够,最好确保后端确实只收到一次提交请求。你可以用Laravel的事件监听或者mock来实现:
public function testRegisterDoubleClickNoDuplication() { // 断言员工创建事件只触发一次 $this->expectsEvents(\App\Events\StaffCreated::class)->once(); $this->browse(function (Browser $browser) { $buttonValue = __('common.register'); $buttonEnableSource = "<input type=\"submit\" class=\"button_orange button_big\" value=\"{$buttonValue}\" />"; $browser->visit(route('staffs.create')) ->assertSourceHas($buttonEnableSource) ->script("document.querySelector('[data-testid=\"submit-button-component\"] input').click();") ->script("document.querySelector('[data-testid=\"submit-button-component\"] input').click();") ->assertSourceMissing($buttonEnableSource) ->assertSee('スタッフ詳細'); }); }
这样就能彻底验证你的防重复点击组件既在前端正确切换状态,又在后端防止了重复提交。
内容的提问来源于stack exchange,提问作者ttakahashi2013

