其他测试框架 强大的全新 Web UI 测试框架 Cypress - Cypress 处理 iframe

非洲赵子龙 for Cypress · 2019年02月18日 · 最后由 Freya.Ding 回复于 2021年09月10日 · 801 次阅读

iframe是一种常见的 web 页面展示方式,比如斗鱼的登录框就是一个 iframe 实现的,下面示例 Cypress 如何处理嵌套 iframe 的元素,因为想像操作一般元素的用法去操作 iframe 里面的元素,一步到位是会报错的 (找不到元素)。

  • 首先写一个示例 web 页面
    比如我们这里是用golang/gin框架随便实现的一个页面,很简单,大概 html 代码如下

    • index.tmpl
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>iframe测试</title>
</head>
<body>
<iframe id="iframe1" src="http://www.runoob.com">
</iframe>
<p>
    <iframe name="iframe2name" id="iframe2" src="/login" frameborder="0" align="left" width="800" height="800" scrolling="no"></iframe>
</p>
<span>这里是正文................</span>
</body>
</html>
  • login.tmpl
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>登录页</title>
</head>
<body>
    <form>
        <input id="login_input" type="text" placeholder="登录页输入框">
    </form>
    <iframe id="innerIframe" src="/register" width="200" height="200">

    </iframe>
</body>
</html>
  • register.tmpl
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>登录页</title>
</head>
<body>
<form>
    <input id="register_input" type="text" placeholder="注册页输入框">
</form>
</body>
</html>

它大概长这样:

我们的目标是操作最里层的 innerIframe。
整个页面的树形结构大概如下:


注意:运行调试这种本地起来的 web server,需要在 Cypress 的 plugins/index.js 里添加如下代码,否则 cypress 无法调试你的应用,具体问题详见描述截止 3.1.5 版本的 Cypress 已经解决了该问题,无需再添加如下代码,Cypress<3.1.5 的版本请在 Cypress 的 plugins/index.js 添加如下配置:

module.exports = (on) => {
  on('before:browser:launch', (browser = {}, args) => {
    if (browser.name === 'chrome') { 
      // ^ make sure this is your browser name, you may 
      // be using 'canary' or 'chromium' for example, so change it to match!
      args.push('--proxy-bypass-list=<-loopback>')
      return args
    }
  })
}
  • 测试实现代码
describe("IframeTest", function() {
  it.only("嵌套Iframe测试", function() {
    cy.visit("/iframeTest");
    cy.get("#iframe2", { timeout: 20000 })
      // 先判断最外层topIframe的存在
      .should($topIframe => {
        expect($topIframe.contents().find("#innerIframe")).to.exist;
      })
      // 再找嵌套的innerIframe
      .then($topIframe => {
        return cy.wrap($topIframe.contents().find("#innerIframe"));
      })
       // 找我们需要的元素
      .then($innerIframe => {
        return cy.wrap($innerIframe.contents().find("#register_input"));
      })
      // 对元素的处理
      .then($expectElementLocator => {
        cy.wrap($expectElementLocator).type("TTT");
      });
  });
});
  • 效果

注:截止目前为止,这个问题官方还没有完美解决,这个方案和 github 上的这个issue都是 workround(笔者试了下该 issue 下 paulfalgout 作者的方案,其实不好用,你们试试就知道了,在某些条件下会持续很久都不进行下一步动作),希望官网早日解决这个常见情况下的页面操作,也希望更多高手参与进来,找到一个更加完美的方法!

Cypress 入门系列:

注:目前官方团队正在开发 Python 版本,同样的 Free to use,对 JS 恐惧的同学不妨等一等,或者直接 JS 上手,非常简单,VSCode 装上之后,你会爱上 Cypress 和 JS,笔者会慢慢介绍各种 Web UI 自动化复杂场景下 Cypress 的强大应对,目前还没发现 Cypress 无法处理的问题!欢迎一起入坑!QQ 群:947886065.

共收到 6 条回复 时间 点赞
module.exports = (on) => {
  on('before:browser:launch', (browser = {}, args) => {
    if (browser.name === 'chrome') { 
      // ^ make sure this is your browser name, you may 
      // be using 'canary' or 'chromium' for example, so change it to match!
      args.push('--proxy-bypass-list=<-loopback>')
      return args
    }
  })
}

-------------------------------我是分界线-------------------------------
自己学习了一些 js 的基础语法, 但是看上面的这段代码还是会看到不少陌生语法 (主要是函数传参那块的书写规则),
想问下楼主, 要学 cypress 框架之前, 是不是最好把 ES6 的相应语法也熟悉一下再开始玩会更好呢?

zhang 回复

ES6 是什么😄... 我不是专业搞 JS 出身的哈,但是我可以回答你最后的问题:“不是必须”,因为测试本身重在 “应用”,先通过应用解决一些实际场景中的问题,就会慢慢有一个所谓的 “套路”,等你慢慢习惯于这些 “套路” 的时候,再去研究原理,就会发现 “哦,原来不过如此”...有点啰嗦了哈,就是 “应用”>“建立兴趣”>“形成套路”>“深究原理” 的过程,我目前也处于很初级的阶段,一起进步😄

我用的方法是拿到 cookie/session/token 后,注入到网页中,然后直接 visit 这个 iframe。

嗯 🐂🍺的思路!还没试过。问下,如果直接 visit 的话,会不会整个页面都编程 iframe 了?

谢谢大佬~

大佬,没找到私信的地方,提一个跟本帖无关的问题。最近我在试 cypress-wait-until 这个插件,但是无论如何设置的 timeout 都没起作用,一直还是用的 cypress 默认的 timeout, 翻遍了网站也没找到答案。不知能否帮忙看一下?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册