草庐IT

Cypress 定位、操作页面元素

taoli-qiao 2023-04-09 原文

想象一下,当我们做手动测试时执行的步骤是:创建测试数据-通过页面操作完成业务流程操作-检查执行结果是否符合预期。自动化测试执行过程和手动测试过程一致,区别是把手动的步骤转换为脚本自动执行而已。除完成手动测试中数据准备,业务流程执行、结果校验外,自动化测试还需做到多环境切换运行,故自动化测试还涉及配置信息管理。为了降低维护成本需要考虑测试框架对代码调试的支持,另外,需要提升脚本稳定性、可读性、获取度量指标进行持续优化。下图是搭建稳定、完善的UI层自动化测试需要考虑的点。

此次将从第一个模块“定位操作页面元素”开始详细介绍如何使用cypress框架实现定位操作页面元素,为了便于学习,拆分了2分task

  • Task1:cypress定位页面元素
  • Task2:cypress定位操作页面元素练习

Cypress定位页面元素

本小结将给大家介绍常用的定位element方法,使用的被测系统url是 “https://angular.realworld.io”。练写的第一个场景是点击“Sign in”菜单,完成登陆操作。

使用cypress编写UI层自动化case默认情况下,case文件都放到integration目录下。demo中创建的文件目录如下所示,大家可以自定义integration下所有目录名称。只需控制所有测试文件必须以_spec.js结尾即可。因为在cypress.json文件中定义了testFiles=**/*_spec.js。同样,执行命令“npm run loginDemo”或者dashboard上选择 “loginDemo_spec.js”测试文件运行测试案例。

loginDemo_spec.js脚本内容如下所示

describe("login demo", () => {                     
    //describe是mocha中的语法格式,作用是可以在case上添加描述信息,此外还支持 

    it("login test", () => {
        cy.visit("https://angular.realworld.io");  
        //访问一个页面连接使用cy.visit()方式

        cy.get('app-layout-header ul li a[href="/login"]').click();    
        //点击右上角“Sign in”
        //上面定位element使用CSS selector的方式,后面会详细介绍如何使用该方式定位element

        cy.get('[formcontrolname=email]').type("e2etest@163.com");    
        //输入账户名称

        cy.get('[formcontrolname=password]').type("12345678"); 
        //输入密码 

        cy.get('app-auth-page button[type="submit"]').click();        
        //点击sign in button完成登陆操作
    })
});

上面演示了利用cypress框架实现简单的登陆操作场景。Cypress框架底层套用了很多现有的优秀js工具,例如Mocha,Chai,Chai-jquery,Simon.JS其。中查找页面element借助了jQuery强大的查找element引擎,实际就是对jQuery的一些API进行了二次封装。为了透彻理解UI层测试工具如何选择定位element,我们先简单了解下jQuery如何查找element。jQuery可以通过element的标签、class、id、type、attribute、value of attribute查找页面元素,且所有的查找都使用“$()”固定格式。例如有如下html片段

利用jQuery选择button并进行点击操作,实现方式有如下6种常用方式。

 Cypress进行二次封装后,同样也提供了以上六种selector,当然以上只是最常用的六种查找element的方式,在介绍cypress时,还会讲解其他常用的定位element方式。例如如下图所示,需要查找右上角的“Sign in” element.

Cypress查找element大部分是cy.get("css selector")格式,如下是查找“Sign in” element的13种方式。介绍这么多方式的目的是真实系统中可能无法直接通过class或者type或者id等定位某些element,此时就可以考虑多种方式结合的策略,例如下面第一种方式,同时通过name、attribute value逐级定位element。同样dashboard中选择“findElement_spec.js”脚本即可运行下面的案例。

describe("query element demo", () => {
    it("query element test", () => {
        cy.visit("https://angular.realworld.io");
        cy.get('app-layout-header ul li a[href="/login"]').click();   
        //利用name,attribute value逐级查找element

        cy.get('app-layout-header ul li>a[href="/login"]').click();   
        //li和a标签中无其他标签,li和a逐级查询是可以写出li>a,也可以写出li a

        cy.get('app-layout-header a[href="/login"]').click();         
        // app-layout-header标签后直接跳转到a标签进行定位

        cy.get('app-layout-header .nav-item a[href="/login"]').click(); 
        //利用name,class,attribute value定位element

        cy.get('[href="/login"]').click();  
        //利用attribute value查找element

        cy.contains("Sign in").click();     
        //查找text中包含“Sign in”的element,可以看到这种定位element不是采用cy.get()格式

        cy.get('app-layout-header').find('li a[href="/login"]').click();  
        //利用find方法,先通过name=“app-layout-header”查找该element下的所有子elements,再利用find从子elements中查找符合条件的唯一element

        cy.get('app-layout-header li').children('a[href="/login"]').click();   
        //和上面类似,只是用了children这种写法

        cy.get('a[href="/login"]').parent('li').should("have.class", "nav-item");  
        //除了通过children()获取某个element下的所有子elements,还可以通过parent()获取某个element的父elements,parent("CSS selector 语法")

        cy.get('app-layout-header li a').eq(0).click();   
        //如何查询到多个element,取第一个element

        cy.get('app-layout-header li a').first().click(); 
        //如果查询到多个element,那么取第一个element

        cy.get('app-layout-header li a').last().click(); 
        //如果查询到多个element,取最后一个element

        cy.get('app-layout-header li a').first().should("have.attr","routerlink");  
        //对查询到的element进行校验
        
        cy.get('select').select('apples'); 
        //下拉列表选择
    })
});

 以上演示了使用cypress框架时如何定位页面元素,以及一些基本的操作,例如type(text),click()操作。大家可以自己动手使用上面的方法定位任意页面element,只有熟练掌握上面各种定位页面元素方式,,才能灵活结合各种方式快速定位页面元素。接下来将给大家安排一个小练习。

cypress定位操作页面元素练习

白看不如一练,接下来访问一个angular的小web应用 “ http://juliemr.github.io/protractor-demo” ,如下图所示,利用cypress完成自动化测试。

需要完成的测试场景是:输入不同的数字,点击运算符号,点击go,校验下面结果列表中计算的结果正确。安装加、减、乘、除、求余的顺序依次操作,直到测试完各种类型的数字运算都正确。这个小demo看似简单,但对于不熟悉UI层测试的小伙伴还是有一定难度。该测试场景中涉及到的点:

  • 第一:有个select类型的element需要按测试场景制定的顺序选择不同类型的运行符号。
  • 第二:判断结果的时候下面的table是动态变化的,如何准确获取到最新的计算结果并校验。
  • 第三:点击go后,会等待一下才会显示计算结果,如何进行合理的等待处理。

大家可以利用上面所学先动手练习,当遇到问题时无法解决时再看下面的实现代码。自动化测试脚本如下,同样dashboard中选择“calculateTest_spec.js”脚本即可运行下面的案例。

describe("calculate test", () => {
    it("calculate test", () => {
    cy.visit("http://juliemr.github.io/protractor-demo/");    //访问被测应用
    cy.get('input[ng-model="first"]').clear();
        cy.get('input[ng-model="first"]').type("2");      //第一个输入框中输入数字
        cy.get('select[ng-model="operator"]').select("ADDITION");   //选择加运算符号
        cy.get('input[ng-model="second"]').clear();
        cy.get('input[ng-model="second"]').type("3");     //第二个输入框中输入数字
        cy.get("#gobutton").click();
        cy.get('h2').should("contain","5");   //校验显示的计算结果是否正确
        cy.get("tbody tr").first().find('td').last().should("contain","5");   //校验计算结果是否正确

        cy.get('input[ng-model="first"]').type("3");
        cy.get('select[ng-model="operator"]').select("SUBTRACTION");    //选择减预算符
        cy.get('input[ng-model="second"]').type("4");
        cy.get("#gobutton").click();
        cy.get('h2').should("contain","-1");
        cy.get("tbody tr").first().find('td').last().should("contain","-1");

        cy.get('input[ng-model="first"]').type("3");
        cy.get('select[ng-model="operator"]').select("MULTIPLICATION");  //选择乘运算符
        cy.get('input[ng-model="second"]').type("5");
        cy.get("#gobutton").click();
        cy.get('h2').should("contain","15");
        cy.get("tbody tr").first().find('td').last().should("contain","15");

        cy.get('input[ng-model="first"]').type("25");
        cy.get('select[ng-model="operator"]').select("DIVISION");    //选择除运算符
        cy.get('input[ng-model="second"]').type("5");
        cy.get("#gobutton").click();
        cy.get('h2').should("contain","5");
        cy.get("tbody tr").first().find('td').last().should("contain","5");

        cy.get('input[ng-model="first"]').type("25");
        cy.get('select[ng-model="operator"]').select("MODULO");    //选择求余运算符
        cy.get('input[ng-model="second"]').type("6");
        cy.get("#gobutton").click();
        cy.get('h2').should("contain","1");
        cy.get("tbody tr").first().find('td').last().should("contain","1");

    })
});

 大家可以反复执行多次,验证脚本稳定性是否良好。笔者自己连续运行过10次都能运行成功,说明脚本稳定行良好。另外上述测试场景中查找最新计算结果时采用的是first(),last()方法,还有其他定位element的方式可以达到相同的效果,这个小点就留给大家自行练习吧。

 

有关Cypress 定位、操作页面元素的更多相关文章

  1. ruby - 在哈希的键数组中追加元素 - 2

    查看我的Ruby代码:h=Hash.new([])h[0]=:word1h[1]=h[1]输出是:Hash={0=>:word1,1=>[:word2,:word3],2=>[:word2,:word3]}我希望有Hash={0=>:word1,1=>[:word2],2=>[:word3]}为什么要附加第二个哈希元素(数组)?如何将新数组元素附加到第三个哈希元素? 最佳答案 如果您提供单个值作为Hash.new的参数(例如Hash.new([]),完全相同的对象将用作每个缺失键的默认值。这就是您所拥有的,那是你不想要的。您可以改用

  2. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

  3. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

  4. ruby - Hanami link_to 助手只呈现最后一个元素 - 2

    我是HanamiWorld的新人。我已经写了这段代码:moduleWeb::Views::HomeclassIndexincludeWeb::ViewincludeHanami::Helpers::HtmlHelperdeftitlehtml.headerdoh1'Testsearchengine',id:'title'hrdiv(id:'test')dolink_to('Home',"/",class:'mnu_orizontal')link_to('About',"/",class:'mnu_orizontal')endendendendend我在模板上调用了title方法。htm

  5. ruby-on-rails - 如何处理 Grape 中特定操作的过滤器之前? - 2

    我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?

  6. ruby-on-rails - 在 Ruby on Rails 中发送响应之前如何等待多个异步操作完成? - 2

    在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.

  7. ruby - 在 ASP 页面上 Mechanize 中断 - 2

    require'mechanize'agent=Mechanize.newlogin=agent.get('http://www.schoolnet.ch/DE/HomeDE.htm')agent.clicklogin.link_withtext:/Login/然后我得到Mechanize::UnsupportedSchemeError。 最佳答案 Mechanize不支持javascript但您可以将搜索字段添加到表单并为其分配搜索词并使用mechanize提交表单form=page.forms.firstform.add_fie

  8. ruby - 将n维数组的每个元素乘以Ruby中的数字 - 2

    在Ruby中,是否有一种简单的方法可以将n维数组中的每个元素乘以一个数字?这样:[1,2,3,4,5].multiplied_by2==[2,4,6,8,10]和[[1,2,3],[1,2,3]].multiplied_by2==[[2,4,6],[2,4,6]]?(很明显,我编写了multiplied_by函数以区别于*,它似乎连接了数组的多个副本,不幸的是这不是我需要的)。谢谢! 最佳答案 它的长格式等价物是:[1,2,3,4,5].collect{|n|n*2}其实并没有那么复杂。你总是可以使你的multiply_by方法:c

  9. ruby - 在 Ruby 中是否有一种惯用的方法来操作 2 个数组? - 2

    a=[3,4,7,8,3]b=[5,3,6,8,3]假设数组长度相同,是否有办法使用each或其他一些惯用方法从两个数组的每个元素中获取结果?不使用计数器?例如获取每个元素的乘积:[15,12,42,64,9](0..a.count-1).eachdo|i|太丑了...ruby1.9.3 最佳答案 使用Array.zip怎么样?:>>a=[3,4,7,8,3]=>[3,4,7,8,3]>>b=[5,3,6,8,3]=>[5,3,6,8,3]>>c=[]=>[]>>a.zip(b)do|i,j|c[[3,5],[4,3],[7,6],

  10. ruby-on-rails - 如何让 Rails View 返回其关联的操作名称? - 2

    我有一个非常简单的Controller来管理我的Rails应用程序中的静态页面:classPagesController我怎样才能让View模板返回它自己的名字,这样我就可以做这样的事情:#pricing.html.erb#-->"Pricing"感谢您的帮助。 最佳答案 4.3RoutingParametersTheparamshashwillalwayscontainthe:controllerand:actionkeys,butyoushouldusethemethodscontroller_nameandaction_nam

随机推荐