Cypress 的学习笔记-阿里云开发者社区

开发者社区> -技术小能手-> 正文

Cypress 的学习笔记

简介: Cypress 的学习笔记

上述 cypress 代码,很像自然语言。

cypress 的 语法,cy.get(’.my-selector’),很像jQuery: cy.get(’.my-selector’)

事实上,cypress 本身就 bundle 了 jQuery:


支持类似 jQuery 的链式调用:




ct.get 并不会像 jQuery 那样,采用同步的方式返回待读取的元素。Cypress 的元素访问,采取异步方式完成。

因为 jQuery 的同步访问机制,我们在调用元素查询 API 之后,需要手动查询其结果是否为空:image.png而 Cypress 的异步操作,导致待读取的元素真正可用时,其结果才会被作为参数,传入回调函数:


也就是说,Cypress 内部帮我们封装了 retry 和 timeout 重试机制。image.png

如果想回归到 jQuery 那种同步读取元素的风格,使用 Cypress.$ 即可。

image.pngCypress 命令并不会直接返回其工作的目标,而是 yield 这些目标。Cypress 命令以异步的方式执行,命令被插入到队列里,并不会立即执行,而是等待调度。当命令真正执行时,目标对象经由前一个命令生成,然后传入下一个命令里。命令与命令之间,执行了很多有用的 Cypress 代码,以确保命令执行顺序和其在 Cypress 测试代码里调用的顺序一致。


Cypress 提供了一种叫做 aliasing 的机制,能将元素引用保存下来,以备将来之用。



使用 then 来对前一个命令 yield 的目标进行操作image.png

Cypress 的异步执行特性image.png

这是 Cypress 不同于其他前端自动测试框架的特别之处:直到测试函数退出,Cypress 才会触发浏览器的自动执行逻辑。



正确的做法,把 html 元素 evaluation 的代码放在 then 的callback里:


Each Cypress command (and chain of commands) returns immediately

每个 Cypress 命令(包含命令链)调用后立即返回,不会阻塞住以达到同步运行的效果。

Having only been appended to a queue of commands to be executed at a later time.

这些 command 只是被添加到一个命令队列里,等待 Cypress 框架稍后统一调度执行。

You purposefully cannot do anything useful with the return value from a command. Commands are enqueued and managed entirely behind the scenes.

对于 Cypress 直接返回的命令的执行结果,我们无法对其实行任何有效的操作,因为代码里命令的调用,实际上只是加入到待执行队列里。至于何时执行,由 Cypress 统一调度,对Cypress 测试开发人员来说是黑盒子。

We’ve designed our API this way because the DOM is a highly mutable object that constantly goes stale. For Cypress to prevent flake, and know when to proceed, we manage commands in a highly controlled deterministic way.

Cypress API 如此设计的原因是,DOM 是一种易变对象,随着用户操作或者交互,状态经常会 go stale. 为了避免出现 flake 情形,Cypress 遵循了上文描述的思路,以一种高度可控,确定性的方式来管理命令执行。

下面一个例子:网页显示随机数,当随机数跳到数字 7 时,让测试停下来。 如果随机数不是数字 7,重新加载页面,继续测试。

下列是错误的 Cypress 代码,会导致浏览器崩溃:


原因就是:在 while 循环里迅速将巨量的 get command 插入到任务队列(准确的说是 test chain)里,而根本没有机会得到执行。

The above test keeps adding more cy.get(’#result’) commands to the test chain without executing any!

上面的代码,起到的效果就是,在 while 循环里,不断地将 cy.get 命令,加入到 test chain里,但是任何一个命令,都不会有得到执行的机会!

The chain of commands keeps growing, but never executes - since the test function never finishes running.

命令队列里的元素个数持续增长,但是永远得不到执行的机会,因为 Cypress 代码本身一直在 while 循环里,没有执行完毕。

The while loop never allows Cypress to start executing even the very first cy.get(…) command.

即使是任务队列里第一个 cy.get 语句,因为 while 循环,也得不到执行的机会。



在 callback 里书写找到 7 之后 return 的逻辑。


command 执行过程中背后发生的事情

下列这段代码,包含了 5 部分逻辑:image.png

5 个 步骤的例子:

Visit a URL.

Find an element by its selector.

Perform a click action on that element.

Grab the URL.

Assert the URL to include a specific string.

上述 5 步骤 是 串行执行的,而不是并发执行。每个步骤背后,Cypress 框架都悄悄执行了一些“魔法”:

Visit a URL

魔法:Cypress wait for the page load event to fire after all external resources have loaded

该命令执行时,Cypress 等待页面所有外部资源加载,然后页面抛出 page load 事件。

Find an element by its selector

魔法:如果 find 命令没找到 DOM element,就执行重试机制,直到找到位置。

Perform a click action on that element

魔法:after we wait for the element to reach an actionable state

在 点击元素之前,先等待其成为可以点击状态。

每个 cy 命令都有特定的超时时间,记录在文档里:

Commands are promise

This is the big secret of Cypress: we’ve taken our favorite pattern for composing JavaScript code, Promises, and built them right into the fabric of Cypress. Above, when we say we’re enqueuing actions to be taken later, we could restate that as “adding Promises to a chain of Promises”.

Cypress 在 promise 编程模式的基础上,增添了 retry 机制。


image.png翻译成 promise 风格的 JavaScript 代码为:image.pngWithout retry-ability, assertions would randomly fail. This would lead to flaky, inconsistent results. This is also why we cannot use new JS features like async / await.

缺少重试机制,后果就是造成 flaky 和不一致的测试结果,这就是 Cypress 没有选择 async / await 的原因。

You can think of Cypress as “queueing” every command. Eventually they’ll get run and in the exact order they were used, 100% of the time.

Cypress 的命令执行顺序和其被插入 test chain 队列的顺序完全一致。

How do I create conditional control flow, using if/else? So that if an element does (or doesn’t) exist, I choose what to do?

有的开发人员可能会产生疑问,如何编写条件式控制流,比如在 IF / ELSE 分支里,执行不同的测试逻辑?

The problem with this question is that this type of conditional control flow ends up being non-deterministic. This means it’s impossible for a script (or robot), to follow it 100% consistently.

事实上,这种条件式的控制逻辑,会使测试流失去确定性(non-deterministic). 这意味着测试脚本挥着机器人,无法 100% 严格按照测试程序去执行。



After clicking on this , I expect its class to eventually be active.


This above test will pass even if the .active class is applied to the button asynchronously - or after a indeterminate period of time.

Cypress 会不断重试上述的 assertion,直至 .active class 被添加到 button 上,不管是通过异步添加,还是在一段未知长度的时间段后。

What makes Cypress unique from other testing tools is that commands automatically retry their assertions. In fact, they will look “downstream” at what you’re expressing and modify their behavior to make your assertions pass.

You should think of assertions as guards.

Use your guards to describe what your application should look like, and Cypress will automatically block, wait, and retry until it reaches that state.

Cypress 命令默认的 assertion 机制

With Cypress, you don’t have to assert to have a useful test. Even without assertions, a few lines of Cypress can ensure thousands of lines of code are working properly across the client and server!

This is because many commands have a built in Default Assertion which offer you a high level of guarantee.

很多 cy 命令都有默认的 assertion 机制。

cy.visit() expects the page to send text/html content with a 200 status code. 确保 页面发出 text/html 内容后,收到200 的状态码。

cy.request() expects the remote server to exist and provide a response.


cy.contains() expects the element with content to eventually exist in the DOM.

确保制订的 content 最终在 DOM 中存在。

cy.get() expects the element to eventually exist in the DOM.

确保请求的 element 最终在 DOM 中存在。

.find() also expects the element to eventually exist in the DOM. - 同 cy.get

.type() expects the element to eventually be in a typeable state.


.click() expects the element to eventually be in an actionable state.


.its() expects to eventually find a property on the current subject.

确保当前对象上能够找到对应的 property

All DOM based commands automatically wait for their elements to exist in the DOM.

所有基于 DOM 的命令,都会自动阻塞,直至其元素存在于 DOM 树为止。

image.png在执行 click 命令之前,button 必须成为可点击状态,否则 click 命令不会得到执行。可点击状态(actionable),意思是 button 不能是 disabled,covered,或者 hidden 状态。

Cypress 命令自带的超时设置image.pngQueries for the element .mobile-nav, 然后停顿 4 秒,直至元素出现在 DOM 里。

再停顿 4 秒,等待元素出现在页面上。

再等待 4 秒,等待元素包含 home 的 text 属性。

一段测试程序里的所有 Cypress 命令,共享同一个超时值。


DevExpress学习02——DevExpress 14.1的汉化
汉化资源: 汉化补丁:dxKB_A421_DXperience_v14.1_(2014-06-09): 汉化工具:DXperienceUniversal-14.
1215 0
今天使用了DevExpress的labelControl,发现拖放上去,其背景色和主窗体的背景一样,非常不谐调,把BackColor设置为透明也不行(Windows中的Label可以)。 没有办法,我用颜色拾取器,拾取到上方面板颜色是RGB(80,80,80),于是将labelControl背景色改为RGB(80,80,80)颜色就统一了。
975 0
记得刚接触编程时,虽然实现了功能,但用户界面十分丑陋,老师叫我们美化一下界面,不要千篇一律,当时觉得能够写出来功能就洋洋得意了,不觉得界面丑陋。后来,在程序比赛中,我接触了一种第三方控件,它可以快速实现控件、皮肤的美化,它就是以前常用的DotNetBar,其入门使用方法见: DotNetBar下载地址: 早就听说了DevExpress比较强大了,今天终于来尝试一把。
1420 0
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
10883 0
MapReduce主要包括两个阶段:一个是Map,一个是Reduce. 每一步都有key-value对作为输入和输出。   Map阶段的key-value对的格式是由输入的格式决定的,如果是默认的TextInputFormat,则每行作为一个记录进程处理,其中key为此行的开头相对文件的起始位置,value就是此行的字符文本。
707 0
+ 订阅