Cypress - 框架 (Frames)
Cypress - 使用 Iframe
Section titled “Cypress - 使用 Iframe”网页有时使用 iframes(内联框架)来嵌入来自其他来源的内容或隔离页面的一部分。Cypress 提供了与 iframe 内部元素交互的机制。
原生 Iframe 交互
Section titled “原生 Iframe 交互”Cypress 可以原生地与 iframe 元素交互。通常的方法包括:
- 定位页面上的 iframe 元素。
- 访问其
contentDocument属性,该属性包含 iframe 的 DOM。 - 确保文档已加载,然后使用
cy.wrap()包装其body(或 iframe 内的特定元素),以便在 iframe 的上下文中继续使用 Cypress 命令。
在尝试与其内容交互之前,确保 iframe 已完全加载非常重要。Cypress 的重试机制有所帮助,但有时可能需要进行明确的检查。
用于重用的自定义命令(推荐)
Section titled “用于重用的自定义命令(推荐)”为了使测试更清晰,你可以在 cypress/support/commands.js 中创建一个自定义命令来封装 iframe 交互逻辑:
Cypress.Commands.add('getIframeBody', (iframeSelector) => { // 获取 iframe > 获取文档 > 获取 body cy.log('Getting iframe body'); return cy.get(iframeSelector, { timeout: 10000 }) .its('0.contentDocument.body').should('not.be.empty') // 然后包装 body .then(cy.wrap);});然后你在测试中使用这个自定义命令:
cy.getIframeBody('iframe#my-iframe').find('#element-inside-iframe').click();直接交互示例
Section titled “直接交互示例”下面是直接与 iframe 交互而无需自定义命令的示例。假设你有一个 ID 为 the-iframe 的 iframe,其内部有一个 ID 为 iframe-button 的按钮。
describe('Iframe Interaction Test', () => { it('should interact with an element inside an iframe', () => { cy.visit('your-page-with-an-iframe.html'); // 替换为你自己的测试页面
// 获取 iframe 元素 cy.get('iframe#the-iframe') .its('0.contentDocument.body') // 访问 iframe 文档的 body .should('not.be.empty') // 确保 body 已加载 .then(cy.wrap) // 包装 body 以使用 Cypress 命令 .find('#iframe-button') // 在 iframe 中查找按钮 .should('be.visible') .click();
// 如果点击触发了 iframe 外部的更改,你也可以断言这些更改 // cy.get('#status-message').should('contain.text', 'Button clicked!'); });});历史说明:cypress-iframe 插件
Section titled “历史说明:cypress-iframe 插件”在早期版本的 Cypress 中,或者对于特定的复杂场景,cypress-iframe 插件是一个常见的解决方案。它提供了诸如 cy.frameLoaded() 和 cy.iframe() 等命令。
// 使用 cypress-iframe 的示例(现在不太常见)// 首先,安装:npm install -D cypress-iframe// 然后,在 cypress/support/e2e.js(或 commands.js)中:// import 'cypress-iframe';
describe('Iframe with cypress-iframe plugin', () => { it.skip('Test Case with cypress-iframe', () => { // .skip 因为更推荐使用原生方法 cy.visit("https://jqueryui.com/draggable/"); // 示例网站 cy.frameLoaded('.demo-frame'); // 使用选择器加载框架 cy.iframe().find("#draggable").then((el) => { const text = el.text(); expect(text).to.contains('Drag me around'); cy.log(text); }); });});虽然 cypress-iframe 仍然有效,但 Cypress 原生处理 iframe 的能力已经有所改进,并且创建如上所示的自定义命令通常是更好的选择,以便更好地控制并与 Cypress 的内置命令结构保持一致。
处理 Iframe 的注意事项
Section titled “处理 Iframe 的注意事项”- 跨域 Iframe: 与跨域 iframe 交互存在安全限制。如果你的
cypress.config.js中将chromeWebSecurity设置为false,Cypress 可以与它们交互,但这通常不推荐用于生产环境测试,因为它不能反映真实用户浏览器的安全性。如果可能,请隔离测试跨域 iframe 中的内容。 - 加载时间: Iframe 可能需要时间加载。确保你的命令等待 iframe 及其内容准备就绪。Cypress 的默认超时和重试机制通常可以处理这个问题,但可能需要明确的等待或对 iframe 内容进行断言。
- 多个 Iframe: 如果页面有多个 iframe,你需要使用其选择器唯一标识你想要交互的那个。
与 iframe 交互需要仔细定位,但 Cypress 提供了有效的工具来实现这一点。