Привет всем, меня зовут Ярослав Астафьев, и сегодня я хотел бы провести для вас экскурсию по тестированию ReactJS. Я не буду углубляться в сложности тестирования веб-приложений с использованием тех или иных библиотек (следуя подходу «сложно тестировать только плохой код»), а вместо этого попробую разнообразить ваш кругозор.
Так что в этой статье React — это скорее повод объединить подходы к тестированию, отправная точка, объединяющая хипстеров и технологии.
Правильнее было бы даже сказать, что о принципах тестирования в целом мы поговорим с иллюстрациями в ReactJS (и не только).
Если вы считаете себя гуру тестирования - пропустить первую половину статьи , речь идет об основных принципах тестирования.
Если вторая часть не откроет для вас ничего нового, приходите работать к нам и научите нас, как это делать.
Если введение не вызвало приступ синестезии, добро пожаловать под кат.
Модульные тесты
Юнит Шутка — библиотека для тестирования JavaScript. Если тебе не нравится этот, возьми его другой , но тогда лучше Ава .Здесь все просто: нажмите на волшебную кнопку и убедитесь, что определенное значение с «0» изменилось на «1»:
Теперь у вас есть все необходимые навыки протестировать волшебную кнопку.import React from "react" import { MyButton } from ".
/src/components/dummy/myButton" import renderer from "react-test-renderer" test("MyButton has onPress fn", () => { let x = 0 const instance = renderer .
create(<MyButton onPress={() => x++} />) .
getInstance() expect(instance.handlePress).
toBeDefined() expect(x).
toBe(0) instance.props.handlePress() expect(x).
toBe(1) })
К сожалению, эти навыки не имеют отношения к реальной жизни.
Компонент React не может быть так хорошо изолирован, а изоляция — один из основных принципов модульного тестирования.
Необходимо как-то удалить все компоненты, которые так или иначе участвуют в методе рендеринга, за исключением тестируемого.
И выход есть: умные люди придумали для этого MomAPI. // initJest.jsx file
global.fetch = require('jest-fetch-mock')
//custom mock
const API = require('mockAPI')
//static mock
describe("Date() Tests", () => {
beforeEach(() => {
MockDate.set("2011-09-11T00:00:00.000Z")
})
afterEach(() => {
MockDate.reset()
})
//smth .
})
Суть Mock проста: все, что не наше, — Макет/заглушка/фейк/пустышка/шпион и т. д. Мы «эмулируем» так, как нам нужно, реальное поведение компонента, который может иметь сложную логику, на заранее подготовленных тестовых данных и принимаем на веру, что все эмулируемые компоненты работают идеально, если им поданы правильные параметры как вход.
Есть библиотека для шуток шутка-принеси-издевательство , в нем вы можете глобально определять макеты.
Если вам не нравится этот вариант, вы можете «намочить» каждый нужный вам компонент в тесте отдельно.
Чистая функция всегда возвращает один и тот же ответ для одного и того же ввода.
Соответственно, если в наших компонентах бизнес-логики есть «не чистые» функции/компоненты, то в юнит-тестах их тоже нужно будет «замачивать» (но для юнит-тестов это правило не всегда справедливо).
Классический пример — компонент реагирования, который отображает текущую дату и время в нужном вам формате; каждый раз, когда вы запускаете тесты, дата будет разной, и вы не сможете написать правильные модульные тесты.
Для всех несогласных можно усложнить пример, где ваш компонент должен отображать дату в относительном формате и выделять более старые даты красным цветом.
Соответственно, если у вас динамические вещи, которые зависят от времени/погоды/давления, то мока переопределит нужный вам вызов, чтобы не было зависимости от сторонних факторов.
Так что не нужно ждать 29 февраля чтобы поймать выпавший тест.
Правила модульного тестирования
Описанные выше проблемы и способы их решения — это попытки неформального подхода к тестированию: каждый тестирует, как хочет. На мой взгляд, соответствия достаточно.три важных правила модульного тестирования :
- Детерминизм
- Изоляция
- Независимость от внешних факторов
- Здравый смысл
Если я написал тест на Windows, то он должен запуститься и на Mac и дать тот же результат. Разработчики Windows любят забывать, что имена файлов в системах *nix чувствительны к регистру.
И тебе повезет, если тесты завершится неудачей в CI, а не в рабочем приложении .
Следующее правило – изоляция.
Смачиваем все непроверенные компоненты.
Если это сложно сделать, значит, пора провести рефакторинг.
И последнее, но не менее важное: если есть данные, которые ваше приложение получает во время выполнения, их также необходимо зафиксировать.
Это может быть локаль, размер окна, формат даты, формат чисел с плавающей запятой и т. д.
Интеграционные тесты
Когда начинать писать интеграционные тесты — это, на мой взгляд, вопрос открытый, и в каждой отдельной команде/продукте решение должно приниматься с учетом внутренних факторов.Можно применить формальный подход: добиться охвата юнит-тесты 80% (плохо написанные тесты не следует пересматривать/требовать охватывать тестами только новый или измененный код), затем проводить полный аудит и рефакторинг всех написанных тестов с анализом типичных ошибок, формализовать внутренние правила написания тестов и проводить подобные рейды раз в год. Если после всех описанных выше шагов покрытие вашего кода юнит-тестами по-прежнему составляет 80%+, это означает, что у вас зрелая команда или вы просто недостаточно критичны к своему коду/тестам.
Если покрытие кода стало меньше, то нужно снова добиться покрытия 80% и переходить к написанию интеграционных тестов.
Можно применить менее формальный подход и просто руководствоваться здравым смыслом: например, для каждого бага, воспроизведенного n раз, написать тест или придумать что-то еще, например, подбросить монетку.
Второй открытый вопрос: а.
какие тесты считаются интеграционными? ? Пожалуй, оставим его без ответа.
В интеграционных тестах мы проверяем работу не одного компонента, а нескольких компонентов в связке.
Никаких правил нет, но здравый смысл подсказывает:
- не тестируйте, что рендерится, где это вызывается и когда всё это заканчивается;
- не тестируйте работу ReactJS, если он не работает, вам ничего не поможет;
- не тестируйте, как работает конечный автомат React;
- тестировать бизнес-логику/модель данных/граничные ситуации/вещи, которые часто ломаются.
Они выполняются гораздо дольше, а также их сложнее писать, поэтому не стоит увлекаться и освещать каждый незначительный случай в логике приложения.
Это дорого с точки зрения аренды инфраструктуры, и долго с точки зрения разработки и времени выполнения скриптов.
Кто-то потратит свою жизнь на эту рутину, а менеджер и пользователи будут грустить , и ждите новых функций, и.
Еще одна причина, по которой не стоит пытаться тестировать все – это False Security (самые важные моменты я уже постарался написать выше).
Каждая команда должна прочитать об ошибках первого и второго типа, лемму Неймана-Пирсона и оценить свои риски в деньгах, попугаях или другой принятой в команде мере истины.
Но из этого правила, как и из любого другого, есть исключения.
Забудь все, что сказано выше :
- При тестировании динамических зависимостей.
Если вы не знаете, какой компонент прибудет во время выполнения, вы визуализируете его, но он может не прибыть.
Для этого вам также необходимо написать тест; автоматический выключатель никто не отменял.
Либо полученный вами компонент не тот, который вы ожидали, либо компонент сломан.
Поэтому в данном случае мы пишем интеграционный тест и рендерим его.
Проверяем, все ли работает и ничего не вылетает.
- При разработке с пиксельной точностью (ну вы поняли) вам придется рендерить и делать различия скриншотов, и каждый раз, когда библиотека компонентов обновляется до новой версии, вам придется обновлять эталонные скриншоты.
Потому что легче смириться с наймом нового дизайнера, чем исправлять ситуацию.
Снимковые тесты
Самый простой интеграционный тест — это снимок:- Возьмите компонент и отрендерите его
- В рендере пишем console.log(this)
- Копирование справочных данных из консоли
- Давайте сравним
Это библиотека для снэпшот-тестов, которая одновременно и завершила идею StyleGuidist — создание собственной дизайн-системы на основе React-компонентов.
Первое правило теста снимка: никогда не говори, попытайся проверить данные .
Они всегда должны быть статичными, «фиксированными» и независимыми.
Второе правило: неработающий снимок теста не означает, что все плохо .
Если он красный, это не значит, что все идет хорошо.
Есть много вариантов сделать так, чтобы макет был одинаковым, но дерево DOM было разным.
Поэтому мы игнорируем пробелы, атрибуты, ключи или не тестируем вещи, на поддержку которых требуется так много времени.
Или отмечаем руками, что сломано, а что нет. Исправляем неработающие тесты и перезапускаем StoryBook в режиме макетного обновления — режиме, в котором тест будет отображать компоненты и вставлять снимок в качестве эталонного значения в ожидаемое условие.
xState и React-автоматы
ReactJS сложен.Казалось бы, библиотека — это круто.
Я сделал три компонента — класс: конечный автомат вроде работает и код красивый.
Потом полгода пишешь на ReactJS, смотришь на код — ерунда какая-то.
Не поймешь, где костыли, где маршруты, где состояние, где тайники… Потом думаешь: ну, сделаю так, как советует Фейсбук: прикреплю «хокки», « крючки», что-то еще, и вдруг ты ловишь себя на мысли о том, какой ты шерстистый, хх.
ru в попытках найти проект с разработкой на React с нуля, вот и все обязательно сделаю все красиво … Все становится настолько сложным, что вообще невозможно понять, как это работает. И это работает до тех пор, пока кто-то не пожалуется.
Починим - и починит, а вокруг все ломается.
Один из выходов - Государственный аппарат , набор детерминированных состояний приложения и разрешенных переходов между ними.
И, как говорят в узких кругах, на React не писал, если не взломал свой конечный автомат. Здесь стоит вспомнить xState .
Это детерминированный конечный автомат для JavaScript. На xState можно сделать очень крутой UI — ссылку на соответствующий отчёт можно найти в документации библиотеки Реагировать на автоматы .
В свою очередь, React Automata — это библиотека, адаптировавшая xState к ReactJS. Более того, она может генерировать тесты для состояний конечного автомата .
Если наш первый флажок установлен, зеленый свет горит. Если второй ложный, то рисуется серая собака, и React Automata генерирует тесты для всех четырёх комбинаций этих параметров и валидирует собак и лампочки.
Правда, в какой-то момент вам захочется отрезать половину тестов, но поначалу вы будете очень рады.
В любом случае, это удобный способ взглянуть на свои тесты со стороны, мне это очень напоминает идей тестирования с детерминированным хаосом.
Кипарис
Со снимком более-менее разобрались, можно двигаться в сторону end2end. У нас есть все наши продукты внутри компании, поэтому локальные решения — единственный вариант для нас.Надеюсь, что у вас есть возможность использовать облачные решения, тогда что-то подобное вам пригодится Кипарис .
Раньше вы выбирали фреймворки для тестирования, брали библиотеки для утверждения, библиотеки для сравнения сложных XML. Затем мы выбрали драйвер и браузер, чтобы все это запустить.
Мы пробежали и написали кучу тестов.
Всё это съедает инфраструктуру, нужно всё запихнуть в Докер, потом прикрутить что-нибудь, что смотрит тесты в динамике, анализирует их, показывает, что не так.
Ребята из Cypress сделали все это за вас.
Они решили несколько задач: настройка рабочей среды, написание кода, запуск и запись тестов.
Если тест не работает, вы можете отобразить снимок экрана, на котором будет указано, что было сломано.
Правда, для мобильных телефонов это не работает, но там, например, есть Детокс .
Это, конечно, жестко с точки зрения порога входа: вам придется под него подгонять свое приложение, переписывать кучу файлов и т. д. Но при желании это возможно.
Мягкие тесты
Существуют альтернативные типы тестов, которые даже правильно назвать тестами нельзя.Я называю их мягкими тестами.
Например, линтеры.
Они используются в основном разработчиками внешнего интерфейса (иногда к разработчикам Java приходит прозрение).
Существует множество линтеров: ESLint , JSHint , красивее , Стандартный , Клинтон .
я советую Красивее: быстро, дешево, сердито, легко настраивается, работает «из коробки» .
Если вы хотите принять более активное участие, вы можете настроить ESLint. Приведу классический пример плагина для него: когда клиент находит в вашем коде комментарии с нецензурными выражениями, он обычно ругается.
Хитрые разработчики делают комментарии на русском языке, чтобы заказчик не догадался.
Но заказчик догадался.
воспользоваться гугл-переводчиком и узнал все, что о нем думают разработчики.
Выход из ситуации неприятный, возможно, с потерей денег или клиентов.
Для этих случаев вы всегда можете разработать плагин для ESLint , который находит в исходном коде «оригинальные русские» слова и говорит: «Ой, извините, отклоните ваш коммит».
Прелесть линтеров в JavaScript в том, что они можно поместить на крючок перед фиксацией .
Лично мне не нравится, что Prettier не хранит историю (хотя, с другой стороны, технический долг не накапливается).
С точки зрения статистического анализа кода такие тесты плохие, потому что нельзя увидеть динамику проекта, посмотреть, сколько ошибок было вчера, позавчера.
В принципе, эта проблема решена в СонарКуб , он также доступен в облачном решении.
Это статистический анализатор кода, хранящий историю запусков и умеющий работать с двумя десятками языков, включая даже PHP (кому еще нужна железная рука статического анализа, как не им? :) ).
В нем вы можете увидеть динамику ваших уязвимостей, багов, технического долга и т.д.
Тесты сложности
Фронтендеры используют линтеры, потому что им нужны красивые отступы .Сложность — это также мягкие тесты, которые можно использовать для проверки качества вашего кода.
На картинке видно, как я пытаюсь уследить за мыслями юниора, сделавшего запрос на включение.
В таких случаях я предлагаю все снести и построить прямую дорогу.
Тесты сложности следуют очень простому принципу: они вычисляют цикломатическая сложность алгоритм.
Например, они читают функцию и находят в ней 10 переменных.
Если 10, то это, наверное, сложно.
Поставим сложность 1. За каждый цикл будем давать 3 балла, за цикл в цикле - 9, за каждый цикл в цикле цикла - 27. Складываем все и говорим: цикломатическая сложность равна 120, а человек может понять только 6. Смысл этой оценки в том, чтобы субъективно сказать, когда вам нужно провести рефакторинг исходного кода, разбить его на части, выделить новые функции и тому подобное.
И да, SonarQube тоже может это сделать.
Альтернативные тесты
В моем мире альтернативные тесты также являются мягкими тестами.Солидарность - очень полезная вещь для онбординга.
И не только для фронтенд-разработчиков, хотя он написан на JavaScript. Она позволяет протестировать рабочую среду .
Раньше нужно было составлять огромные инструкции с указанием версий языка программирования, библиотек, списка необходимого программного обеспечения, чтобы просто начать работу, поддерживать все в актуальном состоянии и т. д. Теперь вы можете сказать так: «Вот ваш компьютер.
, вот исходный код. Пока Солидарность не сработает - не заходите».
При этом порог входа низкий.
Солидарность умеет снимать отпечатки настроенной рабочей среды и позволяет добавлять очень простые правила проверки не только установленного ПО.
Бесит ли вас, когда их придумывают? слова: «Ой, извини, у меня там что-то не работает, можешь мне помочьЭ» Второй вариант использования (он же основной) — тестирование производственной среды со словами: «Юнит-тесты на CI конечно прошли, но конфигурации CI и PROD существенно отличаются.
Так что никаких гарантий.
» Цель библиотеки очень проста: выполнить первое правило непрерывной интеграции: «у всех должна быть одна и та же среда».
Чистый, изолированный, без побочных эффектов или, по крайней мере, их меньше.
кого я пытаюсь обмануть?
API-вызов
Бывает, что разработчики делятся на несколько команд — одни пишут фронтенд, другие — бэкенд. Фиктивная ситуация, которой не может быть в реальной команде: вчера всё работало, а сегодня после двух релизов — переднего и заднего — всё сломалось.Кто виноват? Как человек с изначально бэкенд-опытом, я всегда говорю: фронтендеры.
Все просто, где-то накосячили, как всегда.
В какой-то момент приходят фронтенд-разработчики и говорят: «Мы прочитали пост про связь , просмотрел руководство и научились производить впечатление о вашем REST API .
И вы не поверите, оно изменилось…» В общем, если ваши бэкендеры не дружат со Swagger, openAPI или другими подобными решениями, стоит взять на заметку.
Производительность JS
И наконец, JS-тест производительности.Никто не тестирует производительность JS кроме производителей браузеров.
Как правило, все они используют Бенчмарк.
js .
«О, мы потратили 18 лет на то, чтобы усовершенствовать наш Проводник, чтобы он мог отображать знаки «миллиард за миллиардом» быстрее, чем в Chrome».
Кому вообще нужен такой знак? Если вы хотите провести тесты производительности, лучше пойти другим путем: протестировать end-to-end и посмотреть, как все работает. У пользователя формируется представление о том, как работает приложение в целом, пользователя не волнует, что это проблемы на бэкенд-стороне.
Военная история №1
Теперь пример из жизни.Однажды к нам приходит начальство и говорит: «У вас фронт очень плохо работает, еле загружается.
Нам нужно что-то сделать с выступлением, люди жалуются».
Думаем: теперь придется две недели настраивать производительность, ковыряясь в логах почему ты обновил , подобрать тряску дерева, разрезать всё на куски с динамической загрузкой.
А вдруг не получится, а вдруг всё сломаем или сделаем только хуже? Необходимо найти альтернативное решение.
Откройте браузер, посмотрите: 7,5 МБ, 2 секунды, все нормально.
Давайте установим Nginx GZip:
В Nginx есть возможность настроить уровень сжатия, попробуем:
Прирост - 25% производительности.
Остановитесь пораньше.
Давайте посмотрим на небольшой логотип дизайнера в углу.
Он остается очень красивым, даже если его растянуть, но зачем нам это нужно?
Вот что мы получили после оптимизации одного изображения.
Вес логотипа вы можете оценить самостоятельно.
Наконец мы приходим к заказчику и говорим: «Первая загрузка не так важна, как вторая.
И включите принудительное кэширование:
.
Все счастливы, все радуются!» Кроме пользователя, конечно.
В результате мы решили чаще проводить проверки размеров.
Gzip, шрифты, картинки, стили - те места, куда редко кто заглядывает, а пользы много.
Мэдж и updtrJS
Следующий шаг: аудит зависимостей .Мэдж — это штука, которая анализирует код и говорит: этот класс подключен к такому-то и т. д. Если все пройдет через один компонент и он сломается, то это будет неприятно.
Madge — отличный инструмент визуализации, но он подходит только для ручного исследования.
У него есть эта опция, круговая, которая ищет все циклические зависимости в вашем проекте .
Если они есть, то это плохо; если нет, значит, еще не написали.
Боль устаревших фреймворков и библиотек почти решена с помощью updtrJS .
У вас 70 тысяч строк кода? Вы пытаетесь перейти с React 13 на React 16? Упдтр тебе не поможет move, но он поможет вам узнать, на какие версии библиотек можно безболезненно перейти.
Кроме того, это позволяет разработчикам оставаться в тренде и помогает поддерживать актуальность зависимостей.
Если у вас хорошее тестовое покрытие, я рекомендую его.
Статические типы
Используйте статическую типизацию JS. , потому что динамическая типизация в JS — это вообще не фича, это пропасть.Flow, typeScript, ReasonML и все.
Хаос-тестирование
Суть хаос-тестирования проста: запускаем браузер и начинаем тыкать во все, что тыкают, вводить во все поля все, что введено, и так далее.Пока оно не сломается.
В свое время этот продукт был написан Amazon, чтобы получить как можно больше исключений на бэкенде.
Мол, «давайте постучим спереди, и посмотрим на ошибки сзади».
Если есть ошибки, мы их исправим.
Реализации: Гремлин.
com И Обезьяна Хаоса .
В React оно приобрело новый смысл — начиная с версии 16, в которой добавлен компонентDidCatch. Если ваш фронт дал сбой и выдал исключение, вы можете перехватить его и зарегистрировать.
Хотя есть и более элегантные способы решения этой проблемы.
в рамках проекта Непослушная строка волонтеры собирают все плохие строчки и не только строк, которые могут привести к поломкам или другим неожиданным результатам, позволяет значительно расширить спектр ваших тестов.
Например, если вы опубликуете в Твиттере «пространство нулевой длины», он ответит внутренней ошибкой сервера, так что же мы можем сказать о наших рефлекторных поделках?
Военная история №2
Это вероятность того, что один из моих тестов провалится – одна на десять миллиардов.
И это событие произошло.
def generateRandomPostfix(String prefix) {
return prefix + "-" + Math.abs(new Random().
nextInt()).
toString() } def "testCorrectRandomPostfix"(){ given: def prefix = "ASD" when: def result = generateRandomPostfix(prefix) then: result?.
matches(/[a-zA-Z]++-[0-9]++/)
}
Это было большое и трудное испытание.
В приведенном выше коде я постарался оставить только основную идею.
Разобраться в этом было непросто, но мы нашли проблему.
Давайте сделаем это шаг за шагом.
У нас есть префикс ASD, есть функция, которая генерирует случайный постфикс и добавляет его к префиксу через дефис.
Тем более, что наш постфикс строго цифровой.
Далее с помощью регулярного выражения проверяем корректность сгенерированного результата (забыл сказать, этот тест на языке groovy).
В Java наименьшее целое число на 1 больше самого большого целого числа.
Следовательно, модуль наименьшего целого числа будет наименьшим целым числом — переполнение буфера еще никто не отменял.
Выше приведен код, который убивает браузер.
Исправлено ниже.
Видите ли вы хотя бы одно отличие? Это «+» перед fromX. Дело в том, что в какой-то момент изменился формат бэкенда, XML начал отправлять стоковые данные.
От этого никто не застрахован.
Параметризованный хаос
Иногда параметризованный хаос может спасти вас.TestCheck.JS — одна из самых крутых библиотек с точки зрения хаоса.
Вероятно, он поддерживает все среды тестирования.
И в качестве бонуса - Поток-генерация : Если вы описали типы данных во Flow, то он может генерировать за вас тесты.
check(
property(
gen.int, gen.int,
(a, b) => a + b >= a && a + b >= b
)
)
{ result: false,
failingSize: 2,
numTests: 3,
fail: [ 2, -1 ],
shrunk:
{ totalNodesVisited: 2,
depth: 1,
result: false,
smallest: [ 0, -1 ]
}
}
TestCheck имеет множество готовых генераторов, но вы можете написать свои собственные.
Функция выше проверяет, что сумма двух чисел всегда больше каждого из них.
Естественно, это не так, простой пример: 0 и -1. Эта штука обнаружила ошибку на значениях 2 и -1, но не остановилась и нашла самый примитивный вариант, на котором можно воспроизвести эту ошибку.
Очень круто!
Другое тестирование
Также нужно тыкать руками.Например, вам нужно протестировать состояние.
Государство может быть не только хорошим, но люди часто об этом не задумываются.
Что делать, если у вас есть старые данные и новое состояние? когда у тебя нет подключения к интернету? нет разрешений? проблемы с локалью? Вы можете протестировать различные устройства, платформы, мобильные телефоны, липкие клавиши, поддержку чтения с экрана и многое другое.
Не забывайте о тестировании Неисправности третьих сторон .
«Значит эта сторонняя библиотека сломана» — это тоже ваша проблема.
Производственные испытания
Для производства в React 16 вы можете использовать два простых решения: ErrorCeption И Медоед (у нас есть правда Часовой ).Подключаешь библиотеку, и они начинают собирать статистика ошибок в производстве.
Оптимально делает А/Б тестирование.
Он очень хорошо организован, может доставлять под конкретных людей, в конкретное время, контент, тестовые образцы и при этом балансировать нагрузку и вести статистику.
Из коробки
JS — не панацея.Многие вещи могут сломаться, и тестировать можно не только на JavaScript. Очень простая вещь - validator.w3.org/checklink .
Это сканер, который заходит на ваш сайт, смотрит, какие ссылки есть на страницах, и проверяет их работоспособность.
Если ваш сайт доступен из Индии, это не значит, что его можно открыть в России.
Achecker.ca/checker должно помочь.
Веб-страницаtest.org - проект, без которого мне сложно жить.
Tools.pingdom.com - еще один интересный проект. На www.w3.org/WAI/ER/tools вы можете найти тысячи решений для различных случаев.
На предыдущей работе мы тестировали каждый коммит. Были коммиты для множества вещей.
Слава Богу, что на тот момент не было Jenkins Multibranch Plugin, который после слияния пул-реквеста собирал все пул-реквесты заново.
Используйте наборы тестов, цепочки тестов («зачем запускать это, если оно явно не работает»), ночные сборки, регресс, полный регресс, пакеты умных регрессионных тестов и т. д. Программисты, вероятно, единственные люди, которым платят за исправление собственных ошибок, потому что в прошлый раз они недостаточно хорошо выполнили свою работу.
Вариантов и подходов масса, поэтому буду очень благодарен, если этот пост превратится в дискуссию с перечислением полезных ресурсов, которые помогут сделать нашу жизнь проще.
Думаю, на этом кратком описании я закончу.
Готов ответить на вопросы в комментариях.
Теги: #тестирование #тесты #Тестирование веб-сервисов #JavaScript #react.js #react #оптимизация рабочего времени
-
Самые Популярные Блоггеры
19 Oct, 24 -
Видеоотчеты С Конференции Codefest 2014
19 Oct, 24