Codeception验收测试:如何检测JS函数调用或AJAX执行?
针对你的问题,我整理了几个无需代理、适配你当前Selenium+ChromeDriver环境的可行方案:
方案1:注入JS监听目标函数调用(推荐,直接满足你检查log.execute()是否执行的需求)
Codeception的Acceptance测试支持直接执行JS,我们可以通过重写目标函数的方式添加调用标记,之后在测试中验证这个标记:
$I = new AcceptanceTester($scenario); $I->amOnUrl('http://example.com'); // 等待log对象加载完成(避免页面未完全初始化就执行注入) $I->waitForJS("return typeof window.log !== 'undefined';", 5); // 注入JS包装原函数,添加调用标记 $I->executeJS(" // 保存原始的execute方法 window._originalLogExecute = window.log.execute; // 初始化调用标记 window.logExecuteWasCalled = false; // 重写execute方法,执行时标记为已调用 window.log.execute = function() { window.logExecuteWasCalled = true; // 调用原方法保证业务逻辑正常执行 return window._originalLogExecute.apply(this, arguments); }; "); // 如果你需要触发某些操作才会调用log.execute(),在这里添加触发步骤 // 比如 $I->click('#some-button'); // 检查标记是否为true,确认函数被执行 $wasCalled = $I->executeJS("return window.logExecuteWasCalled;"); $I->assertTrue($wasCalled, 'log.execute() 未被执行');
这个方法的优势是直接监听函数调用行为,不管AJAX请求是否成功,只要函数被执行就能检测到,完美匹配你的需求。
方案2:通过ChromeDriver获取网络日志验证AJAX请求
如果你更关心AJAX请求是否实际发送,可以利用ChromeDriver的性能日志功能,筛选目标请求:
- 先修改Codeception的
acceptance.suite.yml配置,启用性能日志:
modules: enabled: - WebDriver: url: 'http://example.com' browser: chrome capabilities: goog:chromeOptions: args: ["--enable-logging"] loggingPrefs: performance: 'ALL'
- 在测试中获取并分析日志:
$I = new AcceptanceTester($scenario); $I->amOnUrl('http://example.com'); // 等待页面加载完成,确保AJAX请求已发送 $I->wait(2); // 获取性能日志 $logs = $I->getDriver()->manage()->getLog('performance'); $targetAjaxFound = false; foreach ($logs as $logEntry) { $logData = json_decode($logEntry['message'], true); $request = $logData['message']['params']['request'] ?? []; // 替换成你的AJAX请求的特征(比如URL包含特定路径) if (!empty($request['url']) && strpos($request['url'], '/your-ajax-endpoint-path') !== false) { $targetAjaxFound = true; break; } } $I->assertTrue($targetAjaxFound, '目标AJAX请求未发送');
这个方法不需要修改页面JS,但需要你知道AJAX请求的具体特征(比如URL)。
方案3:换用PHPUnit + Facebook WebDriver直接操作
如果你觉得Codeception的封装不够灵活,可以直接用PHPUnit搭配官方的Selenium PHP绑定(Facebook WebDriver),逻辑和方案1类似:
use Facebook\WebDriver\Chrome\ChromeOptions; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; use PHPUnit\Framework\TestCase; class LogExecuteTest extends TestCase { protected RemoteWebDriver $driver; protected function setUp(): void { // 配置ChromeDriver启用日志(如果用方案2的话需要加) $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $this->driver = RemoteWebDriver::create( 'http://localhost:4444/wd/hub', // Selenium服务地址 $capabilities ); } public function testLogExecuteIsCalled(): void { $this->driver->get('http://example.com'); // 等待log对象加载 $this->driver->wait(5)->until(function ($driver) { return $driver->executeScript("return typeof window.log !== 'undefined';"); }); // 注入监听JS $this->driver->executeScript(" window.logExecuteCalled = false; const original = window.log.execute; window.log.execute = function() { window.logExecuteCalled = true; return original.apply(this, arguments); }; "); // 检查调用标记 $wasCalled = $this->driver->executeScript("return window.logExecuteCalled;"); $this->assertTrue($wasCalled); } protected function tearDown(): void { $this->driver->quit(); } }
注意事项
- 如果
log对象是页面异步加载生成的,一定要用waitForJS等待对象初始化完成后再注入监听代码; - 网络日志方案需要确保ChromeDriver版本和Chrome浏览器版本兼容,避免日志无法正常获取。
内容的提问来源于stack exchange,提问作者Gumma Mocciaro
相关产品推荐
相关产品推荐

