The biggest benefit of using Selenium is that you can use the same tests to test multiple browsers. If we are interested in just a single browser, like Chrome, we'd be better off using Puppeteer. So, let's add Firefox to our tests.
Firefox, like Chrome, requires a driver to work. Firefox's driver is geckodriver, which uses the Marionette proxy to send instructions to Firefox (Marionette is similar to Chrome's DevTools Protocol):
$ yarn add geckodriver --dev
Now, all we need to do is change the forBrowser call to use "firefox":
this.driver = new webdriver.Builder()
.forBrowser("firefox")
.build();
When we run our tests again, Firefox will be used instead of Chrome.
However, instead of hard-coding the browser into our code, let's update our scripts to allow us to specify the browsers we want to test. We can do this by passing arguments into the shell script. For instance, if we execute the following:
$ yarn run test:e2e -- chrome firefox
Then, in our scripts/e2e.test.sh, we can access the arguments using $1 for the first argument (chrome), $2 for firefox, and so on. Alternatively, we can use the special argument "$@", which is an array-like construct that contains all arguments. In scripts/e2e.test.sh, change the test block to the following:
if $SERVER_UP; then
for browser in "$@"; do
export TEST_BROWSER="$browser"
echo -e "\n---------- $TEST_BROWSER test start ----------"
npx dotenv cucumberjs spec/cucumber/features -- --compiler js:babel-register --require spec/cucumber/steps
echo -e "----------- $TEST_BROWSER test end -----------\n"
done
else
>&2 echo "Web server failed to start"
fi
This will loop through our list of browsers, export it in the TEST_BROWSER variable, and run our tests. Then, in the forBrowser call inside spec/cucumber/steps/index.js, pass in the browser name from process.env instead of hard-coding it:
this.driver = new webdriver.Builder()
.forBrowser(process.env.TEST_BROWSER || "chrome")
.build();
Now, try running it with $ yarn run test:e2e -- chrome firefox, and you should see our tests being run first on Chrome, and then Firefox, and then the results neatly displayed in a standard output:
$ yarn run test:e2e
---------- chrome test start ----------
......
1 scenario (1 passed)
4 steps (4 passed)
0m01.899s
----------- chrome test end -----------
---------- firefox test start ----------
......
1 scenario (1 passed)
4 steps (4 passed)
0m03.258s
----------- firefox test end -----------
Lastly, we should define NPM scripts to make it obvious to other developers what operations we can run. By adding it as an NPM script, all the user needs to do is look at the package.json, and won't have to study the shell script to see how it works. So, in the scripts section of the package.json, change our test:e2e to the following:
"test:e2e": "yarn run test:e2e:all",
"test:e2e:all": "yarn run test:e2e:chrome firefox",
"test:e2e:chrome": "./scripts/e2e.test.sh chrome",
"test:e2e:firefox": "./scripts/e2e.test.sh firefox"
We have now successfully written our first test and run it. Next, let's make our scenario more generic by covering all the invalid cases:
Scenario Outline: Invalid Input
Tests that the 'Register' button is disabled when either input elements contain invalid values
When user types in "<email>" in the "#email" element
And user types in "<password>" in the "#password" element
Then the "#register-button" element should have a "disabled" attribute
Examples:
| testCase | email | password |
| Both Invalid | invalid-email | shortpw |
| Invalid Email | invalid-email | abcd1234qwerty |
| Short Password | valid@ema.il | shortpw |