Передовой опыт E2E-тестирования по использованию атрибутов данных

Мы используем Cypress для тестирования E2E и собираемся приступить к задаче перехода от селекторов тегов и имен классов к атрибутам данных, чтобы сделать селекторы менее хрупкими.

Мой вопрос касается использования атрибутов данных. Кипарис рекомендует использовать data-cy или data-test или data-testid.

Некоторые из самых сложных селекторов включают выбор строки и столбца из таблицы. Пример:

<!-- example of hard-to-test markup -->
<table class='users-table'>
<thead>
  <th>Name</th>
  <th>Email</th>
  <th>Phone</th>
<thead>
<tbody>
  <tr>
    <td>Bob Fish</td>
    <td>[email protected]</td>
    <td>123-123-1234</td>
  </tr>
    <td>Shaggy Rogers</td>
    <td>[email protected]</td>
    <td>509-123-1235</td>
  </tr>
<tbody>
</table>

Теперь, если мы будем использовать data-test, как рекомендовано, я бы сделал что-то вроде этого:

<table data-test='users-table'>
  ...
<tbody>
  <tr data-test='user-id-1'>
    <td data-test='name-col'>...
    <td data-test='email-col'>...
    <td data-test='phone-col'>...

Теперь я могу найти td с определенным значением, например

  cy.contains('[data-test = "users-table"] [data-test = "name-col"]', user.name).should('be.visible')

или лучше:

  cy.get(`[data-test = "users-table"] [data-test = "user-id-${user.id}"]`).within(() => {
    cy.get('[data-test = "name-col"]').should('have.text', user.name)
    cy.get('[data-test = "email-col"]').should('have.text', user.email)
    cy.get('[data-test = "phone-col"]').should('have.text', user.phone)
  })

Но в духе «семантической разметки» мне хочется сделать что-то вроде этого:

<table data-entity='users'>
  ...
<tbody>
  <tr data-entity-id='1'>
    <td data-col='name'>...
    <td data-col='email'>...
    <td data-col='phone'>...
  </tr>
  <tr data-entity-id='2'> ...

Это позволило бы мне не смешивать значения атрибутов data-test = "[noun]-[value]", таких как user-id-1, за счет необходимости придумывать собственный последовательный набор атрибутов data- (data-entity, data-col и т. д.).

Так каков же правильный, объективный и совсем не основанный на мнениях способ использования атрибутов данных? Потому что мы знаем, что разработка программного обеспечения никогда не требует компромиссов и есть только один правильный ответ.

Кроме того, я также начал читать Cypress Testing Library, которая, кажется, может в некоторой степени помочь, извлекая некоторые элементы семантически значимым способом (например, роль или метку), но все равно там будет масса разметки, которая будет не будет покрыто, если, возможно, я не начну ставить role= на все, что кажется грязным хаком и, вероятно, противоречит ARIA или какому-то другому стандарту w3c.

Похоже, вы опечатали строки таблицы <tr> как <td>.

Maurice 28.03.2024 12:37

Технически нет ничего плохого в том, как вы это сделали, но это вопрос предпочтений — я бы склонялся к меньшему использованию атрибутов, поскольку команды Cypress довольно хорошо справляются с перемещением по DOM (find, next, eq). По моему мнению, у вас есть излишество, просто пометьте саму таблицу и найдите строку на основе содержимого. (Извините, если это слишком очевидно).

Poodle 02.04.2024 22:09

Если вы просто спрашиваете, следует ли мне использовать data-test = "name-col" или data-test = "name", я не уверен, что есть какая-то практическая разница.

Poodle 02.04.2024 22:10

не то, должно ли это быть name или name-col, а, скорее, следует ли предпочитать всегда использовать data-test или многочисленные атрибуты данных с большей семантикой, такие как <table data-entity = "users" и <tr data-entity-id='1', для идентификации строки. Возможно, идентификатор никогда не появляется в видимом для пользователя виде td

thom_nic 04.04.2024 03:34
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
1
4
411
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Обратите внимание, что это основано на моем опыте управления огромными наборами тестов на предприятии и нескольких раз, когда я шел по неверному пути именно по этой проблеме. Здесь есть много компромиссов и нет единственного «правильного пути».

Атрибуты данных

Во-первых, правильно отделить селекторы от внутренних атрибутов DOM, которые являются деталями реализации, такими как атрибут класса и т. д.

Атрибуты данных могут стать частью решения этой проблемы. Однако вы должны знать о недостатках, прежде чем совершать их в одностороннем порядке. Они хороши тем, что вы можете отделить тестовый код от деталей реализации уровня приложения (class) и т. д.

Раньше я видел и использовал такие соглашения, как использование data-cy-component, который представляет тип «компонента», который представляет этот элемент DOM, в сочетании с атрибутами «специфического компонента», связанными с этим компонентом. Например:

<tbody>
  <tr data-cy-component = "row" data-cy-row-id = "1">
    <td data-cy-component = "cell" data-cy-cell-column = "name">...
    <td data-cy-component = "cell" data-cy-cell-column = "email">...
    <td data-cy-component = "cell" data-cy-cell-column = "phone">...

Это:

  • С пуристской точки зрения чище, чем составные значения.
  • Более расширяемый, вы можете добавить больше тестовых атрибутов, если вам нужно выбрать что-то по-новому, не нарушая при этом все селекторы.
  • Устраняет двусмысленность (что, если в названии столбца есть -?).

Однако, с отрицательной стороны:

  • По сути, вы возлагаете повышенную нагрузку на разработчиков приложений, получающих правильные комбинации. Что, если они забудут добавить один из атрибутов? Это более сложно, и существует больше способов ошибиться, поскольку эвристику того, что относится к тому, что вы определяете, зависит от вас, и каждый должен ее придерживаться. Это не так просто, как кажется.
  • Он предлагает людям не только выбирать эти атрибуты, но также читать их и утверждать на их основе. Например. используйте значение. Это вообще плохо. Пользователь не читает это значение. В конце концов, вы пытаетесь доказать то, что действительно может видеть пользователь.
  • Вы по-прежнему принципиально добавляете новый «уровень» деталей реализации, хотя и поддерживаемый отдельно и более стабильный. Пользователь не знает атрибутов данных и не заботится об них. Происходит перекос. Например, вы можете успешно захватить нужный столбец, но отображается ли на экране заголовок столбца с правильным именем?

Доступные селекторы

cypress-testing-library — это пример библиотеки, которая поощряет использование селекторов, основанных на данных DOM, которые существуют по соображениям доступности (которые считаются «общедоступными» или видимыми. Его рекомендации, которым отдать предпочтение весьма красноречивы в отношении концептуального мышления.

Это означает использование видимого текста или ролей aria и их атрибутов для решения проблемы. Это дает огромные преимущества:

  • Обычно вы тестируете то, что считается общедоступным интерфейсом, и часто используете реальный видимый текст. Вместо случайного тестирования атрибутов данных, которые могут отражать, а могут и не отражать реальность. Это позволяет избежать ложного чувства безопасности.
  • Если вам сложно выбрать что-то доступными методами, это обычно означает, что ваша страница недоступна. Итак, вы делаете это так, и это хорошо для всех.
  • Вы не запутаетесь в управлении соглашениями об атрибутах данных, поскольку атрибуты aria четко определены и являются частью общедоступных стандартов.
  • Если селекторы часто ломаются, это означает, что у вас есть проблема с доступом, которую нужно исправить, и это полезно знать!
  • Если вы не можете устранить неоднозначность с помощью доступных селекторов, скажем, если у двух пользователей одинаковое имя, то как пользователь их вообще различает? Это может привести к правильному мышлению о том, как думает пользователь. Вероятно, электронная почта уникальна, поэтому выбирать следует из нее. Это также, что очень важно, заметно.
  • Многие библиотеки и системы дизайна уже реализуют атрибуты aria. Например Чакра. А такие вещи, как Zag, могут помочь вам создавать свои собственные вещи доступным способом.

Обратите внимание, что он не запрещает использование тестовых атрибутов, но также ограничивает вас использованием отдельного атрибута data-testid, исключая описанное выше решение составного атрибута (по крайней мере, без добавления собственных аварийных люков). Но обычно вы обнаруживаете, что вам это все равно не нужно в сочетании с существующими доступными селекторами.

В вашем примере вы сначала должны использовать правильную разметку aria, например:

<table aria-label = "Users table">
<thead>
   <tr>
     <th id = "name-column">Name</th>
     <th id = "email-column">Email</th>
     <th id = "phone-column">Phone</th>
   </tr>
</thead>
<tbody>
  <tr>
    <td aria-describedby = "name-column">...
    <td aria-describedby = "email-column">...
    <td aria-describedby = "phone-column">...
  </tr>
  <tr> ...

Затем для выполнения различных задач:

cy.findByRole('table', {name: "Users table"}).within(() => {

   // Getting a row by its unique id that is visible (email)
   cy.findByRole('cell', {description: 'Email', name: '[email protected]'})
      .should('exist)
      .parent()
      .within(() => {
         cy.findByRole('cell', {description: 'Name'}) // Getting the name cell for that same row
           .should('have.text', 'Shaggy Rogers') 
       })
})

Также стоит отметить, что таблицы представляют собой особенно более сложный случай. С cypress-testing-library найти и нажать кнопку проще простого. При работе с таблицами (но в любом случае это справедливо для подхода с атрибутами данных) вам, вероятно, захочется зарегистрировать некоторые общие команды.

Теперь, чтобы решить вашу проблему:

но все равно остались бы тонны разметки, которая не была бы покрыта, если бы, возможно, я не начал использовать role= во всем, что кажется грязным хаком и, вероятно, противоречит ARIA или какому-то другому стандарту w3c.

Не ставьте role на что-либо, если это не то, о чем вы говорите. Если да, то вам следует это сделать. Обратите внимание, что вам также не нужно устанавливать role для вещей, которые уже имеют правильный role, поскольку элементы HTML уже имеют разные роли по умолчанию.

С атрибутами арии вы можете зайти невероятно далеко. Если вы чувствуете, что вам нужно больше, это часто происходит потому, что вы пытаетесь сделать что-то, что является плохой практикой, т. е. выбираете что-то невидимое. Но если вам абсолютно необходимо, вы все равно можете использовать базовые атрибуты данных с cypress-testing-library в тех редких случаях, когда вам нужно уйти.

Однако прежде чем это сделать, я обычно добавляю осмысленный aria-label или aria-describedby и использую его. В конце концов, aria-label чего-то должно правильно резюмировать, что это за вещь.

Это новая разметка, но она соответствует стандартам, она выдержит испытание временем и в любом случае необходима для доступа.

И помните, селекторы — это только один уровень надежной абстракции. Это нормально и даже ожидается создание оболочек с общими командами, которые достигают определенных обходов или утверждений.

По моему опыту, это правильный путь. Вы повышаете уверенность в тестах и ​​заставляете думать о правильных вещах.

Я не знал об описанной арией — это выглядит невероятно мощно. Спасибо, что нашли время и напечатали этот очень подробный и полезный ответ, прежде чем веселая полиция — хм — модеры — закрыла мой вопрос!

thom_nic 29.03.2024 15:49

Я не согласен с этим близко. Это не фундаментальный вопрос, основанный на мнениях — как и во всем, есть компромиссы, и вам нужно решить, что делать дальше.

adsy 29.03.2024 15:52

Немного грустно, что мой подробный ответ был отклонен. Обратная связь при этом была бы лучше!

adsy 07.04.2024 07:25

Да, я не могу поверить в то, что здесь происходит. Видимо, ТАК хорош только для вопросов, на которые вы уже могли найти ответ в Google 🙄

thom_nic 08.04.2024 13:08

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