How to Upgrade hermione to Version 4.x
This guide is relevant only for projects using hermione versions older than 4.x.
Why Should You Upgrade?
A long time ago, hermione switched to a "temporary" fork of the webdriverio@4 package (abbr. wdio) that it used "under the hood" because issues in the external wdio were slowing down its development: constant bugs in wdio, disagreements over changes, etc. Initially, the fork was regularly updated by the hermione team to provide users with up-to-date functionality, but over time, the fork significantly lagged behind the current version of wdio globally.
By the time many new features appeared in wdio that interested developers, such as Chrome DevTools Protocol (CDP), mocking external requests, extended mobile device capabilities, etc., the hermione team had no choice but to abandon the webdriverio@4 fork and switch to the latest version of webdriverio@7.
Version 8 of webdriverio is already available, and hermione@7 uses it.
Additionally, users found it increasingly inconvenient to use outdated commands: typings had to be included from a separate package (in the new wdio, they are included out of the box), and documentation for commands had to be accessed on the old site, while some users occasionally visited the current page and couldn't understand why the commands from the documentation didn't work in hermione.
Thus, there were plenty of reasons for a radical upgrade — jumping up by three major versions.
What Has Changed?
There are many changes, so only the most important/interesting ones will be listed below.
Command API
async/await Instead of Chaining
In the new version, you can no longer write tests using chaining. Only async/await syntax is available:
- Old
- New
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();
});
Starting from version hermione@4.9.0, you can write tests even shorter, as hermione now passes an object with a browser
field to the function:
it("some test", async function ({ browser }) {
await browser.foo();
await browser.bar();
await browser.baz();
});
In the "New" examples going forward, it is assumed that the hermione version is at least 4.9.0. If you plan to use hermione 4+ but at a lower version than 4.9.0, you should still access the browser in tests through this, for example: await this.browser.getText('.selector').
Direct Result Instead of Object with value Key
Now, instead of returning an object with a value
key, the actual result is directly returned from command results (old behavior often led to errors in tests):
- Old
- New
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
});
Direct Work with Elements
Using the browser.$
command, you can get an instance of the found element and work with it in the test. This is convenient when you need to interact with an element more than once (the element won't be searched again on the page):
- Old
- New
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');
});
Also see the commands:
Passing Arguments Through an Object
For many commands, arguments are now passed using an object with understandable keys instead of sequentially passing arguments, which could be very confusing. For example, in the waitForExist command, which previously accepted even boolean values as arguments:
- Old
- New
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'
});
});
Special Command for React
A bonus for those who are already using React — now you can use the browser.react$
and browser.react$$
commands to find specific react components on the page with certain states. Similar commands are available for elements as well — element.react$
and element.react$$
.
Also read the article on working with react components on the webdriverio website.
Example usage:
- Old
- New
it('some test', async function() {
// no special commands for working with react components :(
});
it('some test', async function({ browser }) {
const component = await browser.react$('MyComponent', {
props: { someProp: true },
state: 'some-state'
});
const result = await component.isDisplayed();
});
Up-to-Date Documentation
While hermione used the old version of webdriverio@4, users constantly had to be reminded that the documentation for all commands was located at a separate address: v4.webdriver.io/api.html. Now, descriptions of all webdriverio commands used by hermione can be found at the standard address: webdriver.io/docs/api.
In addition, we translated the descriptions of all commands into Russian and adapted all usage examples to hermione, since webdriverio uses its own runner and the examples in its documentation cannot be directly applied in hermione.
Tests Run Faster
You might not notice this speedup when running several tests locally, but it will be very noticeable with a large number of tests. The new commands work about 15% faster (assuming you have stopped using the old commands).
Easy Local Browser Testing
Previously, to run tests locally in your browser, you had to start selenium-standalone
and specify a magical gridUrl
to make things work in hermione. Now, it's much simpler: in the config, just specify the automationProtocol
option with the value devtools
:
// hermione.conf.js
module.exports = {
browsers: {
chrome: {
automationProtocol: 'devtools',
desiredCapabilities: {
// ...
}
}
},
// other hermione settings...
};
We also plan to add a separate button in the hermione GUI for switching to CDP mode to make it even easier.
- Currently, this is fully supported only in the Chrome browser. * Retaking screenshots in this mode should only be done for debugging, as browsers in the pipeline run under Linux, which means page rendering will differ and tests in the pull request will fail with diffs.
API for Network Request Stubbing
The new version provides the ability to stub or override the responses of your service. This is done using the mock.respond() command. You can also block URLs of external services.
Read more about all the features in the "How to Track and Intercept Network Requests and Responses" guide.
Currently, this functionality only works in Chrome DevTools Protocol (CDP) mode, which only works in Chrome and Firefox Nightly.
Browser Configuration in the Config
For browsers that support the W3C protocol, instead of the version
field, you need to specify browserVersion
. And additional options need to be prefixed with the browser's name:
- Old
- New
module.exports = {
browsers: {
'chrome-desktop': {
desiredCapabilities: {
browserName: 'chrome',
version: '75',
'chromeOptions': {
// ...
}
}
}
}
};
module.exports = {
browsers: {
'chrome-desktop': {
desiredCapabilities: {
browserName: 'chrome',
browserVersion: '75',
'goog:chromeOptions': { // for Chrome browser, prefix with 'goog'
// ...
}
}
}
}
};
Read more about vendor prefixes at this link.
The list of all available settings can be found in the specification.
How to Migrate?
We upgraded webdriverio by three major versions at once, so simply updating the hermione version in package.json
won't suffice. The main issues during migration are the absent chaining in tests and outdated test commands. To help you with these issues, we wrote the following guide.
1. Update hermione to 4+, Install Migrator Plugin and Codemod
Specifically:
- Update hermione to hermione@4.
- Install the hermione-wdio-migrator plugin for smooth command migration.
- Install the hermione-codemod package to convert existing tests to the new syntax.
You can do all this with one command:
npm install -D hermione@4 hermione-wdio-migrator hermione-codemod --save-exact
The versions of all hermione plugins (e.g., html-reporter) also need to be updated to the latest versions, as some may not work correctly with the new hermione version.
2. Run the Codemod for async/await
The codemod will regenerate your tests from chaining format to async/await format:
- zsh
- bash
If you use the zsh shell, you can pass test files as relative paths and as glob patterns, such as somefolder/**/*.js, and so on.
npx jscodeshift -t node_modules/hermione-codemod/transforms/browser-chaining-to-async-await.js path_to_file_mask
If you use the bash shell, globs won't work as easily as in zsh, so the command will be more complex if you need to process a group of files. For example:
npx jscodeshift -t node_modules/hermione-codemod/transforms/browser-chaining-to-async-await.js $(find ./somefolder -type f -iname '*.js' | xargs echo)
Upon successful completion, you will see a corresponding message:
Results:
0 errors
0 unmodified
0 skipped
251 ok
However, there can be cases the current codemod cannot handle. For such tests, an error with information about the problematic file will be displayed:
WARN: can't correctly transform ConditionalExpression, fix it manually
file: tests/hermione/suites/common/promotion-page/promotion-page.hermione.js
position: {"start":112,"end":116}
Such tests will need to be fixed manually. We tried to account for most test cases, so there shouldn't be too many of these instances.
After this, you can already merge your changes (this is optional) to perform the migration in parts. The async/await syntax will still work in wdio@4. Many services have been writing tests this way for a long time.
3. Run the Codemod to Remove value
Since command results now directly return the actual result instead of an object with a value
key, you need to change result handling in all tests. This codemod is intended for such cases.
The command is very similar to the previous one, only the path to the next codemod file changes:
npx jscodeshift -t node_modules/hermione-codemod/transforms/remove-browser-prop.js path_to_file_mask
For any warnings, problematic tests need to be fixed manually. For example, if a test uses value
multiple times through destructuring, the codemod will not handle it properly and generic variable names might be generated. For example:
// test on wdio@4:
it('test', function(){
return this.browser
...
.getText('.button')
.then((value) => {
assert.equal(value, 'Button', 'We need a button');
})
...
.getValue('.input')
.then((value) => {
assert.equal(value, 'Hello', 'We were not greeted');
});
});
// auto-generated for wdio@7 in this format:
it('test', async function() {
const value = await this.browser.getText('.button');
assert.equal(value, 'Button', 'We need a button');
...
// there will be an error due to reuse of the variable name,
// so the codemod will issue a warning about the problematic spot
const value = await this.browser.getValue('.input');
assert.equal(value, 'Hello', 'We were not greeted');
});
If your project has too many tests that cannot be automatically migrated, please reach out to github issues for help. We will analyze these errors and assist with the migration.
4. Add hermione-wdio-migrator to the hermione Config
This plugin "under the hood" simply adds the implementation of old commands using the new API, so during migration, you don't have to update tests yourself. Eventually, you should replace these deprecated commands with new ones in your tests:
module.exports = {
plugins: {
"hermione-wdio-migrator": {
enabled: true,
},
// other hermione plugins...
},
// other hermione settings...
};
5. Remove the Codemod
Uninstall the hermione-codemod package as you won't need it anymore.
npm uninstall hermione-codemod
6. Run Linters
Run linters on the modified tests, as the codemod might have violated your project's coding standards.
7. Run the Tests
Finally, ensure that all tests pass successfully by creating a pull request and verifying that all tests run successfully in CI.
Conclusion
Updating webdriverio brings many useful features that can be used right away, while some will appear in a more convenient form later. Therefore, we highly recommend upgrading to the new version to make writing tests more convenient, faster, and enjoyable.
The old hermione version is in limited support mode, and new features will not appear in it.
Support
If you encounter issues during the upgrade or have any questions, come to github issues — we will definitely help you!