# Functional Testing With TestCafe

Today we are going to dive into the world of functional web testing with TestCafe.

Unlike the majority of other end-to-end (e2e) testing tools, TestCafe is not dependent on Selenium or WebDriver. Instead, it injects scripts into the browser to communicate directly with the DOM and handle events. It works on any modern browser that supports HTML5 without any plugins. Further, it supports all major operating systems and can run simultaneously on multiple browsers and machines.

We will be using:

Please review the Getting Started guide before beginning.

## Contents

1. Objectives
2. Project Setup
3. Writing Tests
4. Browser Support
5. Continuous Integration
6. Next Steps

## Objectives

By the end of this tutorial, you should be able to…

1. Set up TestCafe with an existing Node app
2. Write TestCafe tests using the PageObject pattern
3. Test a Node application with functional tests
4. Integrate TestCafe into a continuous integration process
5. Configure TestCafe to work with a headless browser

## Project Setup

Start by cloning the base project structure:

Install the dependencies, and then fire up the app by running npm start to make sure all is well. Navigate to http://localhost:3000/ in your browser and you should see a list of jobs in HTML. Experiment with the app. Add a job. Update a job. Delete a job. This is what we will be testing. Kill the server when done.

Install TestCafe:

With that, you can start running tests.

NOTE: If you were using a Selenium-based testing tool you would need to install both Selenium and Web Driver, which can be difficult depending on your system setup.

Add a test command to the scripts in package.json:

Here, we specified the path to TestCafe in our “node_modules” folder along with a target browser, chrome, and a path to where all tests will be located, tests/.

Now, you can use npm test to run TestCafe.

Let’s get a test set up. Add a “tests” folder to the project root, and add an index.js file to it:

What’s happening?

1. Since all tests are organized into fixtures, we started with a fixture() function.
2. Next, we specified a start URL - http://devexpress.github.io/testcafe/example - via the page() method.
3. From there, we added the test code into a test() function, which takes an async function along with the test controller object.
4. await is then used to wait for certain actions to complete. In this case, we used typeText() and pressKey() to search GitHub.
5. On the GitHub search results page, we used a Selector() function to parse the DOM.
6. Finally, we asserted that the actual results contain the expected results.

NOTE: If you’re new to async/await, check out Understanding JavaScript’s async await.

Try this out! Run npm test. If all goes well Chrome should fire up and execute the test. Once done, you should see something like this in your terminal:

Make sense? No? Continue to run the test and review the above steps until it does. Make sure you understand what’s happening before moving on.

## Writing Tests

Add a new file called jobs.js to the “tests” folder:

Then update the test command in package.json:

tests/jobs.js ignores the example GitHub test found in index.js so that we can focus just on the tests added to jobs.js. The --app option is used to launch the Node app so that TestCafe can interact with it.

Try it. You should see the page load in Chrome. With that, let’s test each of our app’s CRUD functions.

### GET ALL Jobs

Update jobs.js:

What’s happening? Review the code above, line by line. It should be fairly straightforward. Turn to the docs for help, adding comments as necessary.

Run:

Before moving on, refactor out the selectors so that they can be re-used by other test cases:

Start by adding a new test() function to jobs.js:

NOTE: Can you guess what only() does? Try running the tests to see. Please review the docs for more info.

Think about the steps an end user has to go through to add a job:

1. Click the add job button
2. Fill out the form
3. Submit the form

Now, try this on your own, step by step, before looking at the solution…

Make sure to add the selector to the top:

Test it out. Then remove the only() and test again:

What are we missing in this test?

1. What happens if the cancel button is pressed?
2. What if the end user does not enter data for all the fields?
3. What if text is entered in the email field but it is not a valid email?

Try testing for these on your own.

### Update Job

Again, start by adding the boilerplate:

Then write out the steps the end user has to take before writing any code:

1. Click the update button
2. Fill out the form
3. Submit the form

Test:

What else should you test for? Write the test cases on your own.

Also, did you notice the code smell? There’s a lot of code duplication happening between those last two test cases. How could this be better handled?

Finally, did you notice that there are still four jobs in the table? Why? Could there be issues with testing the previous two tests together rather than in isolation? Probably not in this case, but if there are, you could always wrap the update in a new fixture(), since this restores the page to its initial state.

### Delete Job

Run the app again with npm start to review, from the end user’s perspective, what happens when you try to delete a job.

Did you notice the setNativeDialogHandler() function? This tells TestCafe how to handle the alert.

What if we click “cancel” instead of “ok”?

Run the tests:

Again, handle any edge cases on you own and clean up the code smell.

## Browser Support

Aside for Chrome, TestCafe supports a number of browsers out-of-the-box. Further, if you don’t need to test browser-dependent functionality, then you can use a headless browser.

Update the test command in package.json:

Run the tests, and you should see:

## Continuous Integration

Finally, let’s incorporate TestCafe into our Continuous Integration (CI) process with Travis CI.

NOTE: New to Travis? Review the Travis CI for Complete Beginners guide along with Running Tests in Firefox and Chrome Using Travis CI.

After you enable Travis CI for the repository you are working with, add a .travis.yml file to the project root:

Here, we added the Node version along with some basic Chrome settings. Also, we have to use xvfb to fake a GUI so that Chrome thinks it’s running in a graphical environment.

That’s it. Grab the final code from the testcafe-example repo. Comment below if you have questions.