Ordering pizza delivery with one console command in TestCafe

Helen Dikareva
6 min readJul 6, 2017

--

Hello everyone, today I’ll tell you a story about a neat and easy way to implement end-to-end testing for a pizza delivery web service using a new open source framework.

These days e2e testing necessity is a well-known issue. Any web app faces this issue sooner or later. The most popular solutions are various Selenium-based approaches most of which are using WebDriver. We, on the other hand, are going to use a new open source framework called TestCafe which is totally different. But enough of talking, let’s do it.

Installing TestCafe

As always it all starts with the tool installation. Yes, it’s boring, but I have good news for you: you need only one console command to install TestCafe.

npm install -g testcafe

If you’ve ever had to install Selenium or Selenium-based frameworks, you’ll see the difference, how easy and quick it was. As you might have noticed TestCafe is built with Node.js which means no Java, no browser plugins or OS restrictions. All you need is to have Node.js on your computer.

Now let’s create a file to keep our test in and call it get-a-pizza.js. In the file, we’ll create a fixture (a set of tests), specify url, and create a blank test.

One of TestCafe framework’s neat features is that both ES6 and ES7 syntaxes can be used regardless whether it’s supported by your browser or your Node.js version. Using Babel TestCafe translates all the code into ES5 syntax.

Creating the test

Interacting with page elements

Now let’s write the test itself. Let’s move to the page where we can order a pizza. Everything is simple: click “Order online”.

We used selectors to specify the elements we wanted to interact with. TestCafe selectors do all the work related to DOM elements. To do that you need to specify the way of receiving the element on the client side, e.g. CSS selector or a function. There’s also an API for creating complex selectors which allow finding elements based on their place in page hierarchy or using filters (text, index & etc.).

As you’ll see in a moment we won’t specify timeouts anywhere, neither will we set how long to wait for the page load, sending a form or XHR response. TestCafe will handle all that for us.

After we’ve navigated to the menu let’s add a large White Primavera pizza to our shopping cart.

Checking the state of page elements

Now we need to make sure that selected item is added to the shopping cart.

We’ll use TestCafe’s built in assertions to check it. And again we’ll use selectors to get the element’s value. Selectors contain a set of asynchronous properties and methods which can be used in tests or in assertions. In the case with assertions TestCafe uses waiting mechanisms because in many cases we need to wait for an animation to finish or XHR response before assertion.

All existing assertion libraries rely on using timeouts which elongate time for tests to run and makes them unstable. TestCafe takes care of this. If the checkup fails while using selector’s property or method test wouldn’t fail immediately. Assertions are calculated several times getting a value on each iteration and the test fails only if a timeout is reached and none of the assertion attempts succeeded. This approach allows for reliable, fast and stable tests without caring about page response time.

Now let’s check the names and number of items in our cart.

Running the code on the client side

We can also use a client side function to check the number of the items in the cart. The function will run on the client side and the result will be returned to the server. There can be any js code inside such function as if it was just added to the page.

There’s also a way to run code on the client immediately via t.eval method.

Placing the order

Now we’ll navigate to the pizza selection menu and add two Vegetable Special pizzas to our cart:

Let’s move to the cart and check that items’ quantity and names have changed:

Let’s move to checkout to fill contact information and delivery address. We won’t order actual delivery though, because we’ve had too many pizzas today already (for science!).

The test is ready to use. There’s no excess code, but required actions and interaction with page elements which keeps the test readable and easy to maintain.

Running the test

Let’s run our test with the console command:

testcafe chrome get-a-pizza.js

TestCafe will automatically find the browser installed on your machine, launch it and run the test. And in the console window, you’ll see all the information related to the test run and results.

If a test would fail you will see an error report. Such report would contain callsite and callstack and, if specified, a link to the screenshot made during the failure. To illustrate this let’s modify a selector in our test so that the element wouldn’t be found.

Before:

.click(Selector('#menu-primary-menu').find('li').nth(2))

After:

.click(Selector('#menu-primary').find('li').nth(2))

In this case we will have the following report:

Test result reports can be presented in various formats which are provided by plugins. They allow setting the framework to work with continuous integration systems. You can run tests not only on local machines but also on remote or in the cloud(e.g. Sause Labs, BrowserStack & etc.).

For the complete automation of our service, we only need to integrate the tests with the CI system. And who knows, maybe one day we’ll add checking the delivery time or taste rating. But this is a topic for another article :)

Conclusion

As you see we’ve reached our goal: we can now order a pizza to our office with just one command. Sure this example is just a joke, but anyone can write a test to make sure that their own website works perfectly 24/7.

The complete example can be found here. And here’s an example of this test using PageObject methodology, which allows the test code to be readable and simple.

I hope that after reading this you’ll pay a visit to our TestCafe. Please feel free to ask any questions in the comments below or on our discuss page. Have a delicious day!

--

--