如何在Cypress中捕获iframe沙盒/CSP限制的浏览器特殊错误日志?
问题
我正在编写Cypress测试,验证iframe的sandbox和CSP权限。已禁用allow-modals,此时alert()调用按预期失败,Chrome会生成错误信息:
VM271 about:srcdoc:1 Ignored call to 'alert()'. The document is sandboxed, and the 'allow-modals' keyword is not set.
这符合预期,但我没办法在Cypress里捕获这条错误日志。
我尝试过监听iframe/主窗口的console.error、error事件,也给这些对象加了Cypress间谍,但这条浏览器生成的错误完全不会触发这些间谍。不过iframe里的window.alert()间谍确实能捕获到调用(符合预期),只是浏览器没弹出alert窗口。
想知道有没有办法捕获这类浏览器“特殊”错误日志?如果它不通过窗口/iframe的常规日志渠道输出,那是怎么被记录的?
相关代码
iframe代码:
<iframe><script>alert('test');</script></iframe>
Cypress测试代码:
let iframeWindow; let spyErrorIframe; cy.get('iframe').then(($iframe) => { iframeWindow = $iframe[0].contentWindow; function errorHandler(...args) { console.log('~~~ iframe'); return iframeWindow.console.error(...args); } spyErrorIframe = cy.spy(errorHandler); iframeWindow.addEventListener('error', spyErrorIframe); iframeWindow.onerror = spyErrorIframe; cy.spy(iframeWindow.console, 'log'); cy.spy(iframeWindow.console, 'error'); cy.spy(iframeWindow, 'alert'); }); let mainWindow; let spyErrorWindow; cy.window().then((win) => { mainWindow = win; function errorHandler(...args) { console.log('~~~ window'); return iframeWindow.console.error(...args); } spyErrorWindow = cy.spy(errorHandler); mainWindow.addEventListener('error', spyErrorWindow); mainWindow.onerror = spyErrorWindow; cy.spy(win, 'alert'); cy.spy(win.console, 'log'); cy.spy(win.console, 'error'); }); cy.wait(GENERIC_TIMEOUT + 1000).then(() => { console.log('~~~ iframe console.error', iframeWindow.console.error.getCalls()); // no calls console.log('~~~ window console.error', mainWindow.console.error.getCalls()); // no calls console.log('~~~ cypress console.error', console.error.getCalls()); // no calls console.log('~~~ iframe error event', spyErrorIframe.getCalls()); // no calls console.log('~~~ window error event', spyErrorWindow.getCalls()); // no calls console.log('~~~ iframe alert', iframeWindow.alert.getCalls()); // one call as expected console.log('~~~ window alert', mainWindow.alert.getCalls()); // no calls });
解答
这类错误属于浏览器内部诊断日志,不会通过常规的console.error或window.error事件触发,而是直接通过Chrome DevTools Protocol(CDP)输出到浏览器控制台。要在Cypress中捕获它,需要借助CDP的Log.entryAdded事件。
具体实现步骤
- 在测试开始前,通过Cypress的
cy.window()获取主窗口,调用CDP的Log.enable开启日志监听。 - 监听
Log.entryAdded事件,过滤出符合目标错误信息的日志条目。 - 验证该日志是否被捕获,以此证明iframe的sandbox权限生效。
示例代码
cy.window().then((win) => { // 开启CDP日志监听 win.cdp('Log.enable'); // 存储捕获到的日志 let sandboxError = null; // 监听日志条目添加事件 win.cdp('Log.entryAdded', (entry) => { if (entry.message.includes("Ignored call to 'alert()'. The document is sandboxed")) { sandboxError = entry; } }); // 监听iframe的alert调用 cy.get('iframe').its('0.contentWindow').then((iframeWin) => { cy.spy(iframeWin, 'alert').as('iframeAlert'); }); // 等待并验证结果 cy.wait(1000).then(() => { // 验证alert被调用 cy.get('@iframeAlert').should('have.been.calledWith', 'test'); // 验证浏览器生成的sandbox错误被捕获 expect(sandboxError).to.not.be.null; expect(sandboxError.message).to.include("Ignored call to 'alert()'"); }); });
补充说明
- 这类浏览器内部日志不会进入页面的JavaScript执行上下文,所以常规的
console.error间谍或error事件监听器无法捕获。 - 除了CDP方法,也可以通过验证
alert()被调用但没有实际弹窗(结合Cypress自动拦截弹窗的特性)来间接证明权限生效,但CDP方法更直接,能明确捕获到浏览器的错误提示。
内容的提问来源于stack exchange,提问作者cosmonot1
相关产品推荐
相关产品推荐

