(Эта запись в блоге также доступна на DEV.to)

Прежде чем углубляться в этот пост, вы должны знать, что такое специальные возможности. Хорошим местом для начала может быть эта статья Что такое доступность от MDN.

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

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

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

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

Случай первый

Во многих командах и проектах OSS, над которыми я работал, я вижу такой стиль тестов пользовательского интерфейса или что-то подобное:

const submitBtn = document.querySelector(‘.btn-primary’)
Simulate.click(submitBtn)
expect(submitBtn.classList).toInclude(‘btn-pimrary__disabled’)
expect(submitBtn.classList).toInclude(‘btn-pimrary__loading’)
// …

Короче говоря, использование имен классов или селекторов CSS для поиска элементов и написания утверждений тестов. Некоторым из вас может показаться очевидным, что это анти-паттерн, а не лучшая практика, но уверяю вас, это не так очевидно для всех. Только на этой неделе я изменил название класса, которое без необходимости нарушило множество тестов, на исправление которых я позже потратил остаток дня, одного этого инцидента было достаточно, чтобы побудить меня написать этот пост.

Стандарт HTML достаточно богат, чтобы вы могли делать все это и многое другое, более семантически и гибко, вообще не полагаясь на какие-либо атрибуты или правила, связанные со стилем? Черт возьми, если вы используете решение CSS-in-JS или подобное, которое шифрует имена ваших классов, это может быть даже невозможным для вас с самого начала, и в этом случае люди возвращаются к деталям реализации своих компонентов пользовательского интерфейса для добиться того же, что также является плохой практикой.

Давайте посмотрим на предложенный мной вариант:

const submitBtn = getByText(‘Submit’)
Simulate.click(submitBtn)
expect(submitBtn.hasAttribute(‘disabled’)).toBe(true)
expect(submitBtn.hasAttribute(‘aria-busy’)).toBe(true)

С помощью WAI-ARIA и обычных HTML-атрибутов вы можете представить практически любое возможное (если не все) состояние, в котором могут находиться ваши элементы, включая активные/неактивные вкладки, развернутые/свернутые панели, загружаемые/готовые элементы, отключенные/включенные элементы ввода или кнопки. , действительные/недействительные формы, видимость… вы называете это. Вы не только сделаете свои тесты намного проще в написании, но и сделаете их более надежными, читабельными и семантическими, не говоря уже о том, что в процессе вы сделаете свое приложение более доступным, это беспроигрышный сценарий в моей книге. Обычно я не решаюсь говорить о «читабельности», потому что я заметил, что это очень чувствительно и субъективно, но я думаю, что в этом случае я уверен в его использовании.

Если вы используете Jest и набор инструментов тестирования Библиотека тестирования, вы можете получить еще более качественные тесты, обновив вышеперечисленное до:

const submitBtn = getByText(‘Submit’)
Simulate.click(submitBtn)
expect(submitBtn).toBeDisabled()
expect(submitBtn).toHaveAttribute(‘aria-busy’, ‘true’)

И если ваши утверждения терпят неудачу, вы получите такие ошибки, как:

Received element is not disabled:
 <button>Submit</button>

и

Expected the element to have attribute: 
 aria-busy=”true” 
Received: 
 aria-busy=”false” 

Что, я думаю, мы все можем согласиться, лучше, чем просто «Ожидается, что ложь окажется правдой».

Случай второй

Допустим, вам нужно реализовать таблицу с флажками, которая выглядела бы так:

Флажки как бы «плавают» в этой таблице без прямого указания на то, что может быть их назначением. Однако, глядя на всю картину, вы, вероятно, можете сделать вывод, что каждое значение флажка связано с комбинацией имен столбца и строки. Просто для примера, скажем, мы заменим имена столбцов днями недели, давайте перейдем к понедельнику, среде и пятнице, и строкам с действиями или домашними делами, если мы видим, что флажок установлен в «Среда» и Перекресток «Косить газон», можно сказать, что это действие, которое либо должно быть выполнено в этот день, либо было выполнено в этот день.

Но что, если бы вам пришлось полагаться только на содержимое разметки, чтобы понять это, не видя макета? Независимо от того, является ли это хорошим дизайном и представлением для этого типа данных или нет, давайте использовать его для этого упражнения. Минималистски говоря, это может быть HTML-код, стоящий за этим:

<table>
 <thead>
   <tr>
    <th></th>
    <th>Col1</th>
    <th>Col2</th>
    <th>Col3</th>
   </tr>
 </thead>
 <tbody>
   <tr>
    <td>Row1</td>
    <td><input type=”checkbox” /></td>
    <td><input type=”checkbox” /></td>
    <td><input type=”checkbox” /></td>
   </tr>
   <!-- Row2, Row3… -->
  </tbody>
</table>

Сможете ли вы понять назначение этой таблицы и флажков из этой разметки так же быстро и легко? Что, если вы разработчик, который впервые заходит на этот экран, чтобы исправить ошибку, и, возможно, вы смотрите на эту разметку непосредственно в коде или в неудачном тесте, будет ли вам сразу очевидно, как работает этот компонент пользовательского интерфейса? В реальном сценарии это может быть таблица, отображающая несколько десятков столбцов и строк и имеющая много добавленной разметки для стилей, что еще больше усложняет ее проверку. В качестве примечания, хотя мы уже заявляли, что это не ориентированный на пользователя пост, представьте, что вы слепой пользователь, полагающийся на программу чтения с экрана, чтобы расшифровать этот пользовательский интерфейс… это, мягко говоря, не пройдет гладко.

Мы можем значительно улучшить это, просто добавив:

<table>
 <thead>
  <tr>
   <th></th>
   <th>Col1</th>
   <th>Col2</th>
   <th>Col3</th>
   </tr>
 </thead>
 <tbody>
  <tr>
   <td>Row1</td>
   <td><input type=”checkbox” aria-label=”Col1 + Row1" /></td>
   <td><input type=”checkbox” aria-label=”Col2 + Row1" /></td>
   <td><input type=”checkbox” aria-label=”Col3 + Row1" /></td>
  </tr>
  <!-- Row2, Row3… -->
 </tbody>
</table>

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

А как насчет написания тестов?

const checkbox = getByLabelText(‘Col2 + Row1’) as HTMLInputElement
expect(checkbox.checked).toBe(true)

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

Вы можете сделать еще один шаг, чтобы улучшить эти входные данные, также предоставив всплывающую подсказку той или иной формы для элемента ввода. Быстрое исправление могло бы также обратиться к атрибуту title и отразить в нем значение метки. Имейте в виду, однако, что атрибуты title имеют определенные ограничения, которые четко описаны в этой статье Хейдона Пикеринга: Tooltips & Toggletips. Или ознакомьтесь с компонентом Reach UI’s Tooltip, даже если вы не используете React, вы можете многому научиться из его реализации, если хотите развернуть свой собственный. Вы заметите, что это не тривиально.

Последние мысли

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

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