С чем я работаю:
<ul class = "abc">
<li class = "xyz">
<a href = "www.something.com">
<div>
<h2>
<div>
<div class = "theText">
<div>Get this text</DIV>
</div>
</div>
</h2>
</div>
</a>
<button aria-label = "remove">...</button>
</li>
<li class = "xyz">...Same stuff here as above li...</li>
<li class = "xyz">...Same stuff here as above li...</li>
<li class = "xyz">...Same stuff here as above li...</li>
</ul>
button здесь имеет два состояния для атрибута aria-label: удаление (когда кнопка нажата) и добавление (когда кнопка еще не нажата).
Чего я хочу добиться:
Я хочу получить значение внутри тега <a>, в данном случае это «Получить этот текст», НО только если для кнопки в том же теге <li> установлено значение aria-label = "remove". Я также буду хранить значения, которые я получаю в массиве, чтобы позже сравнить их с другим массивом.
Что я пробовал:
let myArray: any = []
cy.get('li[class = "xyz"]').each(($element) => {
cy.get('li[class = "xyz"]').within(($element) => {
cy.wrap($element)
.find('button[aria-label = "remove"]')
.find('div[class = "theText"]')
.invoke('text').then(text => {
myArray.push(text)
})
})
}).then(() => {
cy.wrap(myArray).as('myArray')
})
С приведенным выше кодом я получаю эту Assertion Error от Cypress.
@ManosKoonelakis - Все остальные теги <li> имеют одинаковые class = "xyz". Позвольте мне обновить пост, спасибо за это.
Вы можете удалить строку cy.get('li[class = "xyz"]').within(), так как вы оборачиваете $element и используете .find() - внутри, и вы найдете то же самое.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы можете использовать has в своем селекторе
let myArray: any = []
cy.get('li[class = "xyz"]:has(button[aria-label = "remove"])').each(($element) => {
cy.get('li[class = "xyz"]:has(button[aria-label = "remove"])').within(($element) => {
cy.wrap($element)
.find('div[class = "theText"]')
.invoke('text').then(text => {
myArray.push(text)
})
})
}).then(() => {
cy.wrap(myArray).as('myArray')
})
Или вы можете использовать parentUntil, чтобы вернуться к родительскому элементу после нахождения связанного элемента с помощью aria-label = "remove"
let myArray: any = []
cy.get('li[class = "xyz"]').each(($element) => {
cy.get('li[class = "xyz"]').within(($element) => {
cy.wrap($element)
.find('button[aria-label = "remove"]')
.parentsUntil('li[class = "xyz"]')
.find('div[class = "theText"]')
.invoke('text').then(text => {
myArray.push(text)
})
})
}).then(() => {
cy.wrap(myArray).as('myArray')
})
Я пробовал has - Это работает, но проходит через все элементы <button>, даже если у него нет [aria-label = "remove"], вот скриншот . Это увеличивает продолжительность теста. Есть ли у вас какие-либо советы? | Что касается попытки parentsUntil - не повезло с этим и получить эту ошибку утверждения. Он обнаруживает кнопку, но не выполняет команду .parentUntil.
Я также изменил свой ответ на has в первом cy.get. Я думаю, это поможет вам проверять элементы только с определенными условиями. @krisc
let myArray = []
const buttonCheck = document.querySelector("button").getAttribute("aria-label");
if (buttonCheck === "remove"){
const aTagInnerText = document.querySelector("a").innerText;
myArray.push(aTagInnerText.trim(" "));
}
console.info(myArray)<!DOCTYPE html>
<html>
<head>
<meta charset = "utf-8">
<meta name = "viewport" content = "width=device-width">
</head>
<body>
<ul class = "abc">
<li class = "xyz">
<a href = "www.something.com">
<div>
<h2>
<div>
<div class = "theText">
<div>Get this text</DIV>
</div>
</div>
</h2>
</div>
</a>
<button aria-label = "remove">...</button>
</li>
<li>...Same stuff here as above li...</li>
<li>...Same stuff here as above li...</li>
<li>...Same stuff here as above li...</li>
</ul>
</body>
</html>Ваш ответ может быть улучшен с помощью дополнительной вспомогательной информации. Пожалуйста, отредактируйте , чтобы добавить дополнительные сведения, такие как цитаты или документация, чтобы другие могли подтвердить правильность вашего ответа. Вы можете найти больше информации о том, как писать хорошие ответы в справочном центре.
Используйте пакет cypress-if
let myArray: any = []
cy.get('li[class = "xyz"]').each(($element) => {
cy.wrap($element).within(() => {
cy.get('button[aria-label = "remove"]')
.if () // any chained commands will only run
// if [aria-label = "remove"] exists
// but the test does not fail
// if [aria-label = "remove"] does not exist
.parent() // move up to parent to avoid your error msg
.find('div[class = "theText"] div')
.invoke('text').then(text => {
myArray.push(text)
})
})
}).then(() => {
cy.wrap(myArray).as('myArray')
})
cy.get('@myArray')
.should('deep.eq', ['Get this text']) // passes
Пример HTML для тестирования
<ul class = "abc">
<li class = "xyz">
<a href = "www.something.com">
<div>
<h2>
<div>
<div class = "theText">
<div>Get this text</DIV>
</div>
</div>
</h2>
</div>
</a>
<button aria-label = "remove">...</button>
</li>
<li class = "xyz">
<a href = "www.somethingelse.com">
<div>
<h2>
<div>
<div class = "theText">
<div>Not this text</DIV>
</div>
</div>
</h2>
</div>
</a>
<button aria-label = "add">...</button>
</li>
</ul>
Результат: ['Получить этот текст']
Обратите внимание, что я добавил и дополнительный div здесь .find('div[class = "theText"] div'), чтобы избежать пробелов вокруг текста, но это не меняет условную проверку.
Я попробовал это, и тест все равно прошел через все элементы <button>, у которых не было [aria-label = "remove"]. Я также запустил это, не нажимая кнопки, чтобы [aria-label = "remove"] не существовало. В любом случае тест все равно прошел через все элементы <button>. Любые советы по этому поводу?
У вас где-то ошибка, у меня работает - добавлю образец, на котором тестировал.
Это «старый» способ выполнения условной проверки, но команда .if () лучше, потому что она имеет встроенный повтор при загрузке асинхронных данных.
let myArray: any = []
cy.get('li[class = "xyz"]').each(($element) => {
// Use jquery to check the button has remove attribute
const removeButton = $element.find('button[aria-label = "remove"]')
if (removeButton.length) {
cy.wrap($element).find('div[class = "theText"]')
.invoke('text').then(text => {
myArray.push(text)
})
}
}).then(() => {
cy.wrap(myArray).as('myArray')
})
Если вы хотите использовать псевдоселектор :has(), вы должны сделать это снаружи цикла .each().
Но будьте осторожны, псевдо-селектор :has() не работает, если уже не нажато ни одной кнопки.
let myArray: any = []
cy.get('li[class = "xyz"]:has(button[aria-label = "remove"])') // implied filter
.each($li => {
// only element with remove attribute inside here
cy.wrap($li)
.find('div[class = "theText"]')
.invoke('text')
.then(text => {
myArray.push(text)
})
})
}).then(() => {
cy.wrap(myArray).as('myArray')
})
Кипарис не использовал. Однако, если я понимаю, почему бы вам сначала не сделать cy.get('li.xyz')? Также вы запрашиваете все определенные элементы li и для каждого из них пытаетесь найти другой элемент
.xyz? однако на основе предоставленной разметки других .xyz не существует