提问人:Charles Anderson 提问时间:12/12/2017 最后编辑:Mads BruggerCharles Anderson 更新时间:7/16/2023 访问量:77863
如何使用 Cypress 检查可能不存在的元素
How to check for an element that may not exist using Cypress
问:
我正在编写一个赛普拉斯测试来登录一个网站。有 和 字段和一个按钮。大多数情况下,登录很简单,但有时首先会出现一个警告对话框,必须将其关闭。username
password
Submit
我试过这个:
cy.get('#login-username').type('username');
cy.get('#login-password').type(`password{enter}`);
// Check for a possible warning dialog and dismiss it
if (cy.get('.warning')) {
cy.get('#warn-dialog-submit').click();
}
这很好用,但如果警告未出现,测试将失败:
CypressError:重试超时:应找到元素:“.warning”,但从未找到它。
然后我尝试了这个,但失败了,因为警告出现得不够快,所以没有找到任何东西:Cypress.$
cy.get('#login-username').type('username');
cy.get('#login-password').type(`password{enter}`);
// Check for a possible warning dialog and dismiss it
if (Cypress.$('.warning').length > 0) {
cy.get('#warn-dialog-submit').click();
}
检查元素是否存在的正确方法是什么?我需要这样的东西,如果找不到元素,就不会抱怨。cy.get()
答:
35赞
Ran Adler
1/6/2020
#1
export function clickIfExist(element) {
cy.get('body').then((body) => {
if (body.find(element).length > 0) {
cy.get(element).click();
}
});
}
评论
6赞
dewey
2/25/2022
有没有办法设置查找元素的超时时间?
2赞
M. Justin
5/21/2022
@dewey 该方法是 JQuery 方法,而不是 Cypress 方法,因此它没有任何内置超时。这是一个关于使用 JQuery 或纯 Javascript 等待元素存在的问题:stackoverflow.com/questions/5525071/...。我想你可以做这样的事情:find
if (body.find(element).length == 0) {cy.wait(timeout);} if (body.find(element).length > 0) {cy.get(element).click();}
0赞
Patryk Janik
3/20/2020
#2
我已经用纯js完成了。
cy.get('body').then((jqBodyWrapper) => {
if (jqBodyWrapper[0].querySelector('.pager-last a')) {
cy.get('.pager-last a').then(jqWrapper => {
// hardcoded due to similarities found on page
const splitLink = jqWrapper[0].href.split("2C");
AMOUNT_OF_PAGES_TO_BE_RETRIEVED = Number(splitLink[splitLink.length - 1]) + 1;
})
} else {
AMOUNT_OF_PAGES_TO_BE_RETRIEVED = 1;
}
});
我正在尝试检查身体上是否存在元素
cy.get('body').then((jqBodyWrapper) => {
使用纯 js querySelector
if (jqBodyWrapper[0].querySelector('.pager-last a')) {
然后我解雇了我的cy.get
cy.get('.pager-last a').then(jqWrapper => {
1赞
ogulcan
5/23/2020
#3
or for CSS 选择器是 jQuery 中的一个内置方法,用于检查具有指定类名的元素是否存在。然后,您可以返回一个布尔值来执行断言控制。hasClass()
has()
Cypress.Commands.add('isExistElement', selector => {
cy.get('body').then(($el) => {
if ($el.has(selector)) {
return true
} else {
return false
}
})
});
然后,可以用TypeScript文件(index.d.ts)文件将其制作成特殊的cypress方法,并且可以采用可链接的形式。
declare namespace Cypress {
interface Chainable {
isExistElement(cssSelector: string): Cypress.Chainable<boolean>
}
}
如下例所示:
shouldSeeCreateTicketTab() {
cy.isExistElement(homePageSelector.createTicketTab).should("be.true");
}
评论
0赞
Anand
12/9/2022
如果找不到元素,这不会引发错误吗?
4赞
mykola kozub
10/26/2020
#4
export const getEl = name => cy.get(`[data-cy="${name}"]`)
export const checkIfElementPresent = (visibleEl, text) => {
cy.document().then((doc) => {
if(doc.querySelectorAll(`[data-cy=${visibleEl}]`).length){
getEl(visibleEl).should('have.text', text)
return ;
}
getEl(visibleEl).should('not.exist')})}
评论
3赞
Sitzfleisch
6/3/2023
Cypress.$()
执行与较少行相同的操作。doc.querySelectorAll()
40赞
Fody
6/1/2023
#5
使用元素轮询和检查,而不会使测试失败。
在最长等待时间内,对话框永远不会到达,或者此代码将其关闭。
cy.get('#login-username').type('username');
cy.get('#login-password').type(`password{enter}`);
const ifElementExists = (selector, attempt = 0) => {
if (attempt === 100) return null // no appearance, return null
if (Cypress.$(selector).length === 0) {
cy.wait(100, {log:false}) // wait in small chunks
getDialog(selector, ++attempt) // try again
}
return cy.get(selector, {log:false}) // done, exit with the element
}
ifElementExists('.warning').then($el => {
if ($el?.length) {
$el.find('#warn-dialog-submit').click()
}
})
-1赞
Lorraine R.
7/16/2023
#6
请注意,您可能需要等待足够的时间,直到元素添加到 DOM 中,并且应该异步执行此操作:
describe(`App content suite`, () => {
it('app logs in correctly', () => {
console.log('Checking if warning needs to be closed');
const enoughTimeUntilWarningIsAddedToDom = 5000;
cy.wait(enoughTimeUntilWarningIsAddedToDom);
(async () => {
const elementExists = await clickIfElementExists('.warning');
if (elementExists) {
console.log('element exists');
} else {
console.log('element does not exist');
}
})();
}
}
function clickIfElementExists(elementSelector: string) {
return new Promise(resolve => {
cy.get('body').then((body) => {
resolve(body.find(elementSelector).length > 0);
});
})
}
评论
1赞
Giacomo
7/16/2023
如果它没有出现怎么办 - 在这种情况下如何使用 Promise.reject()?
0赞
Lorraine R.
7/16/2023
问题是如何检测元素是否存在,而不会使测试失败,也没有例外。所以,你不应该拒绝。如果元素不存在,则使用值 false 进行解析,并且 false 将返回给 awaiter,您可以在其中检查clickIfElementExists
resolve(false)
if (!await clickIfElementExists('element'))
0赞
Lorraine R.
7/16/2023
我稍微澄清了这个例子@Giacomo
3赞
R.Winkles
7/18/2023
虽然这在技术上可能有效,但您可以摆脱函数、承诺、异步 iify 并仅使用cy.wait(5000).then(() => { const exists = Cypress.$(elementSelector)...
4赞
R.Winkles
7/18/2023
但不要这样做 - 赛普拉斯的发明是为了摆脱测试中的艰难等待时间。您将设置 5 秒,然后发现它偶尔会失败,因此您增加到 10 秒,然后您必须在下一次测试中执行相同的操作,不久之后您就会在套件运行时间中增加几分钟。
0赞
Satrio Ponco
11/24/2023
#7
据我们所知,柏树使用 promise 来处理测试。因此,如果没有特定元素,我们可以使用 promiseFail 返回。我在这里对@Fody答案进行了一些修改。
const ifElementExists = (selector, attempt = 0) => {
const promiseFail = new Promise((resolve) => {
resolve([])
})
if (attempt === 10) return promiseFail;
if (Cypress.$(selector).length === 0) {
cy.wait(100, { log: false });
return ifElementExists(selector, ++attempt);
}
return cy.get(selector, { log: false }); // done, exit with the element
};
ifElementExists(".todo-list").then($el => {
if ($el?.length) {
cy.get(".todo-list li").should("have.length", 2);
} else {
cy.log("NOT FOUND 404")
}
});
评论
0赞
Billy.Burr
11/25/2023
为什么要在不需要的时候添加承诺?
评论