墓园网站建设价格,做网站的集群方案,免费淘宝客网站模板,公司网站设计制作公司#x1f60f;作者简介#xff1a;博主是一位测试管理者#xff0c;同时也是一名对外企业兼职讲师。 #x1f4e1;主页地址#xff1a;【Austin_zhai】 #x1f646;目的与景愿#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能#xff0c;分享行业相关最新信息。… 作者简介博主是一位测试管理者同时也是一名对外企业兼职讲师。 主页地址【Austin_zhai】 目的与景愿旨在于能帮助更多的测试行业人员提升软硬技能分享行业相关最新信息。 声明博主日常工作较为繁忙文章会不定期更新各类行业或职场问题欢迎大家私信有空必回。 阅读目录 1. 接上回2. 自定义命令2.1 参数传递2.2 链式调用2.3 自定义断言2.4 处理异步操作2.5 Cypress对象 3. 注意点3.1 关于脚本业务上下文3.2 抽象的程度 1. 接上回 上一篇我们介绍了一些Cypress中的一些高频使用技巧那么今天就由博主我继续来为大家带来关于Cypress的一些高阶技巧。 2. 自定义命令 在Cypress中自定义命令是一个强大的辅助功能说直白点就是它允许你将重复使用的代码片段抽象成可重用的命令。而通过这些自定义的命令我们可以让我们的自动化测试脚本更加的趋于模块化可想而知的是模块化的脚本其自身的可维护性、复用性和可阅读性就会更上一个台阶。 要使用自定义命令我们就需要在support/commands.js中建立自己的命令。比如我们需要将登录这个业务动作进行抽象那就先编写一段登录的相关业务代码。
我们写一个十分简单的登录操作语法如下可以看到整个的业务代码十分的简单只需要将用户名和密码进行传参即可。
Cypress.Commands.add(login, (username, password) {cy.visit(/login);cy.get(#username).type(username);cy.get(#password).type(password);cy.get(button[typesubmit]).click();
});那么我们在commands.js中将这段业务代码添加完成后在实际的测试脚本中就可以直接对其进行使用。 使用起来是不是很方便因为其本身就是将业务方法继续抽象所以直接调用其方法名就可以达到登录代码同样的效果。
describe(login_test, () {it(should log in successfully, () {cy.login(your_username, your_password);});
});2.1 参数传递 我们在定义业务方法的时候传参不仅仅可以传一些基础的业务参数还可以在此基础上根据自己的业务场景来定义一些比较灵活的参数类别。比如我们在对特定元素进行业务操作时我们可以统一的定义一个操作类或方法来对此进行特定的传参类似于selenium中find_elelment方法。 我们先在commands.js中定义这里我们要传递的参数是一个元素选择器。这样我们就可以灵活的在页面上选择到任何一个能捕捉到的元素。
Cypress.Commands.add(clickAndVerify, { prevSubject: element }, (element, text) {cy.wrap(element).click();cy.contains(text);
});使用的时候只需要直接调用即可。
cy.get(.my-button).clickAndVerify(Clicked Button Text);2.2 链式调用 自定义命令毫无意外的也支持了链式写法无疑这让我们在设计脚本的过程中可以更加灵活的应对各类复杂业务场景。 同样的现在commands.js中定义这里我们在返回get的时候进行了链式调用。
Cypress.Commands.add(login, (username, password) {cy.visit(/login);cy.get(#username).type(username);cy.get(#password).type(password);cy.get(button[typesubmit]).click();return cy.get(.user-dashboard);
});使用的时候只需要直接调用即可。
cy.login(your_username, your_password).should(be.visible);2.3 自定义断言 同样的既然可以进行抽象我们也完全可以将断言的操作加进自定义命令以验证特定的状态或条件包括一些特殊的验证逻辑。 commands.js中定义断言元素存在切包含text。
Cypress.Commands.add(shouldBeVisibleAndContain, { prevSubject: element }, (element, text) {cy.wrap(element).should(be.visible).and(contain, text);
});直接调用方法即可对元素进行断言。
cy.get(.my-element).shouldBeVisibleAndContain(Expected Text);2.4 处理异步操作 对于上一篇末尾处说到的异步操作处理同样可以在自定义命令中进行抽象其实在被测对象中异步操作是很常见的比如等待某个条件成立后再继续执行后续的操作类似的这种场景我们都可以在自定义命令中继续抽象和服用以优化脚本的整体运行效率和维护性。 在commands.js中定义等待特定的条件后再执行后续的操作。
Cypress.Commands.add(waitForApiResponse, () {cy.intercept(GET, /api/data).as(apiCall);cy.wait(apiCall);
});调用不再赘述。
cy.waitForApiResponse();2.5 Cypress对象 除了以上说的这些方法外我们还可以将一些元素和值包装成Cypress对象这样做的作用就是让这些抽象后的对象可以在自定义命令中使用更多的Cypress自带命令。 在commands.js中定义我们使用cy.wrap()将对象包装成Cypress对象使用自带的日志命令。
Cypress.Commands.add(logAndDebug, (subject) {cy.wrap(subject).debug().log(Subject:, subject);
});调用不再赘述。
cy.get(.my-element).logAndDebug();3. 注意点 我们在使用自定义命令的同时也需要注意一些特殊的情况与场景。 3.1 关于脚本业务上下文 在自定义命令中当然也存在着上下文的关系我们要确保了解Cypress中命令的上下文其中this与prevSubject 是特别觉有代表性的关键字。它们其实是允许你在自定义命令中引用和操作前一个命令的主体就this这个来说它在自定义命令中用于引用当前命令的上下文对于一般的命令它指向cy对象对于一些带有{ prevSubject: element }选项的命令this则会指向前一个命令的主体这个是需要大家注意的。 下面我们来举两个例子 首先我们来看普通命令中的this这里的this就是指向cy对象的。
Cypress.Commands.add(customCommand, function () {cy.log(this);
});调用
cy.customCommand();而对面带有{ prevSubject: element }的方法时这里的this就像我之前说的那样指向的是前一个命令的主体。简单点来说this指向前一个命令的subject而cy.log(subject)里的就是前一个命令的主体。
Cypress.Commands.add(customCommandWithSubject, { prevSubject: element }, function (subject) {cy.log(this); cy.log(subject);
});调用
cy.get(.my-element).customCommandWithSubject();prevSubject 的用作为告诉cypress你的自定义命令期望前一个命令的主体作为传参一般在多个自定义命令中共享同一个元素的场景中会频繁使用到。 同理这里我们对前一个命令的主体进行点击操作所以使用prevSubject 来达到我们所想要的效果。
Cypress.Commands.add(customCommandWithSubject, { prevSubject: element }, function (subject) {cy.wrap(subject).click();
});调用
cy.get(.my-element).customCommandWithSubject();3.2 抽象的程度 虽然在自定义命令中我们需要对要定义的方法进行抽象但往往会有些同学在设计的过程中什么都想要从而导致自己的自定义命令变得过度抽象这些代码的可读性一般都比较差而且维护起来难度较大无法适应被测对象界面中的需求更改与样式变更。 这里我们就举一个过度抽象的例子让大家了解适度和过度抽象的区别。 我们先来看一下过度抽象的自定义命令这里虽然方法中提供了一个登录的基本步骤但它的步骤过于具体这样会导致在测试用例中要添加其他的测试逻辑变得困难本身自定义命令的本质就是用来大量复用的这样就变得本末倒置了。所以这样的抽象程度限制了自定义命令的灵活性使得它本身的价值变得可有可无。
Cypress.Commands.add(login, (username, password) {cy.visit(/login);cy.get(#username).type(username);cy.get(#password).type(password);cy.get(button[typesubmit]).click();cy.get(.user-dashboard).should(be.visible);
});调用
describe(Login Test, () {it(should log in successfully, () {cy.login(testuser, password123);});
});那么接下来我们看一下什么是适度抽象的自定义命令下面这段乍一看似乎与上面的没什么很大的区别其实则不然。在这其中我们只保留的基本的登录操作不进行过多的细化操作说人话就是我们只把共通与大框架的部分保留了下来一些根据业务不同而扩展或特定的操作则被丢弃掉了。这样我们就可以在测试用例中添加更多的具体步骤来适应各类业务测试场景的需求。
Cypress.Commands.add(basicLogin, (username, password) {cy.visit(/login);cy.get(#username).type(username);cy.get(#password).type(password);cy.get(button[typesubmit]).click();
});调用
describe(Login Test, () {it(should log in successfully, () {cy.basicLogin(testuser, password123);cy.get(.user-dashboard).should(be.visible);});
});