Как проверить программу Socket.io-client с помощью Jest и библиотеки тестирования реакции

kak proverit programmu socketio client s pomoshhyu jest i biblioteki testirovaniya?v=1656599181

судья Мба

0*hO-7lLXvx8RG6CAQ
Фото: freestocks на Unsplash

Тестирование качества интеграции Socket.io-клиента в реальном времени, кажется, кануло в Лету, возможно, потому, что пользовательский интерфейс имел долгую историю проблем с тестированием. Давайте поправим это!

Быстро загуглите тестирование программы socket.io.

Первые две страницы результатов (только не беспокойтесь открывать остальные страницы) – это все примеры и учебные пособия, посвященные тестированию интеграции socket.io на стороне сервера. Никто не говорит о качестве интеграции socket.io-client в интерфейс, как будет выглядеть пользовательский интерфейс, когда он получит определенные события, и действительно ли код интерфейса выдает правильные события.

Но почему? Значит ли это лишь то, что люди не слишком заботятся о качестве своих приложений в реальном времени на интерфейсе – суть программного обеспечения? Так я не думаю. Я предполагаю: тестирование интерфейсов был просто слишком тяжело!

Пользовательские интерфейсы имели долгую историю проблем с тестированностью. Пользовательский интерфейс никогда не бывает стабильным. Инструменты тестирования, которые мы располагали, легко привели к написанию очень хрупких тестов пользовательского интерфейса. Таким образом, люди обычно сосредотачивают свое время и энергию на тестировании своих программ socket.io только на стороне сервера.

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

библиотека тестирования реакции

Несколько месяцев назад мой друг и наставник Кент С. Доддс выпустил этот отличный инструмент для тестирования реагирующих приложений. С тех пор я больше не просто люблю идея тестирование интерфейсов, но действительно люблю их тестировать. Я буквально выкопал и проверил весь код пользовательского интерфейса, от тестирования которого отказался из-за его сложности :).

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

Примечание: если вы не React, есть vue-testing-library, ng-testing-library и другие, созданные на основе dom-testing-library.

Лучшей особенностью библиотеки для тестирования реакции является поддержка UI TDD. Согласно документам, его основным руководящим принципом является:

Чем больше ваши тесты напоминают способ использования вашего программного обеспечения, тем больше уверенности они могут оказать вам.

Это тот подход, о котором я говорю. Проверьте свои интерфейсы так же, как и ваш друг, не техничен. Ваш пользователь, вероятно, не знает и не беспокоит, как выглядит ваш код. И ваш тест тоже не должен. Это позволяет нам использовать TDD в наших интерфейсах.

Вот как мы собираемся написать наш тест socket.io-client – ​​тестировать все, не задумываясь о коде. Теперь давайте это сделаем!

Тестирование программы Telegram

От нашего очень талантливого дизайнера интерфейса Telegram ниже приведены проекты программы Telegram, которые мы будем тестировать.

1*-DkSudIVU8WGeLQTWeZf8g@2x
1*5s82AK1rmhshHVic0XCpXA@2x
скриншоты чата Telegram

Глядя на дизайн, я вижу пару функций в реальном времени, которые наш пользователь хотел бы убедиться, что приложение работает, иначе они закроют вкладку. Вот некоторые из них:

  • Приложение должно получать уведомления
  • Программа должна указывать, когда/или отправлено сообщение или нет
  • Приложение должно сообщать, когда доставлено сообщение или нет
  • Приложение должно сообщать, когда друг появляется в режиме онлайн или офлайн
  • Программа должна сообщать, когда друг печатает

Ладно, список можно продолжать… но давайте сначала поработаем над этим.

Прием сообщений

Давайте рассмотрим, как пользователь узнает, если он получил сообщение в качестве примера. Сначала создайте тестовый файл, а затем импортируйте файл chat.js и его плохие зависимости. Если вы новичок в издевательствах или подобных вещах, тогда Кент К. Доддс действительно должен быть вашим другом. У него есть все, что касается тестирования JavaScript, поэтому просто следите за ним здесь, в Twitter и везде.

Теперь, когда я писал эту строку, я думал, что она должна просто написать книгу о тестировании JS, поэтому написал в Twitter:

И, надеюсь, он в конце концов будет 🙂

Возврат к нашему тестовому файлу:

// chat.test.jsimport React from 'react';import io from 'socket.io-client';
import Chat from './chat';

Поскольку мы проводим здесь только тестирование интеграции, мы не хотим посылать события socket.io на сервер. Потому нам нужно высмеять socket.io-client. Дополнительные сведения о насмешке см. в разделе статью Кента «Но в самом деле, что такое имитация JavaScript?» а также этот раздел из документов Jest о макетных функциях Jest.

Как только вы поймете, как издеваться, следующая вещь – понять, что делает ваш модуль, а затем подделать реализацию.

// socket.io-client.js
let EVENTS = {};
function emit(event, ...args) { EVENTS[event].forEach(func => func(...args));}
const socket = { on(event, func) {  if (EVENTS[event]) {   return EVENTS[event].push(func);  }  EVENTS[event] = [func]; }, emit};
export const io = { connect() {  return socket; }};
// Additional helpers, not included in the real socket.io-client,just for out test.
// to emulate server emit.export const serverSocket = { emit }; // cleanup helperexport function cleanup() { EVENTS = {}}
export default io;

Таким образом, у нас достаточно хороший макет socket.io-client для нашего теста. Давайте это используем.

// chat.test.jsimport React from 'react';import mockio, {serverSocket, cleanUp } from 'socket.io-client';
import Chat from './chat';

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

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

Обычно это работает так, что друг пользователя отправляет на сервер сообщение с пользовательским адресом, а затем сервер отправляет сообщение пользователю. Теперь, поскольку мы не проверяем, может ли пользователь сейчас отправлять сообщения, может ли пользователь получать сообщения, давайтеsocket.io server непосредственно отправить пользователю сообщение.

// chat.test.jsimport React from 'react';import mock-io, {serverSocket, cleanUp } from 'socket.io-client';import {render} from 'react-testing-library';
import Chat from './chat';
test('App should get messages', () => {  // first render the app  const utils = render(<Chat />)    // then send a message  serverSocket.emit('message', 'Hey Wizy!');})

Выше мы импортировали render метод из библиотеки react-testing-library, которая просто оберткой ReactDom.render. В нашем тексте мы используем его для просмотра нашей программы Chat. Метод render возвращает тестовый объект утилиты, содержащий методы запроса, которые мы можем использовать для запроса container нашего приложения — узел DOM render отразил наше приложение в — для узлов DOM, интересующих наш тест. Далее в тексте используйте фиктивный сервер socket.io, чтобы отправить сообщение пользователю.

Теперь, когда мы послали сообщение пользователю, подумайте еще раз: как пользователь узнает, что он получил сообщение? Учитывая вышеприведенный дизайн, им обязательно придется посмотреть на экран, чтобы увидеть сообщения. Итак, чтобы проверить это, нам нужно спросить контейнер нашей программы, чтобы увидеть, есть ли в нем узел, содержащий отправленное нами сообщение Hey Wizy! Для этого объект утилиты вернулся из render имеет метод запроса под названием getByTextтак что мы могли бы просто сделать:

expect(utils.getByText('Hey Wizy!')).toBeTruthy();

Хотя это может сработать, к сожалению, мы не можем этого сделать. Вот почему: все методы запроса, возвращены из render выполнит поиск во всем контейнере по указанному запросу. Это означает, что getByTextкак используется выше, будет искать текст Hey Wizy! во всем контейнере, а затем возвращает первый узел, содержащий этот текст.

Но не так, наш пользователь будет искать текст. Зато наш пользователь будет только смотреть внутри ‘messages-section’, раздел, содержащий все сообщения. Только если сообщения появятся в этом разделе, они узнают, что сообщения получили. Итак, чтобы убедиться, что наш тест похож на то, как пользователь использует наше приложение, нам нужно будет искать текст «Hey Wizy!» только внутри раздел сообщений, как это сделал бы пользователь.

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

Примечание: within это новый API, вдохновленный этой статьей, поэтому убедитесь, что у вас новейшая версия библиотеки тестирования реакции.

// chat.test.jsimport React from 'react';import mock-io, {serverSocket, cleanUp } from 'socket.io-client';import {render, within} from 'react-testing-library';
import Chat from './chat';
test('App should get messages', () => {  // first render the app  const utils = render(<Chat />)    // then send a message  serverSocket.emit('message', 'Hey Wizy!');    // the message must appear in the message-section  const messageSection = utils.getByTestId('message-section');  // check withing messageSection to find the received message  const message = within(messageSection).getByText('Hey Wizy!');})

Сначала мы захватили раздел сообщений с помощью метода запроса getByTestId. Использовать getByTestId в вашем тесте вам придется жестко закодировать его в DOM. Как так:

<div data-testid=”message-section” />

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

Однако наш тест не опирается на структуру DOM. Даже если кто изменит div к а section тег или оборачивает его на 10 уровней глубоко в DOM, наш тест работает не только о коде – он работает только о test-id.

Наконец, мы используем within метод, как описано ранее, чтобы получить полученное сообщение. Если текст не найден, getByText бросит и провалит наш тест.

И именно так мы утверждаем, что приложение может получать уведомления.

Пишу больше тестов

Давайте посмотрим еще несколько способов запроса, которые дает нам библиотека react-test-library. Мы увидим, как мы можем дальше комбинировать API, которые уже научились выполнять более сложные запросы, не полагаясь на код интерфейса пользователя.

Итак, давайте напишем второй тест: приложение должно сообщать пользователю, когда/или было отправлено сообщение или нет. Кроме того, я думаю, что этот тест в основном выполняет то же, что и следующий в списке, поэтому давайте объединим оба в один пример.

Опять же, первый вопрос, который мы задаем…? Я знаю, что вы поняли: «Как наш пользователь проверит эту функцию?» Ладно, то, как вы формулируете свой вопрос, может отличаться, но вы поняли идею :). Следовательно, чтобы проверить функцию отправки сообщений, шаги будут выглядеть так:

  • Пользователь находит вход для ввода сообщения. Затем они вводят свое сообщение. Наконец, они нажимают кнопку отправить.
  • Сообщение должно появиться в разделе сообщения
  • Сервер сообщит, попало ли сообщение на сервер, то есть отправлено
  • Пользовательский интерфейс должен пометить сообщение как отправлено
  • Затем сервер сообщает, когда сообщение было доставлено
  • Пользовательский интерфейс, в свою очередь, должен обновлять сообщение как доставленное

Как пользователь находит вход для ввода сообщения? С дизайна пользовательского интерфейса, с которым мы работаем, они должны посмотреть и найти входящие данные с помощью заполнителя «сообщения». (На самом деле это единственный вход на экране, но даже если их будет больше, пользователь определит вход для ввода сообщения заполнителем или меткой.)

React-testing-library снова охватила нас методом запроса, который называется getByPlaceholderText

// chat.test.jsimport React from 'react';import mock-io, {serverSocket, cleanUp } from 'socket.io-client';import {render, renderIntoDocument, within, cleanup} from 'react-testing-library';
import Chat from './chat';
afterEach(cleanup);
test('App should get messages', () => {  // ...})
test('App should tell when message is sent and delivered', () => {  // first render the app  const utils= renderIntoDocument(<Chat />)    // enter and send a message  utils.getByPlaceholderText('message').value="Hello";  utils.getByTestId('send-btn').click()})

Потому мы представили здесь пару новых API. Первый из них renderIntoDocument метод. В нашем тесте мы должны запускать реальные события DOM, а не моделировать их, поскольку это больше напоминает, как пользователи используют нашу программу.

Недостатком является то, что render метод создает и отображает нашу программу к произвольному узлу DOM, который называется container, на лету. Но React обрабатывает события с помощью делегирования событий – добавляя одно событие для всех типов событий на documentа затем делегировать событие соответствующему узлу DOM, который инициировал событие.

Итак, чтобы запускать реальные события DOM, нам нужно фактически отразить наше приложение document.body. Вот что renderIntoDocument делает для нас.

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

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

Теперь, когда мы нажали кнопку послать, давайте сделаем некоторые утверждения.

// chat.test.jsimport React from 'react';import mock-io, {serverSocket, cleanUp } from 'socket.io-client';import {render, renderIntoDocument, within, cleanup} from 'react-testing-library';
import Chat from './chat';
afterEach(cleanup);
test('App should get messages', () => {  // ...})
test('App should tell when message is sent/delivered', () => {  // first render the app  const utils = renderIntoDocument(<Chat />)    // enter and send a message  utils.getByPlaceholderText('message').value="Hello";  utils.getByTestId('send-btn').click();    // the message should appear on the message section  const messageSection = uitils.getByTestId('message-section');  expect(within(messageSection).getByText('Hello')).toBeTruthy();    // server tells us message is sent  serverSocket.emit('message-sent');
  // Now the UI should mark the message as sent  const message = within(messageSection).getByText('Hello');  expect(within(message).getByTestId('sentIcon')).toBeTruthy();
  // server tells us it's delivered  serverSocket.emit('message-delivered');
  // UI should mark the message as delivered  expect(within(message).getByTestId('deliveredIcon')).toBeTruthy();})

И все это. Именно так, как ожидает пользователь, наш тест ожидает, что значок отправлено/доставлено появится рядом с сообщением, когда оно будет отправлено/доставлено.

Пока мы видели, как легко может быть тестирование программы socket.io-client в реальном времени с помощью библиотеки react-testing-library. Независимо от того, что вы тестируете, следуя этому подходу, вы получаете больше уверенности, что ваша программа работает должным образом. И что больше, у нас еще есть нулевая идея как будет выглядеть реализация программы Так же, как пользователь, наш тест просто не заботится о реализации!

Заканчиваем

Наконец, я оставлю вам подумать о том, как написать два последних теста, оставшихся в нашем списке:

  • Приложение должно сообщать, когда друг появляется в режиме онлайн или офлайн
  • Программа должна сообщать, когда друг печатает

Совет: вы должны настроить сервер socket.io излучать событие, а затем утверждать, как будет выглядеть пользовательский интерфейс. Подумайте, как точно пользователь будет знать, когда друг печатает, онлайн, офлайн.

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

Если у вас есть вопросы, на которые нет ответа или вы чувствуете иначе относительно некоторых пунктов здесь, не стесняйтесь оставлять некоторые комментарии здесь или через Twitter.

Вы также можете подписаться на меня здесь и/или в Twitter, чтобы получать новые замечательные статьи. И вы можете просмотреть мои предыдущие статьи:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *