Skip to content

Cypress - 框架 (Frames)

网页有时使用 iframes(内联框架)来嵌入来自其他来源的内容或隔离页面的一部分。Cypress 提供了与 iframe 内部元素交互的机制。

Cypress 可以原生地与 iframe 元素交互。通常的方法包括:

  1. 定位页面上的 iframe 元素。
  2. 访问其 contentDocument 属性,该属性包含 iframe 的 DOM。
  3. 确保文档已加载,然后使用 cy.wrap() 包装其 body(或 iframe 内的特定元素),以便在 iframe 的上下文中继续使用 Cypress 命令。

在尝试与其内容交互之前,确保 iframe 已完全加载非常重要。Cypress 的重试机制有所帮助,但有时可能需要进行明确的检查。

用于重用的自定义命令(推荐)

Section titled “用于重用的自定义命令(推荐)”

为了使测试更清晰,你可以在 cypress/support/commands.js 中创建一个自定义命令来封装 iframe 交互逻辑:

cypress/support/commands.js
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();

下面是直接与 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 中,或者对于特定的复杂场景,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: 与跨域 iframe 交互存在安全限制。如果你的 cypress.config.js 中将 chromeWebSecurity 设置为 false,Cypress 可以与它们交互,但这通常不推荐用于生产环境测试,因为它不能反映真实用户浏览器的安全性。如果可能,请隔离测试跨域 iframe 中的内容。
  • 加载时间: Iframe 可能需要时间加载。确保你的命令等待 iframe 及其内容准备就绪。Cypress 的默认超时和重试机制通常可以处理这个问题,但可能需要明确的等待或对 iframe 内容进行断言。
  • 多个 Iframe: 如果页面有多个 iframe,你需要使用其选择器唯一标识你想要交互的那个。

与 iframe 交互需要仔细定位,但 Cypress 提供了有效的工具来实现这一点。