While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

End-to-end testing is one of the most valuable tools in your testing arsenal, allowing you to simulate what your user would do as they move through your app and determine if your app is responding correctly to that. Unfortunately, it’s also one of the most difficult and time-consuming test methods as well, and the usual tools to do so require a decent amount of configuration and setup, further complicating the process. Thankfully, there are some relatively simple solutions. Here we’ll demonstrate one of them, TestCafe, and show you how to do end-to-end testing with your Vue.js app. (That said, you can use these methods with any framework or site.)

Installation

Unlike traditional solutions that generally involve a near-unmanageable amount of dependencies, such as Selenium / WebDriver + Browser Drivers + Client Libraries, the entirety of TestCafe is node-based and installable in one package. It’s also a zero-configuration tool. The required options are passed via the command line. As such, it’s best used through NPM scripts.

To begin using it in your Vue app, install testcafe via Yarn or NPM. You might also consider using the vuepack template for vue-cli if you’re starting a new project.

# Yarn $ yarn add testcafe -D # NPM $ npm install testcafe --save-dev

Setup

It is assumed from here that your app has a development server that can be run with npm run dev. webpack-dev-server works fine.

Add a new script to your package.json scripts object that starts testcafe.

"scripts": { "dev": "...", "test": "testcafe all tests/*.test.js --app \"npm run dev\" --app-init-delay 10000 -S -s screenshots", }

This tells testcafe to:

all - Run tests in all browsers that it can find on the system. Optionally, set this to a comma-separated list of browser names.

- Run tests in all browsers that it can find on the system. Optionally, set this to a comma-separated list of browser names. tests/*.test.js - Run all files as tests that end with .test.js in the tests folder.

- Run all files as tests that end with in the tests folder. --app \"npm run dev\" - The command to start your app server.

- The command to start your app server. --app-init-delay 10000 - To delay starting the test suite for ten seconds to wait for your app server to load.

- To delay starting the test suite for ten seconds to wait for your app server to load. -S - Take screenshots when tests fail.

- Take screenshots when tests fail. -s screenshots - Store screenshots in the screenshots folder relative to the project root.

Now we’re ready to start writing end-to-end tests.

Your First Test

Let’s assume for a moment that the entirety of your app is simply a paragraph element inside <body> that contains the words "Hello World!" . Here’s how we would ensure that is indeed the case.

Anything that has to communicate with the browser returns a promise. Using async / await to manage calls to the browser makes your tests much easier to grok. TestCafe handles any needed transpilation.

test/example.test.js

// A fixture must be created for each group of tests. fixture(`Index page`) // Load the URL your development server runs on. .page('http://localhost:8080'); // Create a new test(description, function(testController): <Promise>) test('Body > Paragraph contains "Hello World!"', async testController => { // Select the paragraph element under the body. // Must use promises (async / await here) for communication with the browser. const paragraphSelector = await new Selector('body > p'); // Assert that the inner text of the paragraph is "Hello World!" await testController.expect(paragraphSelector.innerText).eql('Hello World!'); });

Controlling User Input

Now to do any half-decent end-to-end testing, you need to be able to simulate user actions and input. Like any good testing suite, TestCafe provides the necessary methods to handle this use-case.

test('Typing in an input', async testController => { // Select the input element (Assumes <body><input type="text/></body>") const inputSelector = await new Selector('body > input[type="text"]'); await testController // Type the last word of "Hello World!" .typeText(inputSelector, 'World!') // Click the beginning of the element. caretPos is the position of the text cursor we want the click to be at. .click(inputSelector, { caretPos: 0 }) // Type the keys, SHIFT+H, e, l, l, o, and SPACE in order to write "Hello ". .keyPress('H e l l o space') // The resulting value should now be "Hello World!" .expect(inputSelector.value).eql('Hello World!'); });

Reference

TestCafe can do quite a bit more. They also provide some interesting conventions for reducing test duplication. To learn more, visit their official site.