How to Test Your Vue App with Automated Tests

Unit Tests

Jest

Jest is my favorite testing library for JavaScript. Its fast and the tests are fast and easy to write once you get the syntax down. You don't have to add on a lot of other libraries for test coverage or mocking. With Jest you get that for free.

Unit test utilities

Extracting complex, reusable functionality to utility methods makes your app easy to test. Since you don't have to worry about mounting Vue components these tests are like any other JS test.

If you have a robust test suite you can also potentially extract these utilities into a reusable library and publish on NPM.

Some examples of good functionality to extract are string manipulation and sanitizing, validation, and calculations you use throughout your app. Do not extract functionality that is dependent on your components. There are better ways to reuse this logic.

Testing Vuex

Write unit tests for you Vuex code. Especially if it contains complex logic. You don't need to write tests for mutations that do simple updates.

Testing your Vuex methods let you know that your store is doing what you expect. Since your Vuex store will need to be mocked in your component tests its important to test Vuex separately. Your component tests will not adequately ensure that your Vuex modules are working properly.

Testing Components

I typically don't write unit tests for components on my personal projects. I do find that unit testing components does help on teams that have many developers. But make sure that you require all tests to pass before committing code and have automated tests running before code is pushed to production.

It is possible to write unit tests for component methods but I advise against this. If you have complex methods extract them into a utility and test them. Or if they are tightly coupled to your component template prefer integration tests.

Integration Tests

Integration tests combine functionality and test units as a group. They test how your methods work together.

Favoring integration tests for your components helps you test the stuff your end users care about. Your visitors don't care what class an element has. They don't even care what framework you're using. Don't test that the correct Vue component is loaded. Test that the final content is correct.

Don't write tests like this.

it("should be a VueButton", () => {
  expect(wrapper.is(VueButton)).toBeTruthy();
  expect(wrapper.find(VueButton).text()).toBe("Sign Up");
});

Write tests like this.

it("should be a button that says Sign Up!", () => {
  expect(wrapper.find("button").text()).toBe("Sign Up");
});

The first test only proves that our component is an instance of the VueButton component. We don't know what the VueButton component does. Is is accessible? Is it even a button. Who knows!

The second test proves that our component is a button with the text "Sign Up!". Its much more descriptive since we know what the component does. It will break if someone comes along and swaps it out for a div styled like a button.

***If this happens be sure to start a conversation about accessibility on your team.

Keep the following tips in mind

  • full test coverage is not necessary but you can use the coverage tool to find gaps in your tests
  • you generally don't need to test that hard-coded HTML is present. sometimes I do use snapshots to track any erroneous changes though.
  • you can test for accessibility issues by making sure that the proper HTML element is used.
    • test for semantic HTML
    • ensure correct aria attributes are present

Jest enables snapshot testing. I would advise using this feature very selectively. Its pretty cool but takes a lot of discipline since pressing u while in watch mode makes broken snapshot tests pass. Essentially you have a click a button and make the tests pass escape hatch.

Linting for code style

I use ESLint and Prettier in all of my personal projects. Throughout my career I've changed my coding style many times and with Prettier I just don't think about it. Prettier just does its thing and I'm ok with that.

Keep these tips in mind

  • linting can prevent some common errors
  • keeps style consistent
  • don't get too rigid with linting though
  • ESLint and Prettier

Storybook for Visual Tests

Ok this one isn't really automated but its important. Storybook can help you build a component library but its so much more than that.

In the past I've tried to maintain separate style guides and component libraries but they've always fallen out of sync with my project. This happens because they were always maintained outside of my project. Storybook runs along with your project. This way it will never fall out of date.

Storybook also helps by sandboxing your components. This means you can develop components in isolation eliminating distraction and clutter. This also makes it so much easier to develop and test components that depend on a lot of state or complex flows.

You may have a component that only appears when there is a server error. Chances are during development you will not see this state very often and this component will be forgotten. With Storybook you can work on this component without triggering a server error.

You can also add stories for components in all of their possible states. So you can make sure a form input thats in an empty, error, focus, and success state all work correctly.

There are also add ons that allow for accessibility tests, testing emitted events and tons of other add ons.

Storybook article coming soon.

E2E Tests with Cypress

For medium and large applications automated E2E testing is a must. Once you get up and running Cypress tests are fast and easy to write.

You can also use Cypress for better integration tests. If you are using Vuex so much of your store is mocked in your component tests that its hard to know if it will all come together. With Cypress you can test how your store, router and components work.

Cypress is also very helpful in applications that have a lot of forms. Manual form validation is so tedious. Its one of my least favorite Q/A tasks. Using Cypress I can test all sorts of combinations of data with little effort.

If your application receives data from an external API you can either use the live API or mock data using fixtures. I prefer to use mock data since it gives me more control over my tests and doesn't generate a ton of API calls. I know this isn't a true E2E test but the whole purpose of these tests is to see that our Vue application works properly. We can test the live API manually.

If you truly need to test the live API I suggest writing a small number of tests without the mock data. And only test the happy paths.

If your company has a Q/A team rest assured that Cypress is not a replacement for manual testing. Adding Cypress E2E tests is not going to get your QA team fired. Cypress cannot totally replace actual humans testing your app. It doesn't look for visual bugs. It doesn't know if there are usability issues. It will catch regressions and logical errors and save your QA team from sending the same defects over and over.

https://www.cypress.io/

Additional Testing Tips

Write Tests Early and Often

  • start writing tests immediately when you begin a project
  • this will build a foundation of tests as your application gets more complex
  • even if its just sanity checks its important to know that your tests are set up and working

Use Git Hooks to Automate Testing

  • this keeps broken code out of your app
  • forces you and your team to keep tests updated
  • I add these to projects even if I'm the only developer

Bonus Points

  • error logging with Sentry
  • TypeScript

Need Help with Your Website

If you need help with your website contact me here.

© 2023, Elizabeth Rogers All Rights Reserved