使用Laravel Dusk测试PayPal支付时如何处理Cookie横幅?
问题
我开发的Web应用集成了Stripe与PayPal,并用Laravel Dusk搭建了二者的集成测试。但PayPal测试在GitHub Actions上的失败率约50%,就算加了条件逻辑也没用——根源是PayPal沙盒会随机弹出Cookie横幅,而且出现时机完全没规律。
想问两个点:
- 在PayPal修复沙盒之前,有什么解决办法?
- 我写的检测Cookie横幅是否存在的if条件为什么只有时候生效?
以下是我的Dusk测试简化版本:
public function test_paypal_payments_are_working() { $this->browse(function (Browser $browser) { $browser->visit("/product1") ->waitForLocation('/payment') ->resize(1920, 2000) # 临时方案:确保PayPal按钮始终可点击 ->withinFrame('#paypal-button-container iframe', function($browser) { $browser ->waitFor(".paypal-button") ->click(".paypal-button"); }); $mainWindow = $browser->driver->getWindowHandle(); $paypalWindow = collect($browser->driver->getWindowHandles())->last(); // 获取PayPal弹窗 $browser->driver->switchTo()->window($paypalWindow); // 切换到弹窗 $browser ->disableFitOnFailure() # 强制截图显示交互时的屏幕状态 ->click("#btnLogin") ->storeSource("debug"); # 验证PayPal Cookie横幅按钮的ID # 检查Cookie横幅按钮是否存在,存在则点击接受 if ($browser->element('#acceptAllButton')) { $browser ->click("#acceptAllButton"); } $browser ->waitFor("#payment-submit-btn") ->click("#payment-submit-btn"); $browser->driver->switchTo()->window($mainWindow); // 切回原窗口 $browser->waitFor("@payment-success", 15) ->assertSeeIn("@payment-success"); }); }
解决方案
为什么你的if条件仅有时生效?
- 无等待机制:
$browser->element('#acceptAllButton')是同步执行的,一旦Cookie横幅延迟加载(比如PayPal沙盒的网络波动导致),代码执行时元素还没渲染出来,就会直接判定为不存在,后续点击逻辑不执行,之后横幅弹出就会挡住操作。 - 未处理异常:Dusk的
element()方法在元素不存在时会抛出NoSuchElementException,而不是返回null,你的代码没做异常捕获,一旦元素不存在,整个测试直接崩溃,而非跳过点击步骤。
可行解决办法
办法1:用等待+异常捕获处理横幅
把原来的if判断换成带等待和异常捕获的逻辑,兼容横幅延迟出现的场景:
// 替换原来的if判断代码 try { // 最多等5秒,直到Cookie接受按钮出现 $browser->waitFor('#acceptAllButton', 5)->click('#acceptAllButton'); } catch (\Facebook\WebDriver\Exception\TimeoutException $e) { // 没弹出横幅,直接跳过 }
waitFor会轮询查找元素,超时则捕获异常跳过,既解决了时机问题,也不会因为元素不存在导致测试崩溃。
办法2:通过浏览器配置禁用Cookie横幅
直接在Dusk的Chrome启动参数里添加禁用Cookie提示的配置,从根源上阻止横幅弹出。修改tests/DuskTestCase.php的driver()方法:
protected function driver() { $options = (new ChromeOptions)->addArguments([ '--disable-gpu', '--headless=new', // 添加以下参数禁用Cookie控制功能 '--disable-features=CookieControls', '--disable-site-isolation-trials', '--allow-insecure-localhost', // 强制浏览器默认接受所有Cookie '--user-data-dir=/tmp/dusk-chrome', '--profile-directory=Default', '--disable-popup-blocking', ]); return RemoteWebDriver::create( 'http://localhost:9515', DesiredCapabilities::chrome()->setCapability( ChromeOptions::CAPABILITY, $options ) ); }
这个方法让Chrome默认跳过Cookie提示,适合稳定的CI环境(比如GitHub Actions)。
办法3:等待页面完全加载后再操作
切换到PayPal弹窗后,先等待页面所有资源加载完成,再执行后续逻辑:
$browser->driver->switchTo()->window($paypalWindow); // 等待页面加载完成(document ready状态) $browser->waitUntil(function ($browser) { return $browser->script('return document.readyState === "complete";')[0]; }); // 执行登录操作 $browser->disableFitOnFailure()->click("#btnLogin"); // 再处理Cookie横幅 try { $browser->waitFor('#acceptAllButton', 3)->click(); } catch (\Exception $e) {}
确保页面所有异步资源(包括延迟加载的Cookie横幅)都渲染完成后再判断,减少时机问题导致的检测失败。
内容的提问来源于stack exchange,提问作者Hashim Aziz
相关产品推荐
相关产品推荐

