Как получить значение элемента, только если виден другой конкретный элемент?

С чем я работаю:

<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.

Кипарис не использовал. Однако, если я понимаю, почему бы вам сначала не сделать cy.get('li.xyz')? Также вы запрашиваете все определенные элементы li и для каждого из них пытаетесь найти другой элемент .xyz? однако на основе предоставленной разметки других .xyz не существует

Manos Kounelakis 14.10.2022 06:15

@ManosKoonelakis - Все остальные теги <li> имеют одинаковые class = "xyz". Позвольте мне обновить пост, спасибо за это.

krisc 14.10.2022 08:53

Вы можете удалить строку cy.get('li[class = "xyz"]').within(), так как вы оборачиваете $element и используете .find() - внутри, и вы найдете то же самое.

Roberta D 14.10.2022 09:57
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
125
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Вы можете использовать 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.

krisc 15.10.2022 06:54

Я также изменил свой ответ на has в первом cy.get. Я думаю, это поможет вам проверять элементы только с определенными условиями. @krisc

Nick Vu 15.10.2022 08:33

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>. Любые советы по этому поводу?

krisc 14.10.2022 14:21

У вас где-то ошибка, у меня работает - добавлю образец, на котором тестировал.

TesterDick 14.10.2022 21:48

Это «старый» способ выполнения условной проверки, но команда .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')
})

Другие вопросы по теме