92. Designing E2E tests

How do we design effective E2E tests, and what exactly should we be testing for?

As we discussed in previous videos, E2E tests are used to verify that the integrated application is functioning as intended.

So the way to design E2E tests is to firstly consider what the main features or use cases for the app are.

In PrintBay, some of the main features are:

We could make each of these uses cases the basis of a separate E2E test.

Designing first test

Let's start by designing a test that checks if a user can add an item to their cart.

We'll continue to use the spec file test.js, but we'll delete the existing sanity test and create a new one called "add item to cart".

Remember this is a function property, and the function receives the browser object as an argument. We'll make it a fat arrow function and leave the body empty for now.

tests/e2e/specs/test.js

module.exports = {
  "add item to cart": browser => {}
};

Manual walkthrough

Now that we've chosen the use case we want to test, we need to break is down into a series of atomic steps. We can then tell Nightwatch to perform those steps and make assertions about the page state as it does so.

So to add an item to the cart, the first step is to load home page. We then click an item we want, and we're taken to the item page. We then click the "Add to cart button", and the item is added to the cart.

Creating test

So let's now get Nightwatch to perform those steps, starting with navigating to the homepage.

We can do that by firstly declaring the browser object, then chaining the url method. Rather than hardcoding a URL, let's use the environment variable Vue CLI 3 supplies for our the dev server URL, which is process.env.VUE_DEV_SERVER_URL.

tests/e2e/specs/test.js

module.exports = {
  "add item to cart": browser => {
    browser
      .url(process.env.VUE_DEV_SERVER_URL)
  }
};

Click

Once the home page loads, we then click on an item summary. To do that, we can use the click method. This method accepts a CSS selector to specify the element we want to click.

tests/e2e/specs/test.js

"add item to cart": browser => {
  browser
    .url(process.env.VUE_DEV_SERVER_URL)
    .click()
}

Inspecting the items on the home page, notice that the item summaries are contained in an element with class item-summaries. Let's exploit that to easily select the item we want to click.

So let's use the selector .item-summaries > :first-child. This will tell Nightwatch to click the first child of the .item-summaries element.

End

We don't have any assertions yet, but let's try and run this just to see what happens.

Before we do, though, we'll need to complete our test by adding an end method.

tests/e2e/specs/test.js

"add item to cart": browser => {
  browser
    .url(process.env.VUE_DEV_SERVER_URL)
    .click(".item-summaries > :first-child")
    .end();
}

API server

One more thing before we run the test, we need to ensure the dev server is off because Vue CLI 3 will automatically set up and tear down the dev server when the E2E test command is run.

However, it won't set up the API server automatically because it doesn't know about it, so for now, we need to manually run that. So let's type:

$ npm run serve:server

With that done, we can now run the E2E suite in another tab by typing:

$ npm run test:e2e

After it runs, you'll see we get an error:

ERROR: Unable to locate element: ".item-summaries > :first-child" using: css selector

Wait

You might think this error means we got our CSS selector wrong, and sometimes that does happen, but in this case, it's the wrong conclusion.

The actual issue is that we didn't wait for the page to load before trying to click the element.

To do that, we can chain in the waitForElementVisible method before the click method. This method takes two arguments, firstly, a CSS selector for the element we want to wait for. Let's make that ".item-summaries".

Secondly, we need to elect the maximum wait time. Let's make that 5000 milliseconds, keeping in mind that Nightwatch will likely find the element much quicker than that.

tests/e2e/specs/test.js

"add item to cart": browser => {
  browser
    .url(process.env.VUE_DEV_SERVER_URL)
    .waitForElementVisible(".item-summaries", 5000)
    .click(".item-summaries > :first-child")
    .end();
}

With that done, let's run the test suite again. This time it works.

We'll continue to work on this test in the next video.

Discussion

0 comments