как проверить javascript код

Инструменты для проверки кода JS на ошибки

как проверить javascript код

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

JSLint

«JSLint will hurt your feelings» — такое предупреждение можно увидеть на сайте валидатора JSLint, созданного в 2002 году Дугласом Крокфордом. И это правда, поскольку очень часто JSLint находит множество ошибок в абсолютно работающем коде. Если вы стремитесь к совершенствованию своего кода и доведению до идеального состояния — воспользуйтесь этим сервисом.

как проверить javascript код

JSHint

JSHint — более удобная и настраиваемая, а также более популярная версия валидатора JSLint. JSHint больше нравится программистам за возможность выбирать настройки и правила для проверки кода, и сопровождается хорошей документацией. Легко интегрируется в редакторы.

как проверить javascript код

ESLint

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

как проверить javascript код

Инструмент JavaScript Code Style отличается от предыдущих тем, что не проверяет код на наличие потенциальных багов и ошибок. Задача JSCS — проверка и выявление нарушений в стиле кода. Пользователям доступно множество пресетов и готовых конфигураций, которые вы можете сразу же начать использовать, если придерживаетесь такого же кодстайла.

как проверить javascript код

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

Источник

Тестирование JavaScript кода с Jest для чайников. Часть 1

Что такое Jest?

Jest — это восхитительная среда тестирования JavaScript с упором на простоту.

И действительно, Jest очень простой. Он не требует дополнительных настроек, легкий в понимании и применении, а так же имеет довольно хорошую документацию. Отлично подходит для проектов использующих Node, React, Angular, Vue, Babel, TypeScript и не только.
Также он имеет открытый исходный код и поддерживается компанией Facebook.

Установка

Для установки Jest в ваш проект выполните:

Если вы используете yarn:

После установки можете обновить секцию scripts вашего package.json:

С помощью такого простого вызова мы уже можем запустить наши тесты (на самом деле jest потребует существование хотя бы одного теста).

Также можно установить глобально (но так делать я бы не рекомендовал, так как по мне глобальная установка модулей является плохой практикой):

И соответственно для yarn:

После этого вы можете использовать jest непосредственно из командной строки.

Первый тест

Давайте создадим файл first.test.js и напишем наш первый тест:

И запустим наши тесты с помощью npm run test или непосредственно командой jest (если он установлен глобально). После запуска мы увидим отчет о прохождении тестов.

Давайте «сломаем» наш тест и запустим jest повторно:

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

Теперь давайте разберём код самого теста. Функция test используется для создания нового теста. Она принимает три аргумента (в примере мы использовали вызов с двумя аргументами). Первый — строка с названием теста, его jest отобразит в отчете. Второй — функция, которая содержит логику нашего теста. Также можно использовать 3-й аргумент — таймаут. Он является не обязательным, а его значение по умолчанию составляет 5 секунд. Задаётся в миллисекундах. Этот параметр необходим когда мы работаем с асинхронным кодом и возвращаем из функции теста промис. Он указывает как долго jest должен ждать разрешения промиса. По истечению этого времени, если промис не был разрешен — jest будет считать тест не пройденным. Подробнее про работу с асинхронными вызовами будет в следующих частях. Также вместо test() можно использовать it(). Разницы между такими вызовами нету. it() это просто алиас на функцию test().

Внутри функции теста мы сначала вызываем expect(). Ему мы передаем значение, которое хотим проверить. В нашем случае, это результат вызова Math.max(1, 5, 10). expect() возвращает объект «обертку», у которой есть ряд методов для сопоставления полученного значения с ожидаемым. Один из таких методов мы и использовали — toBe.

Давайте разберем основные из этих методов:

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

Далее добавим тесты:

В этих тестах мы проверили результат работы 2-х методов — area и circumference. При помощи метода toBeCloseTo мы сверились с ожидаемым результатом. В первом случае мы проверили или вычисляемая площадь круга с радиусом 5 приблизительно равна 78.54, при этом разница с полученым значением (оно составит 78.53981633974483) не большая и тест будет засчитан. Во втором мы указали, что нас интересует проверка с точностью до 1 знака после запятой. Также мы вызвали наши методы без аргументов и проверили результат с помощью toBeNaN. Поскольку результат их выполнения будет NaN, то и тесты будут пройдены успешно.

Разберём ещё один пример. Создадим функцию, которая будет фильтровать массив продуктов по цене:

В этом тесте мы проверям результат работы функии byRangePrice. Сначала мы проверили соответствие длины полученого массива ожидаемой — 2. Следующая проверка требует, чтобы в массиве находился элемент — < name: 'tomato', price: 26 >. Объект в массиве и объект переданный toContainEqual — это два разных объекта, а не ссылка на один и тот же. Но toContainEqual сверит каждое свойство. Так как оба объекта идентичные — проверка пройдет успешно. Далее мы используем toEqual для провеки структуры всего массива и его элементов. Методы toBeGreaterThanOrEqual и toBeLessThanOrEqual помогут нам проверить price первого и второго элемента массива. И, наконец, вызов not.toContainEqual сделает проверку, не содержится ли в массиве элемент — < name: 'orange', price: 38 >, которого по условию там быть не должно.

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

Источник

Как и какими средствами находить ошибки в Javascript коде?

Частенько, при разработке, код не работает так, как задумано или вообще не работает. Сижу часами, гадаю: что и где не так?

А порой просто иду на проф. ресурсы, например Stack Overflow и публикую вопрос «Где здесь ошибка?» или «Почему не работает?»

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

Вопрос: какие есть способы, чтобы найти ошибки в Javascript коде? Какие инструменты, методы, плагины, пути и пр.?

как проверить javascript код

4 ответа 4

Вчера всё работало, а сегодня не работает / Код не работает как задумано

Debugging (Отладка)

В чем заключается процесс отладки? Что это такое?

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

Будет рассмотрен пример с Сhrome, но отладить код можно и в любом другом браузере и даже в IDE.

как проверить javascript код

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

А во вкладке Breakpoints можно:

Запускаем отладку

В данном случае, т.к. функция выполняется сразу при загрузке страницы, то для активации отладчика достаточно её перезагрузить. В ином случае, для активации требуется исполнить действие, при котором произойдет исполнение нужного участка кода (клик на кнопку, заполнение инпута данными, движение мыши и другие действия)

В данном случае после перезагрузки страницы выполнение «заморозится» на 4 строке:

как проверить javascript код

В Local показываются переменные функции: объявленные через var и параметры. В Global – глобальные переменные и функции.

Процесс

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

как проверить javascript код ( F8 ) — продолжить выполнение. Продолжает выполнения скрипта с текущего момента. Если больше нет других точек останова, то отладка заканчивается и скрипт продолжает работу. В ином случае работа прерывается на следующей точке останова.

как проверить javascript код ( F10 ) — делает один шаг не заходя внутрь функции. Т.е. если на текущей линии есть какая-то функция, а не просто переменная со значением, то при клике данной кнопки, отладчик не будет заходить внутрь неё.

как проверить javascript код ( F11 ) — делает шаг. Но в отличие от предыдущей, если есть вложенный вызов (например функция), то заходит внутрь неё.

как проверить javascript код ( Shift+F11 ) — выполняет команды до завершения текущей функции. Удобна, если случайно вошли во вложенный вызов и нужно быстро из него выйти, не завершая при этом отладку.

как проверить javascript код — отключить/включить все точки останова

как проверить javascript код — включить/отключить автоматическую остановку при ошибке. Если включена, то при ошибке в коде он скрипт остановится автоматически и можно посмотреть в отладчике текущие значения переменных, проанализировать и принять меры по устранению.

Итак, в текущем коде видно значение входного параметра:

как проверить javascript код

Дальнейшие нажатия F10 переместит линию кода на строки 11, 12 и, наконец, 15.

Дополнительно

Остановку можно инициировать принудительно без всяких точек останова, если непосредственно в коде написать ключевое слово debugger :

Если нажать ПКМ на строке с брейкпойнтом, то это позволит еще более тонко настроить условие, при котором на данной отметке надо остановиться. В функции выше, например, нужно остановиться только когда sum превысит значение 20.

как проверить javascript код

Это удобно, если останов нужен только при определённом значении, а не всегда (особенно в случае с циклами).

Больше информации о возможностях инструментов например Chrome — можно прочитать здесь

Дополнительно 2

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

Пример для Chrome:

как проверить javascript код

Для Firefox:

Если функция инлайновая, например

то можно зайти в Инспектор, найти тот самый элемент, в котором прописано событие и обнаружить рядом значок em :

как проверить javascript код

Кликнув на него, как утверждает developer.mozilla.org/ru/docs можно увидеть строчки:

как проверить javascript код

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

В других случаях, а также если кнопка паузы не обнаружена, то на вкладке Debugger (отладчик) надо найти стрелку, при наведении на которую будет написано «Events». Там должно быть событие выделенного элемента.

А вот таких полезных вкладок как у Chrome к сожалению у Firefox там нет.

Источник

[в закладки] Инструменты для тестирования JavaScript-проектов

Автор материала, перевод которого мы публикуем сегодня, сотрудник Welldone Software, говорит, что если в двух словах рассказать об инструментах для тестирования JavaScript-проектов, то для модульного и интеграционного тестирования рекомендуется использовать Jest, а для тестов пользовательского интерфейса — TestCafe. Однако каждый конкретный проект может нуждаться в чём-то особенном. Лучший способ найти именно то, что нужно — взять несколько инструментов, которые, как кажется, подойдут, и испытать их в действии. Эксперименты подскажут — на чём именно стоит остановиться.

как проверить javascript код

Представляем вашему вниманию обзор наиболее широко используемых инструментов тестирования для JS-проектов, на которые стоит обратить внимание в 2018-м году.

Инструменты тестирования общего назначения

▍Jsdom

Jsdom — это JavaScript-реализация WHATWG DOM и стандартов HTML. Другими словами, jsdom имитирует окружение браузера, не выполняя ничего кроме обычного JS.

В подобном окружении тесты могут выполняться очень быстро. Минус jsdom заключается в том, что не всё можно симулировать за пределами реального браузера (например, при таком подходе не получится делать скриншоты), поэтому использование данного средства ограничивает возможности тестирования.

Стоит упомянуть, что сообщество JS интенсивно работает над jsdom и совершенствует этот инструмент. Возможности его текущей версии очень близки к настоящему браузеру.

▍Istanbul

Инструмент Istanbul позволяет анализировать покрытие кода модульными тестами. Он выводит детальные отчёты, ориентируясь на которые можно получить точное представление о том, что в проекте ещё не протестировано, и оценить объём работ, необходимый для улучшения ситуации.

▍Karma

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

Chai — это самая популярная библиотека для создания утверждений.

▍Unexpected

Unexpected — это библиотека для создания утверждений, синтаксис которой немного отличается от Chai. Кроме того, эта библиотека расширяема, что позволяет создавать более продвинутые утверждения. В частности, речь идёт об использовании библиотек, основанных на unexpected, например таких, как unexpected-react, подробности о которой можно почитать здесь.

▍Sinon.JS

Sinon.JS представляет собой мощную автономную систему, предоставляющую возможность выполнять тестирование JavaScript-проектов с использованием так называемых шпионов (spy), заглушек (stub) и имитаций (mock). Эта система умеет работать с любыми фреймворками для модульного тестирования.

▍Testdouble.js

Testdouble.js — это менее популярная библиотека, выполняющая те же функции, что и Sinon, при этом её разработчики говорят о том, что она решает похожие задачи лучше, чем Sinon. Она отличается набором возможностей, некоторыми особенностями архитектуры и подходом к тестированию, что может сделать её полезной во многих ситуациях. Подробности о testdouble можно почитать здесь, здесь и здесь.

▍Wallaby

Wallaby — это ещё один инструмент, достойный упоминания. Он не бесплатен, но многие пользователи полагают, что он стоит тех денег, что за него просят. Wallaby работает в IDE (поддерживаются все основные IDE) и выполняет тесты, соответствующие изменениям кода. Данные о результатах тестирования выводятся в реальном времени там же, где находится код.

как проверить javascript код
Wallaby

▍Cucumber

Cucumber помогает разработчикам с написанием тестов в BDD. Тесты разделены между файлами критериев приемлемости, подготовленных с использованием синтаксиса Gherkin, и собственно файлами тестов, которые им соответствуют. Тесты могут быть написаны на различных языках, которые поддерживает фреймворк, в том числе и на JS.

Вот пример файла like-article.feature :

Вот пример файла like-article.steps.js :

Многие команды находят этот синтаксис более удобным, чем TDD.

Фреймворки для модульного и интеграционного тестирования

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

▍Mocha

Mocha в настоящий момент является самой широко используемой библиотекой. В отличие от библиотеки Jasmine, о который мы ещё поговорим, эта библиотека применяет сторонние инструменты для построения утверждений и внешние средства для создания имитаций и функций-шпионов (обычно Enzyme и Chai). Это означает некоторые дополнительные сложности при настройке Mocha, и то, что получаемый функционал будет разделён между различными библиотеками, но этот фреймворк более гибок и расширяем в сравнении с Jasmine.

Например, если вам нужна особая логика утверждений, вы можете сделать форк Chai и заменить только Chai в своём наборе инструментов вашей собственной библиотекой для создания утверждений. Это можно сделать и в Jasmine, но в Mocha это изменение будет более очевидным.

Вот некоторые особенности Mocha, на которые стоит обратить внимание:

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

Стоит отметить, что после анализа огромного количества материалов о Jest, мы можем сделать вывод о том, что многие разработчики впечатлены скоростью и удобством этого фреймворка. Среди особенностей Jest можно отметить следующие:

▍Jasmine

Jasmine — это фреймворк для тестирования, на котором основан Jest. Если есть Jest — кому может понадобиться Jasmine? Всё дело в том, что Jasmine появился раньше, чем Jest, по нему имеется огромное количество публикаций, для него создано множество инструментов.

Кроме того, создатели Angular всё ещё советуют использовать именно Jasmine, а не Jest, хотя и Jest отлично подходит для выполнения тестирования Angular-проектов, и многие пользуются им для этого. Вот основные особенности Jasmine:

Ava — это минималистичная библиотека для тестирования, поддерживающая параллельное выполнение тестов. Вот её основные характеристики:

Tape — это самый простой из рассматриваемых здесь фреймворков для тестирования, имеющий небольшое и понятное API. Это — обычный JS-файл, который работает в Node.js. Вот основные характеристики tape:

Средства тестирования пользовательского интерфейса

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

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

▍Selenium

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

Возможностями Selenium можно управлять различными способами, используя множество языков программирования, а применение некоторых инструментов позволяет работать с Selenium и вовсе без программирования.

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

WebDriver можно импортировать в выбранный фреймворк для тестирования. Тесты можно писать с использованием возможностей по управлению браузером:

Кстати, и самого WebDriver может быть вполне достаточно для выполнения тестов. Встречаются рекомендации, авторы которых советуют использовать WebDriver в его исходном виде.

Однако, тут нельзя не учитывать то, что существуют библиотеки, расширяющие возможности WebDriver, представленные либо его форками, либо обёртками для него.

Минусы библиотек-обёрток заключаются в том, что они усложняют систему. В появлении форков плохо то, что усилия, затраченные на них, вполне могли бы быть вложены в разработку самого WebDriver.

Однако, если говорить о Selenium, многие предпочитают не использовать его напрямую. Взглянем на некоторые библиотеки, использующие возможности Selenium.

Appium

Appium предоставляет API, похожее на API Selenium. Этот фреймворк предназначен для организации тестирования мобильных проектов с использованием следующих инструментов:

Protractor

Protractor — это библиотека-обёртка для Selenium, которая ориентирована на Angular. Вот основные особенности этой библиотеки:

WebdriverIO

WebdriverIO предлагает собственный подход к использованию функционала Selenium WebDriver. Эта библиотека предназначена для Node.js. Среди особенностей этого проекта можно выделить следующие:

Nightwatch

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

▍TestCafe

TestCafe является отличной альтернативой инструментам, основанным на Selenium. Код этой библиотеки был открыт в конце 2016-го года. Надо отметить, что всё ещё существует платная версия TestCafe, которая предлагает средства для тестирования, не требующие программирования. Например — это инструменты для записи тестов. В рамках платной версии предлагается и поддержка пользователей. Надо отметить, что существует множество устаревших публикаций, которые вышли до открытия кода библиотеки и считают закрытый код её недостатком.

TestCafe внедряется в страницы в виде JS-скрипта, она не контролирует браузер, как это делает Selenium. Это позволяет TestCafe выполняться в любых браузерах, включая мобильные, и иметь полный контроль над тем, что происходит в JavaScript.

Библиотека TestCafe написана на JavaScript и ориентирована на тестирование. Она в настоящее время бурно развивается, хотя уже сейчас считается стабильной и имеющей достаточное количество возможностей. Рассмотрим её основные особенности:

▍Cypress

Cypress — это прямой конкурент TestCafe. Этот фреймворк работает практически так же, внедряя тесты в код страниц, но он пытается делать это более современным, гибким и удобным способом. Cypress новее, этот фреймворк недавно перешёл из стадии закрытой бета-версии в общедоступную бета-версию (в октябре 2017), но многие уже им пользуются. Вот основные особенности Cypress:

▍Puppeteer

Puppeteer — это библиотека для Node.js, которую разработала Google. Она предоставляет удобное Node.js API для управления браузером Chrome без пользовательского интерфейса.

Стоит сказать, что браузер Firefox также, в конце 2017-го, был выпущен с поддержкой работы в режиме без пользовательского интерфейса.

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

Среди основных особенностей Puppeteer можно отметить следующие:

▍PhantomJS

PhantomJS использует движок Chromium для создания управляемого браузера без пользовательского интерфейса, похожего на Chrome.

С момента появления Puppeteer создатель PhantomJS, Виталий Слободин, прекратил работу над ним, в результате все процессы в сфере PhantomJS, с середины 2017, замедлились, хотя тут всё ещё наблюдается какое-то движение.

В каких ситуациях можно отдать предпочтение PhantomJS, если существует Puppeteer? Рассмотрим некоторые из них:

▍Nightmare

Nightmare — это отличная библиотека для тестирования пользовательского интерфейса, которая отличается очень простым синтаксисом тестов.

Nightmare использует Electron, что делает эту библиотеку похожей на PhantomJS, однако, тут применяется более новая версия Chromium и библиотека активно поддерживается и разрабатывается. Этому способствует и тот факт, что главная цель проекта Electron, который так же динамично развивается, заключается в создании кросс-платформенных настольных приложений на базе JavaScript, HTML и CSS.

Кроме того, сейчас ведутся обсуждения и производятся эксперименты, направленные на применение в Nightmare Chrome без пользовательского интерфейса. Взглянем на код тестов на Nightmare в сравнении с кодом на PhantomJS.

Вот код тестов на Nightmare:

Вот код тестов на PhantomJS:

▍Casper

Casper — это средство, созданное на основе PhantomJS и SlimerJS (это то же самое, что и Phantom, но тут используется Firefox Gecko). Casper позволяет имитировать взаимодействие пользователя с веб-страницами, даёт возможность написания скриптов и тестовых механизмов в абстрактном виде, поддерживает асинхронные возможности при создании скриптов для Phantom и Slimer.

Библиотека Slimer получила широкое распространение, хотя и считалась экспериментальной. В конце 2017-го года была выпущена её бета-версия, 1.0.0-beta.1, которая использует новый Firefox без пользовательского интерфейса. В настоящее время ведётся работа по устранению мелких недочётов и по выпуску первого релиза Slimer.

Возможно, в ближайшем будущем, с выходом второго релиза, Casper перейдёт с PhantomJS на Puppeteer и станет отличным инструментом для тестирования и в среде Chrome, и в среде Firefox. Полагаем, за этим проектом стоит понаблюдать.

▍CodeceptJS

CodeceptJS, как и рассмотренный выше CucumberJS, предоставляет дополнительный уровень абстракции над различными библиотечными API. Всё это направлено на то, чтобы разработчик взаимодействовал с тестами, основываясь на сценариях поведения пользователей.

Вот как выглядит работа с CodeceptJS:

А вот некоторые библиотеки, которые могут быть задействованы при выполнении этого кода: WebDriverIO, Protractor, Nightmare, Appium, Puppeteer. О них мы уже говорили.

Если вам кажется, что представленный выше синтаксис соответствует вашим нуждам, советуем опробовать CodeceptJS.

Итоги

Мы рассмотрели наиболее популярные инструменты тестирования веб-проектов. Что именно подойдёт для вас? Пожалуй, тут можно сказать, что лучшие архитектурные решения в сфере современных веб-приложений представляют собой комбинацию общих, проверенных временем шаблонов, выработанных сообществом разработчиков, и особенностей конкретного приложения. А найти то, что нужно для конкретного проекта, можно только одним способом: испытать всё, что кажется подходящим, на практике.

Уважаемые читатели! Чем вы пользуетесь для тестирования ваших JS-проектов?

Источник

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

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