The main learning goal of this chapter is to get used to setting up the testing environment for writing end-to-end tests using TestCafe. You will learn how to set up a Node.js environment (including TestCafe itself), create a basic configuration file to run the tests, and structure the test code to follow the best practices.
This is especially important because in real life, each new project/repository usually requires a testing infrastructure to be set up to prevent regressions and to keep the code quality high.
To sum up, this chapter will cover the following main topics:
All the code examples for this chapter can be found on GitHub at https://github.com/PacktPublishing/Modern-Web-Testing-with-TestCafe/tree/master/ch3.
It is important to set up the environment properly now as we will be using it for the rest of the chapter and up to the end of this book. Doing so will also help you understand the basics of how Node.js deals with different packages and how to spin up pretty much any JavaScript/Node.js-based testing framework. We will divide the setup process into two sections:
So, let's go through the whole process, starting from the beginning—installing Node.js.
JavaScript is a client-side programming language that mostly deals with the frontend, which means it is usually processed by the browser of each user that opens your website or web application. Node.js was developed as a JavaScript runtime environment to provide the ability to use JavaScript as a server-side backend language.
In order to launch almost any development tools written in JavaScript, you'll need to use Node.js and Node Package Manager (npm). This package manager is a tool that helps you install, update, and keep your Node.js project dependencies (packages) all in one place (the node_modules folder).
Node.js is available for a variety of operating systems, macOS, Ubuntu/Linux, and Windows being among them. The easiest way to install Node.js and npm is to follow these steps:
Another slightly more complex but reusable way is to install Node.js through Node Version Manager (nvm – https://github.com/nvm-sh/nvm) or n (https://github.com/tj/n). Version managers give you the ability to install several versions of Node.js simultaneously and switch between them whenever you like, which is quite useful during test development.
Once the installation is finished, you can check whether both Node.js and npm are working properly by opening any shell (for example, Terminal or PowerShell) and executing the following:
$ node -v
$ npm -v
That should output the version number for Node.js and npm, respectively.
As we already have Node.js and npm installed, let's proceed with installing TestCafe. It can be installed from npm locally (to run from your project folder) or globally (to run from any location).
To install TestCafe locally to your project directory and save it to the dependencies list, open any shell, go to your project folder, and execute the following two commands:
$ npm init --yes
$ npm install testcafe --save-dev
The first command will create a simple package.json file to store all the dependencies. The second command will install the testcafe package and save it to the list of your project's dependencies in package.json.
To install TestCafe globally, open any shell and execute the following command:
$ npm install testcafe --global
This will install TestCafe globally, and it will be accessible from any folder.
You can always check the version of the testcafe package that is installed by executing the following command:
$ npx testcafe -v --no-install
Note
On macOS (starting from v10.15 Catalina and up), TestCafe requires screen recording permission to carry out test actions and take screenshots and videos. When TestCafe tests launch for the first time, macOS will ask you to allow screen recording for TestCafe browser tools. Go to System Preferences - Security and Privacy - Privacy and check TestCafe Browser Tools to grant permission. When you update macOS or TestCafe, security permissions may be purged—in this case, the system will repeat the request. So, when the Security and Privacy popup opens again, just uncheck and recheck the TestCafe Browser Tools checkbox.
Now, as we have Node.js, npm, and TestCafe installed and ready, let's proceed with creating a configuration file for our tests.
In this section, we will see how to configure TestCafe. However, before reviewing the main configuration options, let's set a convention for some coding style standards.
When writing code throughout this book, we will follow some simple rules, such as indenting with two spaces for .json files and four spaces for .js files. We will also use semicolons and single-quotes. Most popular code editors support a .editorconfig configuration file to automatically apply the rules:
root = true [*]indent_style = space indent_size = 4 end_of_line = lf insert_final_newline = true charset = utf-8 trim_trailing_whitespace = true max_line_length = 120 [*.json]indent_size = 2
You can copy the basic config file that we will be using from https://github.com/PacktPublishing/Modern-Web-Testing-with-TestCafe/blob/master/.editorconfig.
The TestCafe configuration settings are usually stored in the .testcaferc.json file in the root folder of your project. Let's look at the main options that can be specified:
$ npx testcafe --list-browsers
To run tests in Chrome only, .testcaferc.json will look like this:
To run tests in Firefox and Chrome, your test will look like this:
{ "browsers": ["firefox", "chrome"]}
To run tests in remote browsers (such as SauceLabs, BrowserStack, CrossBrowserTesting, and so on) with a browser provider plugin, set the browser provider name, together with the browser alias and operating system, as follows:
{ "browsers": "saucelabs:[email protected]:Windows 10"}
Postfixes to browser aliases can be used to launch tests in headless mode or to apply Chrome device emulation (https://devexpress.github.io/testcafe/documentation/guides/concepts/browsers.html#use-chromium-device-emulation):
{ "browsers": ["firefox:headless", "chrome:emulation:device=iphone X"]}
Note
TestCafe starts Chrome and Firefox with a fresh profile by default, without any extensions or profile settings. If you need to launch a browser with the current user profile, add the :userProfile postfix flag after the browser alias.
{ "src": "tests/login-test.js"}
Global patterns can be used to parse a set of files:
Multiple reporters can be set at the same time, but only one reporter can write to the console output (standard output, or stdout), and all other reporters should write to the files:
{ "reporter": [ { "name": "minimal" }, { "name": "json", "output": "tests/reports/report.json" }, { "name": "xunit", "output": "tests/reports/report.xml" } ]}
You can also explore and use any of the available reporters from https://www.npmjs.com/search?q=testcafe-reporter.
{ "screenshots": { "path": "tests/screenshots/", "takeOnFails": true, "pathPattern": "${DATE}_${TIME}/test-${TEST_ INDEX}/${USERAGENT}/${FILE_INDEX}.png", "fullPage": true }}
Note
See the full list of the placeholder path patterns that can be used for screenshots and videos at https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/screenshots-and-videos.html#path-pattern-placeholders.
{ "videoOptions": { "failedOnly": true, "singleFile": true, "pathPattern": "${TEST_INDEX}/${USERAGENT}/${FILE_INDEX}.mp4" }}
If quarantine mode is turned on, tests run will follow the next logic:
Note
If debug mode is on, test execution will be paused before the first action or assertion so that you can open the developer tools and start debugging. To make it easier, a status bar will be displayed in the footer showing the available debug actions: Unlock page, Resume, and Next step.
Note
If the speed is set in .testcaferc.json and also within the test for an individual action, the action's speed setting will have a higher priority and will override the speed set in the configuration file.
{ "clientScripts": [ { "content": "Date.prototype.getTimestamp = () => new Date().getTime().toString();" }, { "module": "js-automation-tools" }, { "path": "scripts/helpers.js", "page": "https://test-site.com/page/" } ]}
{ "proxy": "123.123.123.123:8080"}
Authentication credentials can also be set with the proxy host:
{ "proxy": "username:[email protected]est-site.com"}
{ "proxyBypass": ["localhost:8080", "internal.corp.test-site.com"]}
{ "tsConfigPath": "/Users/john/testcafe/tsconfig.json"}
In the case of relative paths, they will be resolved against the directory from which you run TestCafe.
{ "disablePageCaching": true }
When browsers open a cached page inside the role code, the localStorage and sessionStorage content will not be saved. To keep the storage items after navigation, set disablePageCaching to true.
Note
Here is a good example of a .testcaferc.json file with all the main settings: https://github.com/DevExpress/testcafe/blob/master/examples/.testcaferc.json.
Now, let's assemble all that we have learned in this section and create a folder with the basic configuration for our test project by opening any shell (for example, we will use Terminal with Bash) and executing the following steps:
$ node -v
$ mkdir test-project
$ cd test-project/
$ npm init --yes
$ npm install testcafe --save-dev
{ "browsers": "chrome", "src": [ "tests/**/*.js", "tests/**/*.feature" ], "screenshots": { "path": "tests/screenshots/", "takeOnFails": true, "pathPattern": "${DATE}_${TIME}/test-${TEST_INDEX}/${USERAGENT}/${FILE_INDEX}.png" }, "quarantineMode": false, "stopOnFirstFail": true, "skipJsErrors": true, "skipUncaughtErrors": true, "concurrency": 1, "selectorTimeout": 3000, "assertionTimeout": 1000, "pageLoadTimeout": 1000, "disablePageCaching": true }
We have covered the options from this file in the Exploring the configuration settings section, so you can always refer back to it to understand this example.
You can also review and download this configuration file from GitHub at https://github.com/PacktPublishing/Modern-Web-Testing-with-TestCafe/blob/master/ch3/test-project/.testcaferc.json.
As we installed Node.js and TestCafe and created a basic config file, let's continue setting up our test project by organizing our test code structure.
To gain a better understanding of test code structure organization, let's divide it into several parts: fixtures, tests, the starting web page, metadata, and skipping tests.
TestCafe tests are usually grouped into test suites, called fixtures (which are the same as the describe blocks in the Jasmine and Mocha test frameworks). Any JavaScript, TypeScript, or CoffeeScript files with TestCafe tests should contain one or more fixtures. Test fixtures can be declared with the fixture function, which only accepts one argument—fixtureName—which is a string for the name of the fixture (set of tests):
fixture('Name for the set of the tests');
Alternatively, you can write this without the brackets:
fixture `Name for the set of the tests`;
A fixture is basically a wrapper to indicate the beginning of a set of tests. Let's see how these tests should be structured.
Tests are usually written right after the fixture declaration. To create a test, call the test function, which accepts two arguments:
A simple test with the block of code usually looks like this:
test('Go to the main page', async (t) => { await t.click('#button-main-page'); await t.expect(Selector('#logo-main-page').visible).ok();});
Due to the fact that TestCafe tests are executed on the server side, you can use any additional packages or modules. Also, inside the test, you can do the following:
Now, let's see how to specify a starting page for all tests in a fixture.
You can set the initial web page that will be the starting point for all tests in a fixture with the fixture.page function. It only accepts one argument—url, which is a string for the URL of the web page where all tests in a fixture start:
fixture('Contacts page').page('http://test-site.com/example');test('Test Contact form', async (t) => { // Starts at http://test-site.com/example });
Next, let's see how to specify metadata for fixtures and tests.
In TestCafe, you can also provide additional information for tests, such as key-value metadata. This can be used to filter tests and display this data in reports. To define metadata, use the fixture.meta and test.meta methods. They accept two string arguments:
Alternatively, they can accept one argument—metadata, which is an object for key-value pairs of metadata.
Both styles of setting metadata can be combined, which will look like this:
fixture('Contacts page') .meta('env', 'production') .meta('fixtureId', 'f0001') .meta({ author: 'John', creationDate: '01.06.2020' });test.meta('testId', 't0001') .meta({ testType: 'fast', testedFeatureVersion: '1.1' }) ('Test Contact form', async (t) => { // Your test code });
Fixtures or tests can be launched by the specific metadata values that they contain. To filter tests by metadata, add the filter.testMeta and filter.fixtureMeta properties to the .testcaferc.json configuration file:
{ "filter": { "fixtureMeta": { "env": "production", "author": "John" }, "testMeta": { "testType": "fast", "testedFeatureVersion": "1.1" } }}
This configuration will run only tests that have the testType property of metadata set to fast and testedFeatureVersion set to 1.1, as well as tests whose fixture's metadata has the env property set to production and the author property set to John.
You can use custom reporters (https://devexpress.github.io/testcafe/documentation/guides/extend-testcafe/reporter-plugin.html) to display fixture's and test's metadata in reports.
In TestCafe, you can also specify a fixture or test to skip while all the other tests run. This is achieved with the fixture.skip and test.skip methods:
fixture.skip('Contacts page');test('Test Contact form', async (t) => { // Your test code });test('Test Review form', async (t) => { // Your test code });fixture('About page');test('Test Reviews block', async (t) => { // Your test code });test.skip('Test More info form', async (t) => { // Your test code });test('Test Our mission block', async (t) => { // Your test code });
In this example, all tests from the Contacts page fixture will be excluded from running. The Test More info form test will not be executed either.
Another pair of useful methods is fixture.only and test.only. They are used to specify that only a particular fixture or test should be launched, and all others should be skipped. If several fixtures or tests are marked with .only, then all fixtures or tests marked with .only will be executed:
fixture.only('Contacts page');test('Test Contact form', async (t) => { // Your test code });test('Test Review form', async (t) => { // Your test code });fixture('About page');test('Test Reviews block', async (t) => { // Your test code });test.only('Test More info form', async (t) => { // Your test code });test('Test Our mission block', async (t) => { // Your test code });
In this example, only the tests from the Contacts page fixture and the Test More info form test will be executed.
In this chapter, we learned how to set up the testing environment for writing end-to-end tests using TestCafe. We installed Node.js and TestCafe, reviewed the configuration options, and created a basic .testcaferc.json file to store them. In addition to that, we found out about several techniques to structure TestCafe code, including fixtures, tests, the starting web page, metadata, and skipping tests.
The lessons of this chapter are important as you will be going through the configuration phase for any new project that you'll start.
Now, we are well prepared and ready to proceed with utilizing this knowledge in writing TestCafe tests for our test project. We will learn how to create and debug a test, and will start building a real-life test suite right after that.