Производить проверку браузера, исходя из строки агента, не рекоммендуется — современным методом является feature discovery — к примеру, вариант для ES6, но это даже не столь существенно
Самое главное — такое решение плохо сочетается с самой идеей bundle-ирование клиентского кода. Конечно, можно загрузить предложенную библиотеку как статику и добавить в externals, но тогда bundle все равно или будет целиком содержать излишний исходный код, или требовать условной сборки, зависимой от клиентского агента.
Или babel-polyfill, если зависимости собираются webpack-ом и поставляются на клиент в виде bundle-а? Окей, но скорее всего нет, поскольку есть один важный аспект — вопросы оптимизации, включая объем трафика для bundle-а и вычислительные ресурсы для выполнения на клиенте.
Применение единого bundle-а со всеми polyfills и transpile-кодом на современных браузерах приводит к существенному оверхэду, поэтому рекоммендуется разворачивать отдельный bundle для современных клиентских агентов (раз, два).
Условно все относительно-современные браузеры поддеривают ES6, и для них может приозводиться доставка непосредственно ES6-кода. Для старых браузеров можно применять polyfills, transpile-ить код, или вообще просить пользователя обновиться для просмотра ресурса — это вопрос отдельный.
Теперь если взять все браузеры с ES6, то часть из них, включая IE11, Smart TV, Tizen, не поддерживают ES7, но отлично понимают ES6. Если вспомнить соответствующую спецификацию комитета TC39, то 6-ая версия включает всего два изменения — оператор возведения в степень и includes. ВСЁ.
Исходя из этого вопрос — имеет ли смысл заморачиваться с отдельным bundle-ом с polyfills и transpile-ингом с уровня ES7 до ES6 (*), по сути ради одной единственной функции, которая чуть менее, чем на 100% — всего лишь синтаксический сахар для arr.indexOf(value) > 0? Настраивать развертывание, кеширование отдельного bundle-а, отдельные функциональные тесты на каком-нибудь SauseLabs, ради одной малополезной функции?
(*) При условии, что такое легко реализовать; babel по умолчанию, вроде бы, так не умеет, так что задача приобретает еще один виток сложности
Если говорить об ES6 то почему бы не использовать Array.prototype.includes вместо вот этого
Безотносительно ко всей статье, но именно includes в некоторым смысле вредная штука — способ выкинуть поддержку как минимум IE11 и Samsung TV browser на пустом месте
Если синтаксические конструкции ES7+ легко раз-babel-иваются, а для ES6-функционала polyfills во всех современных браузерах не нужны и по умолчанию их давно уже никто не включает в bundle-ы, то includes — фактически единственное исключение и способ нажить неудобства при deployment-е
А теперь тоже самое для статичных (выделяемых в стеке) фукнций.
Имеются в виду функции, использующие переменные из activation object, то бишь замыкания? Они такие же объекты с похожим жизненным циклом, так что отлавливать и подсчитывать ссылки на объекты из activation object проблем нет.
Еще раз — потенцаильная сложность это функции из host object, типа DOM-модели, но это тоже обходится в transpile-фазе
но компилятор… все еще ждем
Это вопрос к автору статьи, к которому я никакого отношения не имею. Это лишь ответ на вопрос о том, что при должной сноровке поддерживать деструкторы в ES262 не представляется проблемой
Основная сложность в том, что придется обернуть взаимодействие с native и host-object-функциями, которые также могут хранить внутри себя ссылку на объекты — да, это объемная работа, но вполне реализуемая.
Сама по себе идея разрабатывать части web-приложения на C/C++ далеко не новая — другое дело, какой результат вы хотите получить от такого подхода? Возможно, вам будет интересно ознакомиться с WASM: http://webassembly.org/docs/c-and-c++/
Да, без качественных автоматических функциональных тестов хорошее сложное web-приложение не сделать.
Однако у оригинального Selenuim-а два недостатка: отличие языка тестов от языка клиентского кода и необходимость наличия webdriver-а для целевого браузера. И если первый недостаток давно решен в библиотеках Webdriver.io, Nightwatch, и тому подобное, позволяя писать на том же ECMA-262 ver 6+, то со вторым недостатком никаких подвижек нет.
В частности, учитывая обилие устройств, как проверить работоспособность на всевозможных смартфонах, Smart TV и тому подобное. В этом плане TestCafe нет равных, или связке TestCafe + SauceLabs — на случай если у вас нет фермы живых устройств для прогона тестов
Да, наверное можно получше сформулировать. Форма и значения в том или ином объекте могут стать известны только в runtime-фазе, например, когда прочли request body в HTTP-запросе и инстанцировали из него объект посредством JSON.parse — по сути преобразование из произвольного string в произвольный plain object.
Каждое из полей может быть null, undefined или чем угодно, но эта станет известно только в фазе выполнения. Есть такая штука как tcomb — это да, может помочь.
Опять-таки самая ближайшая аналогия из строго-типизированного языка, C#, это по типу:
dynamic excel = Interop.create("Excel.Workbook");
dynamic book = excel.Workbook[0];
book.Activate();
Одно из самых распространенных заблуждений состоит в том, что статическая типазация, или новомодные обертки для ее эмуляции в виде ES-Flow, могут помочь побороть ошибку undefined is not a function, но на деле это невозможно сделать в статическом анализе.
Аналогичный примерчик на C#. В общем-то проблема в Nullable объектах, а не то, что часто принято приводить в качестве аргумента
Теоретически можно заимплементить плагин для prettier-а, но это решает очень узкую задачу — выявление опечаток в именах подключаемых модулей, заданных в виде строковых констант. А если require(vasya${petya}) ?
Многие остальные вещи становятся известными только в runtime-фазе, так что ни EsLint, ни Flow тут не помощники. Поэтому если уж заморачиваться, то нужна более тяжелая артиллерия.
И еще раз важная заметочка: подобная задача вполне имеет место в динамическом анализе кода и функциональном тестировании. Есть как минимум:
Задачи ооочень нетривиальные в общем случае. К примеру, довольно проблемно перехватить сгенерированный script-блок из DOM-манипуляций, чтобы выполнить предварительную обертку.
Сейчас доступ только из отладчика по скрытому свойству [[Scope]]. Подозреваю, что для node.js можно и сейчас получить доступ через V8 natives: https://www.npmjs.com/package/v8-natives, только надо с флажком будет запускать процесс
Правда, все ошибки перехватить всё равно не удастся
Если перехватить сами вызовы, которые могут генерировать новый код динамически тем или иным образом, начиная от new Function и заканчивая манипуляциями с DOM Node и создания новых script-секций, то вполне возможно
Подобная техника, правда не для шутки, а функционального тестирования, применяется в TestCafe: https://github.com/DevExpress/testcafe-hammerhead
Очень неплохо! Правда есть и недостатки, например имена лексических переменных с очепятками никак не перехватываются, да и синтактические ошибки по-прежнему актуальны. Так что нужно сделать babel-плагин, который будет выполнять пред-обработку и учитывать опечатки во всех сущностях.
В движке Fiber проблема производительности уже неактуальна
React требует сложного асинхронного программирования при общении с сервером
Напротив, в связке с Redux весь код бизнес-логики на клиенте может быть сведен в единое место, представляемое одним или несколькими комбинированными reducer-ами. Продолжительные по времени действия легко описать в sagas, а еще лучше реализовать всю архитектуру через events — в таком случае явные асинхронные вызовы вообще не нужны
Даже используя propType React сможет найти ошибки только во время работы программы, а не во время компиляции.
Если нужна статическая проверка, можно использовать Flow
Поддерживает ли Binding.scala серверный rendering?
асинхронный node.js и бороться с ним с помощью await'ов
А причем здесь, собственно, node.js? Это же клиентский EcmaScript-код, который с версии ES2017 вообще будет поддерживать это нативно. Ваше web-приложение асинхронно само по себе, а это инструмент для организации цепочки действий
общий уровень "велосипедизма".… повсеместно используемых setUp/tearDown, тут beforeEach/afterEach
В современном web-е это принятая терминология, смотрите Ava, Jest, Mocha и так далее.
Короче, что люди не делают, только бы не брать selenium
Короче, что люди не делают, только бы не разрабатывать на C++; придумали всякие интерпретаторы, динамические типизации и другие синтаксические сахара.
Под капотом, вероятнее всего, всё тот же вебдрайвер
Нет, там действительно совершенно иной принцип, со своими достоинствами и недостатками. Матчасть можно почитать в моей статье на эту тему, там же сравнение этих тестовых фреймворков
Если смириться с JS синтаксисом
Выбор языка это конечно вкусовщина, но исторически сложилось, что все современные браузеры работают на ES-262, а реализовывать функциональный тест на том же языке, что и тестируемое приложение — IMHO довольно удобно
Весь вопрос в том, какую технологию вы используете на серверной части разрабатываемого/поддерживаемого web-приложения. Если node.js, то очевидно в случае TestCafe не надо устанавливать еще один инструмент, если JSP или что-то подобное, то выбор в сторону семейства Selenuim (Webdriver, nightwatch, etc).
Если PHP, Perl, Ruby или что-то еще, то вопрос с такой стороны рассмотрения открытый, но ES6/7 это все-таки тот язык, который исполняется в браузере, и писать функциональный тест писать на нем IMHO значительно удобнее, чем на Java.
Безусловно, описанная в статье ситуация с XHTML довольно проблематичная, но скорее в идеологическом плане, поскольку технически те или иные задачи все-таки можно решить. Дело в том, что исторически направления XHTML и CSS selectors развивались параллельно, о чем как минимум свидетельствует наличие двух конкурентных языков для выбора элементов документа — XPath и CSS selector, при этом оба успешно применяются в сфере автоматизации web-приложений и функциональном тестировании, в том же Nightwatch-е к примеру.
Далее по техническим вопросам. Во-первых, навигацию по XHTML лучше реализовывать посредством XPath, который изначально как раз предназначен для XML-документов, и поддерживается посредством функции document.evaluate(), по крайней мере в браузерах, приведенных автором статьи в последней таблице. Для IE старых версий тоже нет проблем, можно использовать объект new ActiveXObject("Msxml2.DOMDocument"), за-map-енный на текущее DOM-дерево, пример решения можно взять здесь https://sourceforge.net/projects/html-xpath/
Это имеет свой смысл, поскольку в общем случае CSS и уж тем более CSS selectors являются чужеродными для произвольных XML-элементов, которые не обязаны ни поддерживать стили, ни иметь какой-то внешний вид для отображения — который должен по-хорошему определяться через XSLT-преобразование (Или, если интересует поддержка IE старых версий, через Element Behaviors, во времена которых как раз задумывался XHTML с определением пользовательского поведения элементов — https://msdn.microsoft.com/en-us/library/ms531426(v=vs.85).aspx).
Во-вторых, с учетом современных тенденций в web-приложениях, включающую предварительное преобразование исходного кода в связке webpack + babel, можно сделать свою реализацию для resolve-а и transform-а исходного XHTML-кода, по аналогии с тем же JSX, который в итоге преобразования будет предоставлять набор элементов с некоторыми идентификаторами и классами, а исходный код будет выглядеть так, как задумал автор — с пространствами имен XHTML.
Резюмируя по исходной задаче, решения можно добиться без polyfills, правда потребуется две версии dist-клиентского сценария — для современных браузеров через document.evaluate(), и если захотите поддержку IE старых версий — то через Element Behaviors API, которое кстати поддерживает о-о-о-очень широкую функциональность.
К тому же под Nightwatch есть очень и очень много разнообразных примочек и фишек
Для TestCafe вы просто пишите ES6-код, и можете использовать множество различных библиотек в import-е под свои надобности, причем в selenium-е какие-то сторонние вещи интегрировать в код теста придется через эту функцию, то в TestCafe это обычный код — в таком смысле, возможности по интеграции куда шире.
Асинхронные комманды выполняются с помощью функции .executeAsync()
Безусловно! Однако этот функционал предоставляет значительно большие возможности. Да и promise / async-based стиль выглядит более читаемым, хотя наверное это уже дело вкуса.
Производить проверку браузера, исходя из строки агента, не рекоммендуется — современным методом является feature discovery — к примеру, вариант для ES6, но это даже не столь существенно
Самое главное — такое решение плохо сочетается с самой идеей bundle-ирование клиентского кода. Конечно, можно загрузить предложенную библиотеку как статику и добавить в externals, но тогда bundle все равно или будет целиком содержать излишний исходный код, или требовать условной сборки, зависимой от клиентского агента.
Или
babel-polyfill
, если зависимости собираютсяwebpack
-ом и поставляются на клиент в виде bundle-а? Окей, но скорее всего нет, поскольку есть один важный аспект — вопросы оптимизации, включая объем трафика для bundle-а и вычислительные ресурсы для выполнения на клиенте.Применение единого bundle-а со всеми polyfills и transpile-кодом на современных браузерах приводит к существенному оверхэду, поэтому рекоммендуется разворачивать отдельный bundle для современных клиентских агентов (раз, два).
Условно все относительно-современные браузеры поддеривают ES6, и для них может приозводиться доставка непосредственно ES6-кода. Для старых браузеров можно применять polyfills, transpile-ить код, или вообще просить пользователя обновиться для просмотра ресурса — это вопрос отдельный.
Теперь если взять все браузеры с ES6, то часть из них, включая IE11, Smart TV, Tizen, не поддерживают ES7, но отлично понимают ES6. Если вспомнить соответствующую спецификацию комитета TC39, то 6-ая версия включает всего два изменения — оператор возведения в степень и includes. ВСЁ.
Исходя из этого вопрос — имеет ли смысл заморачиваться с отдельным bundle-ом с polyfills и transpile-ингом с уровня ES7 до ES6 (*), по сути ради одной единственной функции, которая чуть менее, чем на 100% — всего лишь синтаксический сахар для
arr.indexOf(value) > 0
? Настраивать развертывание, кеширование отдельного bundle-а, отдельные функциональные тесты на каком-нибудь SauseLabs, ради одной малополезной функции?(*) При условии, что такое легко реализовать; babel по умолчанию, вроде бы, так не умеет, так что задача приобретает еще один виток сложности
Безотносительно ко всей статье, но именно includes в некоторым смысле вредная штука — способ выкинуть поддержку как минимум IE11 и Samsung TV browser на пустом месте
Если синтаксические конструкции ES7+ легко раз-babel-иваются, а для ES6-функционала polyfills во всех современных браузерах не нужны и по умолчанию их давно уже никто не включает в bundle-ы, то includes — фактически единственное исключение и способ нажить неудобства при deployment-е
Забавно, что приведенный Вами код с точностью до синтаксиса вообще не создает объект, а декларирует прототип функции в лексическом scope (См. https://en.wikipedia.org/wiki/Most_vexing_parse#Example_with_classes или вживую тут https://ideone.com/J3Y0oN )
Но в целом понятно, что Вы имели в вид
Имеются в виду функции, использующие переменные из activation object, то бишь замыкания? Они такие же объекты с похожим жизненным циклом, так что отлавливать и подсчитывать ссылки на объекты из activation object проблем нет.
Еще раз — потенцаильная сложность это функции из host object, типа DOM-модели, но это тоже обходится в transpile-фазе
Это вопрос к автору статьи, к которому я никакого отношения не имею. Это лишь ответ на вопрос о том, что при должной сноровке поддерживать деструкторы в ES262 не представляется проблемой
На платформе node.js решается очень легко — https://www.npmjs.com/package/weak и подобное
Для клиентской стороны немного сложнее, потребуется babel-плагин, осуществляющий обертку объектных сущностей — вроде таких https://www.npmjs.com/package/babel-plugin-source-wrapper или https://gist.github.com/IhostVlad/9310188edbdbc9f62dc3107417cc8fe4
Основная сложность в том, что придется обернуть взаимодействие с native и host-object-функциями, которые также могут хранить внутри себя ссылку на объекты — да, это объемная работа, но вполне реализуемая.
К тому же, большинство обертки и преобразования для DOM-модели уже решено здесь: https://github.com/DevExpress/testcafe-hammerhead/tree/master/src/processing
Сама по себе идея разрабатывать части web-приложения на C/C++ далеко не новая — другое дело, какой результат вы хотите получить от такого подхода? Возможно, вам будет интересно ознакомиться с WASM: http://webassembly.org/docs/c-and-c++/
Да, без качественных автоматических функциональных тестов хорошее сложное web-приложение не сделать.
Однако у оригинального Selenuim-а два недостатка: отличие языка тестов от языка клиентского кода и необходимость наличия webdriver-а для целевого браузера. И если первый недостаток давно решен в библиотеках Webdriver.io, Nightwatch, и тому подобное, позволяя писать на том же ECMA-262 ver 6+, то со вторым недостатком никаких подвижек нет.
В частности, учитывая обилие устройств, как проверить работоспособность на всевозможных смартфонах, Smart TV и тому подобное. В этом плане TestCafe нет равных, или связке TestCafe + SauceLabs — на случай если у вас нет фермы живых устройств для прогона тестов
Да, наверное можно получше сформулировать. Форма и значения в том или ином объекте могут стать известны только в runtime-фазе, например, когда прочли request body в HTTP-запросе и инстанцировали из него объект посредством JSON.parse — по сути преобразование из произвольного string в произвольный plain object.
Каждое из полей может быть null, undefined или чем угодно, но эта станет известно только в фазе выполнения. Есть такая штука как tcomb — это да, может помочь.
Опять-таки самая ближайшая аналогия из строго-типизированного языка, C#, это по типу:
Одно из самых распространенных заблуждений состоит в том, что статическая типазация, или новомодные обертки для ее эмуляции в виде ES-Flow, могут помочь побороть ошибку
undefined is not a function
, но на деле это невозможно сделать в статическом анализе.Аналогичный примерчик на C#. В общем-то проблема в Nullable объектах, а не то, что часто принято приводить в качестве аргумента
Теоретически можно заимплементить плагин для prettier-а, но это решает очень узкую задачу — выявление опечаток в именах подключаемых модулей, заданных в виде строковых констант. А если
require(
vasya${petya})
?Многие остальные вещи становятся известными только в runtime-фазе, так что ни EsLint, ни Flow тут не помощники. Поэтому если уж заморачиваться, то нужна более тяжелая артиллерия.
И еще раз важная заметочка: подобная задача вполне имеет место в динамическом анализе кода и функциональном тестировании. Есть как минимум:
Задачи ооочень нетривиальные в общем случае. К примеру, довольно проблемно перехватить сгенерированный script-блок из DOM-манипуляций, чтобы выполнить предварительную обертку.
Раньше можно было даже программно доступ получить через parent, потом убрали видимо из соображений чистого кода и безопасности/sandboxing-а. Можно почитать тут подробнее: http://whereswalden.com/2010/05/07/spidermonkey-change-du-jour-the-special-__parent__-property-has-been-removed/
Сейчас доступ только из отладчика по скрытому свойству [[Scope]]. Подозреваю, что для node.js можно и сейчас получить доступ через V8 natives: https://www.npmjs.com/package/v8-natives, только надо с флажком будет запускать процесс
Если перехватить сами вызовы, которые могут генерировать новый код динамически тем или иным образом, начиная от new Function и заканчивая манипуляциями с DOM Node и создания новых script-секций, то вполне возможно
Подобная техника, правда не для шутки, а функционального тестирования, применяется в TestCafe: https://github.com/DevExpress/testcafe-hammerhead
Очень неплохо! Правда есть и недостатки, например имена лексических переменных с очепятками никак не перехватываются, да и синтактические ошибки по-прежнему актуальны. Так что нужно сделать babel-плагин, который будет выполнять пред-обработку и учитывать опечатки во всех сущностях.
В движке Fiber проблема производительности уже неактуальна
Напротив, в связке с Redux весь код бизнес-логики на клиенте может быть сведен в единое место, представляемое одним или несколькими комбинированными reducer-ами. Продолжительные по времени действия легко описать в sagas, а еще лучше реализовать всю архитектуру через events — в таком случае явные асинхронные вызовы вообще не нужны
Если нужна статическая проверка, можно использовать Flow
Поддерживает ли Binding.scala серверный rendering?
Да, с принципом работы TestCafe, Вы можете хоть с утюга запускать функциональные тесты, если там есть браузер с поддержкой ES-262 и выходом в интернет
А причем здесь, собственно, node.js? Это же клиентский EcmaScript-код, который с версии ES2017 вообще будет поддерживать это нативно. Ваше web-приложение асинхронно само по себе, а это инструмент для организации цепочки действий
В современном web-е это принятая терминология, смотрите Ava, Jest, Mocha и так далее.
Короче, что люди не делают, только бы не разрабатывать на C++; придумали всякие интерпретаторы, динамические типизации и другие синтаксические сахара.
Нет, там действительно совершенно иной принцип, со своими достоинствами и недостатками. Матчасть можно почитать в моей статье на эту тему, там же сравнение этих тестовых фреймворков
Выбор языка это конечно вкусовщина, но исторически сложилось, что все современные браузеры работают на ES-262, а реализовывать функциональный тест на том же языке, что и тестируемое приложение — IMHO довольно удобно
Весь вопрос в том, какую технологию вы используете на серверной части разрабатываемого/поддерживаемого web-приложения. Если node.js, то очевидно в случае TestCafe не надо устанавливать еще один инструмент, если JSP или что-то подобное, то выбор в сторону семейства Selenuim (Webdriver, nightwatch, etc).
Если PHP, Perl, Ruby или что-то еще, то вопрос с такой стороны рассмотрения открытый, но ES6/7 это все-таки тот язык, который исполняется в браузере, и писать функциональный тест писать на нем IMHO значительно удобнее, чем на Java.
Безусловно, описанная в статье ситуация с XHTML довольно проблематичная, но скорее в идеологическом плане, поскольку технически те или иные задачи все-таки можно решить. Дело в том, что исторически направления XHTML и CSS selectors развивались параллельно, о чем как минимум свидетельствует наличие двух конкурентных языков для выбора элементов документа — XPath и CSS selector, при этом оба успешно применяются в сфере автоматизации web-приложений и функциональном тестировании, в том же Nightwatch-е к примеру.
Далее по техническим вопросам. Во-первых, навигацию по XHTML лучше реализовывать посредством XPath, который изначально как раз предназначен для XML-документов, и поддерживается посредством функции
document.evaluate()
, по крайней мере в браузерах, приведенных автором статьи в последней таблице. Для IE старых версий тоже нет проблем, можно использовать объектnew ActiveXObject("Msxml2.DOMDocument")
, за-map-енный на текущее DOM-дерево, пример решения можно взять здесь https://sourceforge.net/projects/html-xpath/Это имеет свой смысл, поскольку в общем случае CSS и уж тем более CSS selectors являются чужеродными для произвольных XML-элементов, которые не обязаны ни поддерживать стили, ни иметь какой-то внешний вид для отображения — который должен по-хорошему определяться через XSLT-преобразование (Или, если интересует поддержка IE старых версий, через Element Behaviors, во времена которых как раз задумывался XHTML с определением пользовательского поведения элементов — https://msdn.microsoft.com/en-us/library/ms531426(v=vs.85).aspx).
Во-вторых, с учетом современных тенденций в web-приложениях, включающую предварительное преобразование исходного кода в связке webpack + babel, можно сделать свою реализацию для resolve-а и transform-а исходного XHTML-кода, по аналогии с тем же JSX, который в итоге преобразования будет предоставлять набор элементов с некоторыми идентификаторами и классами, а исходный код будет выглядеть так, как задумал автор — с пространствами имен XHTML.
Резюмируя по исходной задаче, решения можно добиться без polyfills, правда потребуется две версии dist-клиентского сценария — для современных браузеров через
document.evaluate()
, и если захотите поддержку IE старых версий — то через Element Behaviors API, которое кстати поддерживает о-о-о-очень широкую функциональность.Для TestCafe вы просто пишите ES6-код, и можете использовать множество различных библиотек в import-е под свои надобности, причем в selenium-е какие-то сторонние вещи интегрировать в код теста придется через эту функцию, то в TestCafe это обычный код — в таком смысле, возможности по интеграции куда шире.
Безусловно! Однако этот функционал предоставляет значительно большие возможности. Да и promise / async-based стиль выглядит более читаемым, хотя наверное это уже дело вкуса.