then
允许您处理从上一个命令中产生的结果对象。
info
注意: .then()
假设您已经熟悉核心概念,例如闭包。
info
注意: 对于断言,优先使用带回调的 .should()
而不是 .then()
,因为它们会自动重试直到不再抛出断言,但请注意差异。
语法
.then(callbackFn)
.then(options, callbackFn)
用法
正确用法
cy.get('.nav').then(($nav) => {}) // 将 .nav 作为第一个参数传递
cy.location().then((loc) => {}) // 将位置对象作为第一个参数传递
参数
options (Object)
传入一个选项对象以更改 .then()
的默认行为。
选项 | 默认值 | 描述 |
---|---|---|
timeout | defaultCommandTimeout | 在超时前等待 .then() 解析的时间 |
callbackFn (Function)
传入一个函数,该函数将上一个命令产生的结果作为其第一个参数。
生成结果
回调函数返回的任何内容都将成为新的结果对象,并流入下一个命令(undefined
或 null
除外)。
- 如果返回值是一系列 Cypress 命令(例如
return cy.get('button')
),Cypress 将等待它们解析并使用它们的返回值作为新的结果对象。 - 如果返回值是一个 Promise,Cypress 将等待它解析,并使用解析后的值作为新的结果对象以继续命令链。
- 如果回调返回
undefined
或null
(或没有返回值),则回调函数中最后一个 Cypress 命令的结果将作为新的结果对象流入下一个命令。 - 如果回调返回
undefined
或null
(或没有返回值)且回调未调用任何 Cypress 命令,则结果对象不会被修改,上一个结果对象将传递到下一个命令。
.then()
的回调函数不会重试。直接从回调返回 DOM 元素然后对它们使用进一步的命令是不安全的。相反,应使用 Cypress 查询来定位您感兴趣的元素以进行操作或断言。
示例
info
我们在核心概念指南中有更多示例,详细介绍了使用 .then()
存储、比较和调试值的各种方法。
DOM 元素
button
元素作为结果对象传递
cy.get('button').then(($btn) => {
const cls = $btn.attr('class')
cy.wrap($btn).click().should('not.have.class', cls)
})
从上一个命令传递数字作为结果对象
cy.wrap(1)
.then((num) => {
cy.wrap(num).should('equal', 1) // true
})
.should('equal', 1) // true
更改结果对象
使用另一个命令更改 el 结果对象
cy.get('button')
.then(($btn) => {
const cls = $btn.attr('class')
cy.wrap($btn).click().should('not.have.class', cls).find('i')
// 由于没有显式返回
// 最后一个 Cypress 命令的结果将作为 结果对象传递
})
.should('have.class', 'spin') // 对 i 元素进行断言
使用另一个命令更改数字结果对象
cy.wrap(1).then((num) => {
cy.wrap(num)).should('equal', 1) // true
cy.wrap(2)
}).should('equal', 2) // true
通过返回更改数字结果对象
cy.wrap(1)
.then((num) => {
cy.wrap(num)
.should('equal', 1) // true
.then(() => {
return 2
})
})
.should('equal', 2) // true
返回 undefined
不会修改传递的结果对象
cy.get('form')
.then(($form) => {
console.log('form is:', $form)
// 此处返回 undefined,但 $form 将
// 作为结果对象传递以允许继续链式调用
})
.find('input')
.then(($input) => {
// 由于我们的 form 元素作为结果对象传递
// 并对其调用了 .find('input'),因此可以在此处获取 $input 元素
})
原始 HTMLElements 会被 jQuery 包装
cy.get('div')
.then(($div) => {
return $div[0] // 类型 => HTMLDivElement
})
.then(($div) => {
$div // 类型 => JQuery<HTMLDivElement>
})
Promises
Cypress 会等待 Promises 解析后再继续执行
使用 Q 的示例
cy.get('button')
.click()
.then(($button) => {
const p = Q.defer()
setTimeout(() => {
p.resolve()
}, 1000)
return p.promise
})
使用 bluebird 的示例
cy.get('button')
.click()
.then(($button) => {
return Promise.delay(1000)
})
使用 jQuery deferred 的示例
cy.get('button')
.click()
.then(($button) => {
const df = $.Deferred()
setTimeout(() => {
df.resolve()
}, 1000)
return df
})
注意事项
差异
.then()
与 .should()
/.and()
有什么区别?
使用 .then()
允许你在回调函数中使用生成的主题(yielded subject),当你需要操作某些值或执行某些操作时应该使用它。
另一方面,当在 .should()
或 .and()
中使用回调函数时,会有特殊的逻辑来重新运行回调函数,直到其中没有断言抛出为止。你应当注意 .should()
或 .and()
回调函数中的副作用,避免你不希望被多次执行的操作。
规则
要求
.then()
需要链接到上一个命令。
断言
.then()
只会运行一次您链接的断言,不会重试。
超时设置
.then()
可能会因等待您返回的 Promise 解析而超时。
命令日志
.then()
不会在命令日志中记录
历史
版本 | 变更 |
---|---|
0.14.0 | 添加了 timeout 选项 |
< 0.3.3 | 添加了 .then() 命令 |