Chapter 12. Testing

This chapter covers

  • Understanding why we test
  • Implementing unit tests
  • Testing components
  • Testing Vuex

We’ve discussed many important topics in this book, but one often-neglected topic doesn’t get enough attention: testing. Testing is an extremely important aspect in any software development project. It ensures that the app behaves the way we expect it to—without bugs. In this chapter, we’ll discuss why you should create tests for your application. Then we’ll look at the fundamentals of unit testing. Next, we’ll look at component testing, both the output and the methods. Finally, we’ll see how to get started testing with Vuex.

It’s worth mentioning before we start that testing is a huge subject. In this chapter, I’ll cover several of the most important aspects of testing with Vue.js. I strongly recommend you look over Edd Yerburgh’s Testing Vue.js Applications (Manning, 2018). In his book, Edd delves into much more detail on creating and developing tests. He also covers server-side rendering testing, snapshot testing, and testing mixins and filters.

Snapshot testing

Snapshot tests are useful tools when you want to ensure that the UI doesn’t change unexpectedly. In this chapter, I’ll use mocha-webpack, which doesn’t support snapshot testing as of this writing. However, if you want to learn more about snapshot testing, look over the official guides for more information on how to set up Jest with snapshot testing at http://mng.bz/1Rur.

12.1. Creating test cases

Typically, in the world of software development, there are two ways of testing code: manually and automated. Let’s talk about coding manually first.

You probably started testing manually as soon as you started coding. For every line of code you’ve written, you’ve probably gone back and checked to make sure the output you expect is occurring. For example, in our pet store app we added a button that added a product to our cart. In the previous chapters we tested that manually by clicking the button and then checking the number of items in the cart.

In our pet store app, we also added a button that routes to the checkout page. Once again, we can click that button and make sure that it redirects properly. Manual testing works fine for smaller apps where there isn’t much going on.

Now let’s imagine a scenario where we’re working with a team of developers. We have an app in production and many developers are working on the code. Developers are pushing code throughout the day to the version control system. As you can imagine, relying on every developer to thoroughly test their code manually and verify they haven’t broken anything is impossible. Manual testing is a nightmare and bugs could certainly crop up.

In certain organizations, a quality assurance department is responsible for manually testing code after the development department releases it. This helps reduce the chances of a bug reaching production but it slows down the whole process. In addition, many quality assurance developers don’t have the resources or time to run a complete regression test on the code.

Definition

Regression testing is a type of software testing that verifies that the application still performs the same way after it was updated.

But automated testing can help solve several of the problems that manual testing runs into. In our imaginary scenario, we could create several automated tests that a developer could run before pushing their code to production. Automated tests run much quicker then manual testing and they’re more likely to catch bugs immediately. With many automated test cases, a developer can run a full regression on a code base and not worry about having to manually test everything, which is time-consuming.

Although automated testing has many benefits, it has its disadvantages. The one disadvantage that you must consider is the upfront cost. Writing test cases takes time, and although you’ll probably save time in the long run, you’ll spend a longer time writing test cases when compared with writing the code. After everything is set up though, processes such as continuous integration, delivery, and deployment can save time, as we’ll see in the next section.

12.2. Continuous integration, delivery, and deployment

Automated testing has the added benefit of enabling workflows such as continuous development. This workflow consists of continuous integration, delivery, and deployments. As the name suggests, these workflows are closely related. We’ll briefly discuss each one.

Imagine we’re creating a basic app that connects to a database and retrieves information for a book website. We have a team of developers working on the code base, but the team is running into a number of issues. Most developers are having merge conflicts when they push their code into their version control system every few weeks. In addition, every Friday one person is responsible for manually creating a staging environment for the latest code. (A staging environment runs production code for testing purposes.) This increasingly has taken more time to do because the code base has gotten larger and more complicated. Pushing to production is no better. Half the time the production code won’t build correctly, and it takes hours to fix. The manager has decided to switch to continuous development to help fix these problems. The first step in that process is continuous integration.

12.2.1. Continuous integration

Continuous integration (CI) is the practice of merging code into a master branch several times a day.

Definition

A master branch is where the production code usually resides. A branch is a version-control term that describes a duplication of a code base so modifications can happen in parallel in both branches.

The obvious benefit of CI is that it helps avoid merge conflicts. Merge conflicts happen when multiple developers try to merge or combine their code into a single branch. Merging code into a master branch several times a day helps avoid one developer’s work-in-progress breaking another developer’s code. Because the master branch is updated continuously, another developer working on the same project can easily pull the latest code down into their own development environment and be relatively sure it’s up to date.

In our imaginary scenario, our manager decides to make the CI process smoother by implementing a service that helps run automated test cases before any developer can push their code. In version control systems like Git, developers can submit pull requests. Services such as Travis, CircleCI, and Jenkins can help check that the pull request passes all the test cases before the code can be merged. After the systems are in place, the team has seen fewer merge conflicts, but they still have problems with deployment.

12.2.2. Continuous delivery

Continuous delivery is a software-engineering approach that aims to build, test, and release software in a fast and frequent manner. The purpose is to create a fast and reliable deployment pipeline that’s guided by a set of checks that must pass before the code is released. For example, before the software is released, all test cases must pass and the build must pass without any errors or warnings. These types of checks help provide more dependable, consistent releases.

Typically, CI isn’t the responsibility of the development team. Usually a team of people known as DevOps or development operations is responsible for setting up and maintaining continuous delivery. It’s good to understand the basics of this process and how it relates to testing.

With continuous delivery, merging or committing code to the master branch triggers a build of the website. This can save time because it removes the manual step of deploying the website to the staging environment. It has the added benefit that it will deploy only if all test cases pass, so it’s less likely that the website will be broken.

With continuous delivery, our team no longer needs to have someone waste hours creating and deploying a staging environment. Continuous delivery will make sure that it occurs daily. With that said, what does continuous deployment have to do with continuous delivery?

12.2.3. Continuous deployment

Continuous deployment goes one step further than continuous delivery and deploys code directly to production on every single change. As with continuous delivery, developers can rest assured that all tests pass before the code is deployed to production.

As you can imagine, deploying to production after every change can be dangerous if the automated tests aren’t robust enough to check all parts of the app. The worst-case scenario is that a broken website gets deployed to production. At that point, a rollback or emergency fix is needed. Now that we’ve seen the way we can integrate testing into a workflow, let’s look into what type of tests are available and how we can use these test in Vue.js.

12.3. Types of tests

In the world of testing, we can create several types of tests. In this chapter we’ll look at the most common, including unit and component testing.

Unit tests are tests against the smallest parts of our application. These are often functions in our apps, but not always. They can also be components. Let’s begin by creating a basic unit test to see how it works.

Unit tests have unique advantages. For one, they’re fast and run quickly. Because they only test a small piece of code, they can run fast. They can also act as documentation. They’re instructions on how the code should behave. Unit tests are also reliable because they only test a small part of the code. They can be run thousands of times and produce the same output. Unlike other tests that might have to rely on APIs that frequently fail, unit tests should never have this problem. Imagine a scenario where you’ve created an application that converts the temperature from Fahrenheit to Celsius. In this app, we have one function that does the conversion. We could easily create a unit test to verify that the amount returned was correct. You can see that in this listing.

Listing 12.1. A basic unit test: chapter-12/unit.js
function convert(degree) {
  let value = parseFloat(degree);
  return (value-32)/ 1.8;
}

function testConvert() {                       1
  if (convert(32) !== 0) {
    throw new Error("Conversion failed");
  }
}

testConvert();

  • 1 A basic unit test that checks the convert function.

The second type of tests we’re going to look at are component tests. These tests run against each component and verify how they should behave. They can be a little more complicated than unit tests because they test more of the application and they’re more difficult to debug. But they verify that the component meets its requirements and achieves its goal.

12.4. Setting up our environment

Now that we have a good idea about the kinds of tests that are out there and why we should test, let’s set up our environment. Our pet store app could use several tests, so let’s add them.

In this section we’ll modify our pet store application so we can use the latest testing libraries recommended by Vue.js. As of this writing, the Vue-CLI didn’t have these libraries built in when we generated our project, so we’ll need to do a little setup. This will require us to install several packages and configure a few files.

To begin our setup, we’ll need to get a copy of our pet store app. If you’ve been following along, feel free to use the app you’ve created. If not, copy the pet store app from chapter 11 at https://github.com/ErikCH/VuejsInActionCode.

The vue-test-utils is the official unit-testing library for Vue.js. It makes testing Vue.js much easier and you should use it. We’ll cover the basics of the library in this chapter; if you’d like more information, you can read how it works in the official guides at https://vue-test-utils.vuejs.org.

You may remember from chapter 7, that when we created the pet store app we said yes to Nightwatch and Karma. This will work but at the time of writing, the Vue-CLI doesn’t support the vue-test-utils library out of the box. Because this library isn’t installed by default, we need to install it.

We’ll also need to make a choice regarding which test-runner we want to use within the vue-test-utils library. A test-runner will pick up the unit tests that we create and execute them. When we first installed our pet store app, Mocha and Karma were our only test-runner choices. Karma works with vue-test-utils but it isn’t officially recommended. The vue-test-utils team recommends either Jest or mocha-webpack. Because we already have Mocha installed, we’ll go ahead and install mocha-webpack. Jest is also an excellent choice, but it won’t be covered in this book.

Note

Keep in mind that if you choose Jest, all the tests in this book will still work, but you’ll have a little different setup. You can find instructions on how to set up Jest at the official guides at http://mng.bz/3Dch.

Because we’re going to use mocha-webpack as our test runner, we’ll need to install a few other things. To run tests, we’ll need a browser. We could run our tests in a real browser, such as Chrome or Firefox, but it’s not recommended because running in a browser can be slow and it’s not as flexible as using a headless browser. Instead we’ll use modules called jsdom and jsdom-global. These modules will simulate a browser for us; they’re headless browsers used to run our test cases.

Definition

A headless browser doesn’t have a graphical user interface (GUI) and is used to facilitate automated control of a web page. The headless browser performs much the same as contemporary browsers, but interaction is typically accomplished through a CLI.

We’ll need to pick an assertion library, and Chai and Expect are popular choices. Assertion libraries are used to verify things are correct instead of relying on things like if statements. The vue-test-utils team recommends using Expect with mocha-webpack, so we’ll go ahead and install that. You can find more information on picking an assertion library at http://mng.bz/g1yp.

That last library we need to install is the webpack-node-externals. This will help us exclude certain npm dependencies from our test bundle.

Retrieve the latest version of the pet store app that’s included with this book. Beware, if you download the latest version of the pet store app from chapter 11 you’ll need to enter your Firebase configuration inside the firebase.js file in the src folder if you haven’t done so already. If you forget this step the application will not load!

After you retrieve the latest version of the pet store app, install these dependencies by running the following commands:

$ cd petstore
$ npm install
$ npm install –-save-dev @vue/test-utils mocha-webpack
$ npm install –-save-dev jsdom jsdom-global
$ npm install –-save-dev expect
$ npm install –-save-dev webpack-node-externals

After the dependencies are installed, we’ll add configuration. Edit the webpack.base.conf.js file in the build folder of the pet store app. Copy and paste the code from the following listing at the bottom of the file to configure the webpack-node-externals and inline-cheap-module-source map. This is required by those modules for everything to work correctly.

Listing 12.2. Setting up source map and node externals: chapter-12/setup.js
if (process.env.NODE_ENV === 'test') {
  module.exports.externals = [require('webpack-node-externals')()]     1
  module.exports.devtool = 'inline-cheap-module-source-map'
}

  • 1 Sets up the test environment

Inside the test folder you’ll notice the unit and e2e folders. We won’t use these folders, so feel free to delete them. Add a new file called setup.js inside the test folder. The setup.js file is where we’ll set the global variables for jsdom-global and expect. This will make it so we don’t have to import both modules into every single test case. Copy and paste the code from this listing into the test/setup.js file.

Listing 12.3. Setting up tests: chapter-12/petstore/setup.js
require('jsdom-global')()               1
global.expect = require('expect')       2

  • 1 Sets up jsdom-globa
  • 2 Sets expect inside app

Next, we need to update the test script in the package.json file. This script will run the mocha-webpack test runner and our tests. For the sake of simplicity, all tests will have a spec.js file extension. Edit the package.json file and replace the scripts test section with this line.

Listing 12.4. Updating package.json: chapter-12/testscript.js
"test": "mocha-webpack --webpack-config
build/webpack.base.conf.js --require
 test/setup.js test/**/*.spec.js"             1

  • 1 Notes the test script inside package.json file

That is all the configuration we need for our setup. Now we can start creating test cases!

12.5. Creating our first test case with vue-test-utils

For our first test using vue-test-utils, let’s see if we can verify that our Form component works correctly after clicking the Order button. When you click the Order button on the form component, an alert box appears. We can test for an alert box, but it’s not easy with our setup and will require us to change our jsdom-global configuration. For the purposes of this test, we’ll create a property called madeOrder. This will be defaulted to false. After clicking the Order button, it will turn true.

The order form will be updated so it shows a message at the bottom that the order is complete (figure 12.1). When madeOrder is true, the text will appear. When it’s false, the text will not show up. We add this so we can get a little more feedback when the order button is clicked, because we’re no longer going to use the alert box.

Figure 12.1. Pet depot checkout page that displays Ordered at the bottom

To make this change, we need to update the src/components/Form.vue file Add a new property in the file called madeOrder in the data function. Edit the submitForm method and delete the alert box, then add this.madeOrder = true. This will guarantee that the property is set to true when the app starts up. Update the src/components/Form.vue with the code in this listing.

Listing 12.5. Update to the Form component: chapter-12/form-update.js
...
        dontSendGift: 'Do Not Send As A Gift'
      },
      madeOrder: false               1
...
  methods: {
    submitForm() {
      this.madeOrder = true;         2
    }
  }
...

  • 1 Adds a new property for madeOrder
  • 2 Sets madeOrder to true

We’re now ready to create our first test case. Let’s verify that after the Place Order button is clicked, the madeOrder property is set to true. To test this, we’ll use the vue-js-utils shallow function. The shallow function renders a Vue component and stubs out any child components it has. The other common function is mount which works the same as shallow, except it doesn’t stub the child component.

We’ll also need to import the Form component. We’ll pass this into the shallow function later to create a wrapper around it. Next, you’ll notice something called describe. The describe function is used to group similar tests together into a test suite. When we run the tests from the command line, we can see whether the test suite passed or failed.

The it function is a test case. This will be our unit test that tests our button and verifies that it updated the madeOrder property correctly. We can have multiple test cases in each test suite.

Because we’re using the expect assertion library, we’ll use it to make sure that the madeOrder property is set to true. In listing 12.6 we’re using wrapper.vm.madeOrder to access the property. The wrapper object returned from the shallow function has several properties including one called vm. We can use the vm property to access any Vue instance methods or properties, allowing us to run any method or get any property inside the Vue component. This is handy.

wrapper also has a find function that accepts a selector. The find function can use any valid CSS selector, such as tag names, IDs, or classes. We can then use the trigger function to trigger the event—in this case, a click event on the button. Take the following listing and create a new Form.spec.js file.

Listing 12.6. Our first test case: chapter-12/petstore/test/Form.spec.js
import { shallow } from '@vue/test-utils'                        1
import Form from '../src/components/Form.vue'                    2

describe('Form.vue', () => {

    it('Check if button press sets madeOrder to true', () => {
      const wrapper = shallow(Form)                              3
      wrapper.find('button').trigger('click')                    4

      expect(wrapper.vm.madeOrder).toBe(true);                   5
    })

})

  • 1 Imports shallow to use in the test case
  • 2 Imports the form component
  • 3 Assigns the wrapper to shallow version of component
  • 4 Finds then triggers the button
  • 5 Verifies madeOrder is true

Let’s run our test cases. Make sure you’re in the pet store top-level directory and run the npm test command. This should run our test suite. If you see an error, make sure you installed all the dependencies that we discussed earlier and verify the package.json file has the test script inside it. Figure 12.2 displays what we’ll see when all of our tests pass!

Figure 12.2. Checking our first test case, which is successful

Because everything passed, a successful message is displayed. Let’s see what it looks like when it fails. Go back into the petstore/test/Form.spec.js file. Look for the expect statement and set the value to false instead of true. Run the command npm test again and it should fail. Notice from figure 12.3 that the expected value and the received value are displayed in the output.

Figure 12.3. The test case fails

Now that we understand the basics of testing, let’s look at testing components.

12.6. Testing components

Before we test our components, we need a general idea of our specifications. What should we expect the components to do? We’ll use our pet store app as an example.

We have three components in our application: Main, Header, and Form. The Header component’s job is to display the number of items in the shopping cart and to show either a Sign In or a Sign Out button. The Form component’s responsibility is to show all our form inputs, and it gives us an option to order by clicking the Order button. Main is used to display all our products. It needs to render all the components from our Firebase store.

We won’t test every component, but it’s important to write down specifications for each component before creating any test cases. That way we’ll know what to test.

12.6.1. Testing props

Many of our components will have props that are passed in to them. For example, in our pet store app, the cartItemCount is passed into our Header component and displayed in the top right corner. Let’s create a test case that verifies that this prop is passed in.

Create a file in the petstore/test/ directory called Header.spec.js. This file will contain all our tests for the Header component. Before we can begin, we need to do a little setup.

If you look at the Header.vue file, you’ll notice that we’re using Firebase and Vuex. The beforeCreate hook calls a Firebase function and sets the value using a Vuex store command that commits the session. We won’t test Vuex or Firebase in this example, but we’ll need to import them, otherwise we’ll get an error. Make sure to import both ../src/firebase and ../src/store/store as seen in listing 12.7.

At the top of the file, import shallow from the vue-test-utils library. In addition, import something called createLocalVue. We need this function so we can set up Vuex.

Next, we’ll create a localVue variable and assign it to createLocalVue(). This function returns a localVue class. You can think of it as a photocopier that produces a photocopy version of Vue. We can use this to help set up Vuex for our testing.

You can see from listing 12.7 that we use the shallow function again, but it looks a little different than the unit test we created earlier. The shallow function can accept an optional second argument. This object holds more information that the component needs. Inside it, we can set the props data using propsData as well as localVue and store.

To set the props, we must pass something in to it. The easiest way to do that is to add cartItemCount. We pass that variable into the propsData, and it will be set inside the Header component.

The last thing we do is check that the wrapper.vm.cartItemCount matches the cartItemCount variable. If they’re the same, the test passes. Take the code in the next listing and copy it to the petstore/test/Header.spec.js file.

Listing 12.7. Testing a prop: chapter-12/header-prop-test.js
import { shallow, createLocalVue } from '@vue/test-utils';
import Header from '../src/components/Header.vue';
import Vuex from 'vuex';                                         1
import '../src/firebase';                                        2
import { store } from '../src/store/store';                      3

const localVue = createLocalVue();
localVue.use(Vuex)

describe('Header.vue', () => {

  it('Check prop was sent over correctly to Header', () => {
    const cartItemCount = 10;
    const wrapper = shallow(Header, {                            4
      store, localVue, propsData: { cartItemCount }              5
    })
    expect(wrapper.vm.cartItemCount).toBe(cartItemCount);        6
  })

});

  • 1 Imports Vuex into test case
  • 2 Imports Firebase into test case
  • 3 Imports Vuex store into test case
  • 4 The new wrapper const has a second argument.
  • 5 The props data is set to cartItemCount.
  • 6 Expect verifies that the cartItemCount matches from the passed-in prop.

Now that we can check props, let’s look at text.

12.6.2. Testing text

Sometimes you want to test if text is rendered somewhere in the component. It doesn’t matter what element renders the text, only that an element renders it.

Keep in mind when writing tests that each test case should test only one thing. It might be easy to create multiple assertions inside a test case that checks text, but it’s often better to take these types of tests and create multiple test cases out of them. We’ll follow this rule of creating a single assertion in a test case.

Open the petstore/test/Header.spec.js file and add a new test case. In our last test case, we verified that the cartItemCount prop was being passed correctly into the Header component. Now we want to verify whether the text from the prop is displayed properly inside the component in the span tag.

To do this, we’ll create another wrapper the way we did before. This time, we’ll use the wrapper.find function to look up the span. We can then use the text() function to extract the text inside the span, which is our cartItemCount. We then use the toContain function to verify that the contents match. Copy the code from the following listing into the pet/test/Header.spec.js as another test after the last test.

Listing 12.8. Testing text: chapter-12/header-text-test.js
it('Check cartItemCount text is properly displayed', () => {
  const cartItemCount = 10;
  const wrapper = shallow(Header, {
    store, localVue, propsData: { cartItemCount }
  })
  const p = wrapper.find('span');              1
  expect(p.text()).toContain(cartItemCount)    2
})

  • 1 The wrapper finds the span tag.
  • 2 The assertion checks whether the text matches cartItemCount.

12.6.3. Testing CSS classes

When testing classes, we can use the method classes, which returns an array of classes attached to an element. Let’s add a quick check to verify whether the class on one of our divs is correct.

Inside the petstore/test/Header.spec.js file, add a new test case. In this test case we’ll create a new wrapper. This time we’ll use a findAll which will return all the divs in the component. We can use the at(0) to retrieve the first div. From there we can use our expect statement on p.classes() to retrieve all the classes attached to the first div. The toContain will return true if any of the classes match.

If we look at the Header.vue file, we’ll notice that both navbar and navbar-default are attached to the first div. Because we’re looking for navbar, this test will pass.

Listing 12.9. Testing classes: chapter-12/header-classes-test.js
it('Check if navbar class is added to first div', () => {
  const cartItemCount = 10;
  const wrapper = shallow(Header, {
    store, localVue, propsData: { cartItemCount }
  })
  const p = wrapper.findAll('div').at(0);         1
  expect(p.classes()).toContain('navbar');        2
})

  • 1 This looks for all the divs and returns the first one.
  • 2 This checks the classes attached to see if navbar exists.

Before we get too much further, run npm test at the command prompt and verify that all the tests are passing (figure 12.4). If any are failing, double-check the expect statements and that you’re importing everything correctly at the top of the file.

Figure 12.4. All tests are passing

All tests are passing, so let’s move on to Vuex.

12.6.4. Testing with a mocked Vuex

The Vuex store is a central location where we can hold data for the application. In our pet store app, we used it to set the session data and hold our product info. When using Vuex, it’s a smart idea to test the store.

Note

Vuex testing is complicated and has many moving parts. Unfortunately, I won’t cover them all here. To learn more about Vuex testing, start with the official Vuex testing guides at https://vue-test-utils.vuejs.org/guides/using-with-vuex.html.

For our test cases, we’ll test our Header component and how it works when the session is set to true or false. We want to verify that if the session exists, the Sign Out button displays and if the session doesn’t exist, the Sign Up button displays.

Earlier in this chapter, we imported the store directly into our test file. This was only a temporary workaround so we could create other test cases for the Header component. This won’t work for testing Vuex. To test our Vuex store, we’ll need to mock the store completely. This is much simpler than you think.

At the top of the petstore/test/Header.spec.js file, you’ll see an import of the store. Delete this line. We’ll create a mock of the store. A mock is an object that has the same structure as a complex object that you cannot use in your test (similar to our Vuex store), but with an implementation that you can control. Beneath the describe statement, add the new variables: store, getters, and mutations, as shown in listing 12.10. Then create a beforeEach function. The code inside the beforeEach runs before every test case. It’s a good place to put setup code.

For the sake of simplicity, our store will be rudimentary. We’ll have a getter for session that returns false, and a mutation that returns an empty object. We can use new Vuex.Store to create the store (make sure you use a capital S in Store). Copy the code in the following listing into the top of the petstore/test/Header.spec.js file.

Listing 12.10. Mocking Vuex: chapter-12/header-vuex-mock.js
describe('Header.vue', () => {

  let store;                     1
  let getters;
  let mutations;
  beforeEach(() => {             2
    getters = {                  3
      session: () => false
    }
    mutations = {                4
      SET_SESSION: () => {}
    }
    store = new Vuex.Store({     5
      getters,
      mutations
    })
})

  • 1 Shows the store, getters, and mutations variables
  • 2 Runs before each test
  • 3 The session getter is set to false.
  • 4 The mutation SET_SESSION returns an empty object.
  • 5 A new store is created.

Now that we’ve mocked our Vuex store, we can use it in our test cases. We can assume if the session is set to false, the Sign In button will be displayed. If this is a little confusing, go to the Header.vue file in the src folder, where you’ll see a v-if directive that relies on a computed property called mySession. If mySession is false, the Sign In button is displayed. The v-else directive shows a Sign Out button if it’s true. Copy the code from this listing into the petstore/test/Header.js file.

Listing 12.11. Testing Sign In: chapter-12/header-signin-test.js
it('Check if Sign in button text is correct for sign in', () => {
  const cartItemCount = 10;
  const wrapper = shallow(Header, {
    store, localVue, propsData: { cartItemCount }
  })

  expect(wrapper.findAll('button').at(0).text()).toBe("Sign In");       1

})

  • 1 The assertion expect looks at the text of the button and verifies it’s Sign In.

Conversely, we should also check that, if the session is signed in, that the Sign Out button displays. You can do this a few ways, but one of the easiest is to create a store with a new getter.session. When we create the wrapper, the new store will be added, and the Header component will act as if the session were set to true instead of false. Copy the code from the following listing and add it as another test case in the petstore/test/Header.spec.js file.

Listing 12.12. Testing Sign Out: chapter-12/header-signout-test.js
it('Check if Sign in text is correct for sign out', () => {
  const cartItemCount = 10;
  getters.session = () => true;
  store = new Vuex.Store({ getters, mutations})
  const wrapper = shallow(Header, {
    store, localVue, propsData: { cartItemCount }
  })
  expect(wrapper.findAll('button').at(0).text()).toBe("Sign Out");     1
})

  • 1 Checks if button text is Sign Out

Run the test and they’ll all pass. These are all the tests we’re going to run for our pet store app. As an exercise, go into the Forms or Main component and add some test cases.

12.7. Setting up the Chrome debugger

When you’re debugging tests, you often end up using the console.log to see what variables are doing during the execution of code. This works, but there is a better way. We can use the Chrome debugger to make our job much easier.

Inside your test cases, you can add a debugger statement. Add the debugger keyword anywhere in the test. This will stop the execution of code as soon as the debugger statement is parsed. This will work only if you use the node inspector with the Chrome browser. The node inspector is a tool that is built into Node 8.4.0 or later and helps with debugging with the Chrome browser. To run tests with the node inspector, we’ll need to run the following code. You can either run this from the command line or add it to your package.json file under scripts. Open your package.json file and add this line under the scripts section.

Listing 12.13. Adding inspect to the package.json file: chapter-12/petstore/package.json
...
  "private": true,
  "scripts": {
...
    "inspect": "node --inspect --inspect-brk node_modules/mocha-
webpack/bin/mocha-webpack --webpack-config build/webpack.base.conf.js –
require test/setup.js    test/**/*.spec.js"                               1
...

  • 1 Runs the script command to inspect the browser

To run this command type in npm run inspect in the console. This will begin the node inspector. Alternatively, you can run this command from the command line:

$ node --inspect --inspect-brk node_modules/mocha-webpack/bin/mocha-webpack
 --webpack-config build/webpack.base.conf.js --require test/setup.js
    test/**/*.spec.js

Either way, a new debugger on localhost 127.0.0.1 will start. You should see an output like this:

Debugger listening on ws://127.0.0.1:9229/71ba3e86-8c3c-410f-a480-
ae3098220b59
For help see https://nodejs.org/en/docs/inspector

Open your Chrome browser and type the URL: chrome://inspect. This opens a Devices page (figure 12.5).

Figure 12.5. Chrome Devices page

After a few seconds, you should see a target at the bottom and a link that shows inspect. Click the Inspect button and a separate window opens. The Inspect window starts in the paused state. Click the arrow to start the debugger (figure 12.6).

Figure 12.6. Chrome Inspect window

After the debugger starts, it will stop at the place in our code where we added the debugger statement. From here, we can view the console, and look at variables, as you can see in figure 12.7. For example, if you click the wrapper, then __proto__, and then __proto__ again, you’ll see all the wrapper methods.

Figure 12.7. Debugger statement showing all the wrapper methods.

Use the Chrome inspector whenever you need to figure out a test, and you’re not sure what variables do.

Exercise

Use your knowledge from this chapter to answer the following questions:

  • Why is it important to test? What tool is made for Vue.js that can help with testing?

See the solution in appendix B.

Summary

  • Unit test cases test small units of functionality.
  • Writing tests allows you to test functions and verify they work as expected in the application.
  • You can debug your test cases in real-time using the Chrome browser.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset