Как обновить hermione до версии 4.x
Данный рецепт актуален только для тех проектов, которые используют hermione младше 4-й версии.
Почему стоит обновиться?
Когда-то очень давно hermione перешла на «временный» форк пакета webdriverio@4 (сокр. wdio), который она использовала «под капотом», т. к. проблемы во внешнем wdio тормозили её разработку: постоянные баги в wdio, разногласия относительно вносимых изменений и т. п. И если сначала форк регулярно обновлялся командой hermione, чтобы предоставить пользователю актуальную функциональность, то со временем форк значительно отстал от текущей версии wdio во внешнем мире.
К тому времени во внешнем мире в wdio уже появилось много различных фич, которые интересны разработчикам: Chrome DevTools Protocol (CDP), стабы внешних запросов, расширенные возможности работы с мобильными устройствами и т. п. Поэтому у команды hermione не осталось выбора: нужно было отказываться от форка webdriverio@4 и переходить на самую актуальную версию webdriverio@7.
Сейчас уже доступна 8-я версия webdriverio и hermione@7 уже использует её.
Кроме этого, пользователям становилось всё неудобнее пользоваться устаревшими командами: тайпинги приходилось подключать из отдельного пакета (в новом wdio они поставляются из коробки), за документацией по командам приходилось ходить на старый сайт, в то время как некоторые пользователи иногда заходили на актуальную страницу и не могли понять, почему команды из документации не работают в hermione.
Таким образом, причин для радикального апгрейда — сразу на 3 мажора вверх — накопилось достаточно.
Что изменилось?
Изменений очень много, поэтому ниже будут перечислены только самые важные / интересные из них.
API команд
async/await вместо чейнинга
В новой версии теперь нельзя писать тесты, используя chaining. Доступен только async/await-синтаксис:
- Было
- Стало
it('some test', function() {
return this.browser
.foo()
.bar()
.baz();
});
it('some test', async function() {
await this.browser.foo();
await this.browser.bar();
await this.browser.baz();
});
А начиная с версии hermione@4.9.0 можно писать тесты ещё короче, так как hermione теперь передает в функцию объект с полем browser
:
it("some test", async function ({ browser }) {
await browser.foo();
await browser.bar();
await browser.baz();
});
Далее в примерах «Стало» мы будем везде предполагать, что речь идет о hermione с версией не меньше, чем 4.9.0. Если по какой-то причине вы планируете использовать версию hermione 4+ младше 4.9.0, то к браузеру в тестах нужно обращаться как и раньше — через this, например: await this.browser.getText('.selector').
Результат вместо объекта с ключом value
Теперь при получении результатов команд вместо объекта с ключом value
возвращается реальный результат (старое поведение часто приводило к ошибкам в тестах):
- Было
- Стало
it('some test', async function() {
const { value } = await this.browser.getText('.selector');
console.log(value); // some text
});
it('some test', async function({ browser }) {
const text = await browser.getText('.selector');
console.log(text); // some text
});
Работа с элементами напрямую
С помощью команды browser.$
можно получить инстанс найденного элемента и работать с ним в тесте. Это удобно, когда с элементом нужно взаимодействовать больше одного раза (при этом элемент не будет повторно искаться на странице):
- Было
- Стало
it('some test', async function() {
await this.browser.clearElement('.input');
await this.browser.setValue('.input', 'text');
});
it('some test', async function({ browser }) {
const elem = await browser.$('.input');
await elem.clearElement();
await elem.setValue('text');
});
Смотрите также команды:
Передача аргументов через объект
Для многих команд аргументы теперь передаются с помощью объекта с понятными ключами вместо последовательной передачи аргументов, в которых было очень легко запутаться. Например, в команде waitForExist, в которой в качестве аргументов раньше передавались даже булевые значения:
- Было
- Стало
it('some test', async function() {
await this.browser.waitForExist('.selector', 1000, true);
});
it('some test', async function({ browser }) {
const elem = await browser.$('.selector');
await elem.waitForExist({
timeout: 1000,
interval: 500,
reverse: true,
timeoutMsg: 'still exists'
});
});