Testing Vue.js Applications
Edd Yerburgh
Copyright
The frontend testing pyramid
Preface
Acknowledgments
About this book
WHO SHOULD READ THIS BOOK
HOW THIS BOOK IS ORGANIZED
ABOUT THE CODE
ONLINE RESOURCES
BOOK FORUM
About the author
About the cover illustration
Chapter 1. Introduction to testing Vue applications
1.1. DEFINING TESTING
1.1.1. Manual testing
Definition
1.1.2. Automated testing
1.1.3. Testing pull requests on GitHub
Definition
Note
Figure 1.1. A pull request that passed the tests; the tick appears when the tests have passed.
Note
Note
1.2. TESTING OVERVIEW
1.2.1. Overview of end-to-end tests
Listing 1.1. An end-to-end test to check that a calculator sums two numbers
Note
1.2.2. Overview of unit tests
Listing 1.2. A basic unit test
Definition
1.2.3. Snapshot testing
Definition
1.2.4. Combining test types effectively
Figure 1.2. The testing pyramid. Most of your tests should be unit tests.
1.2.5. Test-driven development
Note
1.2.6. Learning when not to test
1.2.7. The fallacy of 100% code coverage
1.3. WRITING A HACKER NEWS APPLICATION
Figure 1.3. The Hacker News website
Note
1.4. VUE TESTING OVERVIEW
Note
1.4.1. The Vue instance
Note
Listing 1.3. Creating a Vue instance
Note
1.4.2. Templates and render functions
Listing 1.4. A template string
Listing 1.5. Using a render function
Listing 1.6. Simple example of a virtual DOM
Note
1.4.3. Understanding the Vue component system
Listing 1.7. Registering a component globally in Vue
Note
Note
Listing 1.8. A single-file component (SFC)
Listing 1.9. A compiled SFC
1.4.4. Unit testing components
Note
Figure 1.4. Triggering an input and asserting an output in a component unit test
Definition
Listing 1.10. AuthorizedMessage.vue
SUMMARY
Chapter 2. Creating your first test
2.1. UNDERSTANDING A VUE PROJECT STRUCTURE
2.1.1. Understanding build tools
Note
2.1.2. Using Vue CLI to generate a project
Note
2.1.3. Understanding directory structure
Figure 2.1. A common Vue project directory structure
Note
2.1.4. Understanding npm
Definition
Note
Definition
Figure 2.2. Downloading packages from the npm remote repository
Note
2.1.5. Understanding the package.json file
Note
2.1.6. Linting files with ESLint
2.1.7. Writing a test script
2.1.8. Building the project
Note
2.2. INTRODUCTION TO JEST
Note
2.2.1. Writing a sanity test
Note
Definition
Note
Tip
Listing 2.1. Sanity test
Note
Note
Note
2.2.2. Understanding test assertions
Listing 2.2. Using a Jest matcher
Figure 2.3. A Jest assertion error
2.2.3. Avoiding false positives
Listing 2.3. A test that always passes
2.2.4. Organizing tests with the describe function
Listing 2.4. Grouping tests in describe blocks
Listing 2.5. Nested describe functions
Listing 2.6. Flattened describe function
2.2.5. Unit testing a component
Note
2.2.6. Compiling files with Jest
Listing 2.7. Importing a Vue single-file component
Note
Listing 2.8. Jest configuration field in package.json
Figure 2.4. Jest compiling a component with vue-jest and babel-jest
2.2.7. Mounting a component
Note
Warning
Listing 2.9. Creating a constructor and mounting a component
2.3. INTRODUCTION TO VUE TEST UTILS
2.3.1. Understanding the API
Listing 2.10. Using Vue Test Utils to test textContent
Listing 2.11. Using the Vue Test Utils text method
2.3.2. Using shallowMount
Figure 2.5. Mounting a component
Figure 2.6. shallowMount mounting a component
Listing 2.12. Using the shallowMount method
2.4. DEBUGGING TESTS WITH CHROME DEBUGGER
Important
Listing 2.13. Using Vue Test Utils to test text
Figure 2.7. The Chrome Inspect window
Figure 2.8. The Resume Execution button
Figure 2.9. Inspecting the wrapper
Figure 2.10. Inspecting wrapper methods
Note
SUMMARY
EXERCISES
Chapter 3. Testing rendered component output
3.1. CREATING TEST SPECIFICATIONS
3.1.1. High-level specifications
Figure 3.1. Two items from the finished feed
Note
Note
Listing 3.1. Instantiating Vue after fetching data
Note
3.1.2. Creating component-level specifications
Figure 3.2. ItemList containing Item components
3.2. TESTING RENDERED TEXT
3.2.1. Passing props to a component
Listing 3.2. Passing props to a component with mounting options
3.2.2. Testing the text content of a component
Listing 3.3. Passing props to components in a test
3.2.3. Using find
Figure 3.3. find searching the render tree
3.2.4. Testing the text content of an element
Note
Listing 3.4. Testing component text
3.3. TESTING DOM ATTRIBUTES
Listing 3.5. Testing DOM attributes
3.3.1. Avoiding Boolean assertions
Note
3.4. TESTING HOW MANY COMPONENTS ARE RENDERED
3.4.1. Using findAll
Listing 3.6. Using the wrapper array length property
Listing 3.7. Using a component as a selector
Listing 3.8. Testing child components
Listing 3.9. Using v-for to render items based on an array
3.5. TESTING PROPS
3.5.1. Using the Vue Test Utils props method
Listing 3.10. Testing props
Listing 3.11. Testing props using the props method
Listing 3.12. Passing props to a child component
3.5.2. Avoiding gotchas when testing props
Listing 3.13. Declaring a prop in a single-file component
Note
3.6. TESTING CLASSES
Figure 3.4. The progress bar in progress
3.6.1. Using the classes method
Listing 3.14. Testing a class with the classes method
3.7. TESTING STYLE
3.7.1. Accessing a wrapper element
Listing 3.15. Testing style by accessing wrapper element
3.7.2. Adding style to an application
3.8. WHEN TO TEST RENDERED COMPONENT OUTPUT
Definition
SUMMARY
EXERCISES
Chapter 4. Testing component methods
Figure 4.1. The finished progress bar at 80% complete
4.1. TESTING PUBLIC AND PRIVATE COMPONENT METHODS
Listing 4.1. Calling a method on click
Listing 4.2. Creating a public method
Note
Note
4.1.1. Testing public component methods
Listing 4.3. Testing a public method
Listing 4.4. Testing component state
Listing 4.5. ProgressBar.vue
Listing 4.6. Testing public methods
4.2. TESTING TIMER FUNCTIONS
Note
4.2.1. Using fake timers
Note
Note
Listing 4.7. Using fake timers
Listing 4.8. Calling useFakeTimers before each test
Listing 4.9. Moving the time forward with fake timers
Listing 4.10. Using a timer function in a component
4.2.2. Testing using spies
Listing 4.11. Using a spy to test someMethod was called
Listing 4.12. Using jest.spyOn to test clearInterval
Listing 4.13. ProgressBar.vue
4.3. ADDING PROPERTIES TO THE VUE INSTANCE
Definitions
Listing 4.14. Adding an instance property to the Vue prototype
Tip
Listing 4.15. Adding a Vue instance to the prototype
4.4. MOCKING CODE
4.4.1. Mocking Vue instance properties in components
Figure 4.2. Injecting a property into the Vue instance tree
Listing 4.16. Injecting an instance property with the mocks option
4.4.2. Understanding Jest mock functions
Listing 4.17. Storing function calls
Listing 4.18. Using a Jest mock function
Listing 4.19. Stubbing a function with a Jest mock
4.4.3. Using Vue lifecycle hooks
Note
Listing 4.20. Using the beforeMount lifecycle event
4.5. MOCKING MODULE DEPENDENCIES
Figure 4.3. Importing a function from another file
Figure 4.4. Stubbing a file import
Listing 4.21. Mocking a module dependency
Note
4.5.1. Using Jest mocks to mock module dependencies
Listing 4.22. Creating a mock file
4.5.2. Testing asynchronous code
Definition
Note
Listing 4.23. Writing an asynchronous test
Note
Listing 4.24. Testing a promise
Listing 4.25. Flushing promises
Note
Listing 4.26. Mocking a module dependency with Jest
Listing 4.27. Stubbing a module dependency in tests
Listing 4.28. Using flush-promises in a test
Listing 4.29. ItemList.vue
Listing 4.30. Mocking function to reject
4.5.3. Using mocks in moderation
SUMMARY
EXERCISES
Chapter 5. Testing events
Figure 5.1. The finished pop-up email subscribe form that you’ll create in this chapter
Note
5.1. TESTING NATIVE DOM EVENTS
Note
5.1.1. Using the Vue Test Utils trigger method
Definition
Listing 5.1. Triggering a mouseenter event
Note
Listing 5.2. Triggering a test by dispatching a DOM event
Note
Listing 5.3. Calling a prop when button is clicked
5.2. TESTING CUSTOM VUE EVENTS
Note
5.2.1. Testing that components emit custom events
Note
Listing 5.4. Testing that a component emits an event
Listing 5.5. Testing a Vue custom event is emitted
Listing 5.6. Emitting a custom event on form submit
5.2.2. Testing components that listen to Vue custom events
Listing 5.7. Testing that the component responds to Vue custom event
5.3. TESTING INPUT FORMS
Figure 5.2. The finished form
5.3.1. Testing text control inputs
Note
Listing 5.8. Using v-model to bind data
Listing 5.9. Updating the value and v-model value of an input in a test
Note
Listing 5.10. Using objectContaining
Listing 5.11. Testing a mock was called with a v-model bound input form value
Listing 5.12. Form component
5.3.2. Testing radio buttons
Note
Listing 5.13. Updating the value and v-model value of a radio button input in a test
Listing 5.14. Testing a component is called with the correct values
5.4. UNDERSTANDING THE LIMITATIONS OF JSDOM
Note
SUMMARY
EXERCISES
Chapter 6. Understanding Vuex
Note
Note
6.1. UNDERSTANDING STATE
Listing 6.1. Counter component
6.2. THE PROBLEM VUEX SOLVES
Definition
6.3. UNDERSTANDING THE VUEX STORE
Note
Note
Listing 6.2. Counter component
6.3.1. Creating a store
Listing 6.3. Creating a Vuex store
Listing 6.4. Using Vuex in a component
6.3.2. Understanding Vuex mutations
Figure 6.1. One-way data flow
Listing 6.5. Adding a mutation
Listing 6.6. Committing a mutation
6.3.3. Understanding Vuex actions
Listing 6.7. Committing mutations asynchronously
Note
Listing 6.8. Committing mutations inside a Vuex action
Listing 6.9. Dispatching an action
Figure 6.2. Dispatching actions in the Vuex lifecycle
6.3.4. Understanding Vuex getters
Note
Listing 6.10. A getter
Figure 6.3. Computing data with getters
Listing 6.11. Using a getter inside a component
Note
SUMMARY
Chapter 7. Testing Vuex
Note
7.1. UNDERSTANDING THE STORE DESIGN
Figure 7.1. Calling fetchListData in the application
7.2. ADDING VUEX TO THE PROJECT
Listing 7.1. Instantiating a Vuex store
Listing 7.2. Instantiating a Vuex store with a configuration object
Listing 7.3. A store configuration object
Note
Listing 7.4. Installing Vuex
7.3. TESTING VUEX STORE PARTS SEPARATELY
7.3.1. Testing mutations
Listing 7.5. A mutation
Listing 7.6. Testing a mutation
Listing 7.7. A simple mutation
7.3.2. Testing Vuex getters
Listing 7.8. Testing that an array is returned
Listing 7.9. A getter
Listing 7.10. Testing a getter
7.3.3. Testing Vuex actions
Note
Listing 7.11. Calling an action with a fake context object
Listing 7.12. Testing that commit was called in an action
Listing 7.13. Calling commit inside a promise chain
7.4. TESTING A VUEX STORE INSTANCE
Listing 7.14. Testing a Vuex store instance
Note
Listing 7.15. Cloning a store config object in a store instance test
7.4.1. Understanding the localVue constructor
Listing 7.16. Creating a Vue instance with the base Vue constructor
Figure 7.2. Polluting the Vue base class
Listing 7.17. Using a localVue constructor with Vue Test Utils
Note
Figure 7.3. Testing a store instance
Listing 7.18. Testing a Vuex store instance
7.5. TESTING VUEX IN COMPONENTS
Listing 7.19. Mocking a store in a test
Listing 7.20. Using beforeEach to reassign values
Listing 7.21. Controlling a getter in a fake store
Listing 7.22. Providing a store to a component in tests
Listing 7.23. Testing that dispatch was called in a component
Listing 7.24. Mocking an action to throw an error
SUMMARY
EXERCISES
Chapter 8. Organizing tests with factory functions
8.1. UNDERSTANDING FACTORY FUNCTIONS
Listing 8.1. Creating a wrapper object
Listing 8.2. Using a createWrapper function
8.1.1. Keeping code DRY
Listing 8.3. Creating a wrapper
8.1.2. Improving test code by following a pattern
8.1.3. Understanding the trade-offs of factory functions
Note
8.2. CREATING A STORE FACTORY FUNCTION
Listing 8.4. A createStore factory function
8.3. OVERWRITING DEFAULT OPTIONS IN FACTORY FUNCTIONS
Note
Listing 8.5. Using Lodash merge
Listing 8.6. Using Lodash merge with an array or object
Listing 8.7. Using mergeWith with a customizer function
Listing 8.8. A customizer function to overwrite empty objects and arrays
Listing 8.9. Using a createStore factory function
8.4. CREATING A WRAPPER FACTORY FUNCTION
Listing 8.10. A createWrapper function
Listing 8.11. Using createStore and createWrapper in a test
Tip
Listing 8.12. Keeping a reference to a mock when using a factory function
Listing 8.13. Passing a mocks object to createWrapper
Listing 8.14. Using a createWrapper factory function
Listing 8.15. Mocking actions
Listing 8.16. Mocking actions to reject
SUMMARY
EXERCISES
Chapter 9. Understanding Vue Router
Note
9.1. UNDERSTANDING ROUTING
Definition
9.1.1. Understanding server-side routing
Figure 9.1. Hacker News site with different feed links
Figure 9.2. Server-sider routing
9.1.2. Understanding client-side routing
Figure 9.3. Client-side routing
9.1.3. Understanding Vue Router concepts
Listing 9.1. A routes array
Listing 9.2. Using Vue Router to render an App component
Note
9.1.4. Understanding dynamic route matching
Note
Table 9.1. Dynamic path matching
Note
9.1.5. Adding Vue Router to an application
Listing 9.3. An array of RouteConfig objects
Listing 9.4. Router config file
Note
Listing 9.5. Using RouterView to render components
SUMMARY
Chapter 10. Testing Vue Router
Definition
Note
10.1. TESTING ROUTER PROPERTIES
10.1.1. Testing the $route property
Listing 10.1. Mocking a $route property
Listing 10.2. Passing props into a component
Listing 10.3. Creating a store with a maxPage getter
Listing 10.4. Mocking $route.params
Listing 10.5. Using the $route.params value in the template
10.1.2. Testing the $router property
Listing 10.6. Testing a router.replace call
Listing 10.7. Calling $router.replace
10.1.3. Avoiding common gotchas
Figure 10.1. Unintentionally calling Vue.use when importing a module
10.2. TESTING THE ROUTERLINK COMPONENT
Figure 10.2. Pagination on the third page
Figure 10.3. Pagination on the first page
Listing 10.8. Testing that a ChildComponent receives a prop
Listing 10.9. Stubbing RouterLink in a test
Tip
Listing 10.10. Using a RouterLinkStub
Note
Listing 10.11. Using RouterLinkStub to find a component
Listing 10.12. Using RouterLinkStub as a selector
Listing 10.13. Testing that router-link is rendered
Listing 10.14. Using router-link in the template
10.3. USING VUEX WITH VUE ROUTER
10.3.1. Adding the route to the store
10.3.2. Using router parameters in the store
Listing 10.15. Testing a getter that uses the route object
Listing 10.16. Testing a getter that uses the route object
Note
Listing 10.17. Using the route params inside a Vuex getter
Listing 10.18. Syncing Vuex and Vue Router on a localVue
SUMMARY
EXERCISES
Chapter 11. Testing mixins and filters
11.1. TESTING MIXINS
11.1.1. Understanding mixins
Listing 11.1. An example mixin
Note
11.1.2. Writing tests for mixins
Listing 11.2. Testing a mixin
Listing 11.3. Creating an instance with a mixin
Listing 11.4. Testing a mixin
Note
Listing 11.5. A title mixin
Listing 11.6. Testing a mixin
Listing 11.7. Calling the instance property if title is a function
11.1.3. Testing local mixins in components
Listing 11.8. Testing a mixin in a component
11.1.4. Testing global mixins in components
Listing 11.9. A test setup file
11.2. TESTING FILTERS
Listing 11.10. Applying a filter in a template
11.2.1. Writing tests for filters
Figure 11.1. Before filtering
Figure 11.2. After filtering
Listing 11.11. Testing a filter
Listing 11.12. A host filter
11.2.2. Testing filters that use Date.now
Definition
Listing 11.13. Stubbing Date.now
Listing 11.14. Testing a filter function
Listing 11.15. Writing a timeAgo filter
11.2.3. Testing filters in components
Listing 11.16. Mocking Date.now in a test
Note
Listing 11.17. Testing a filter in a component
SUMMARY
EXERCISES
Chapter 12. Writing snapshot tests
Definition
Figure 12.1. The frontend testing pyramid
12.1. UNDERSTANDING SNAPSHOT TESTS
Listing 12.1. A snapshot test
Listing 12.2. A snap file
Note
Figure 12.2. The snapshot test flow
12.1.1. Writing snapshot tests for components
12.1.2. Writing snapshot tests for static components
Listing 12.3. A static component
Listing 12.4. Writing a snapshot test
12.1.3. Writing snapshot tests for dynamic components
Note
Listing 12.5. Writing a snapshot test for a dynamic component
Definition
Listing 12.6. Mocking Date.now
12.2. ADDING SNAPSHOT TESTS TO YOUR WORKFLOW
Figure 12.3. A testing workflow with snapshots
SUMMARY
EXERCISES
Chapter 13. Testing server-side rendering
Note
13.1. UNDERSTANDING SERVER-SIDE RENDERING
Note
13.1.1. The advantages of SSR
Listing 13.1. HTML response for a client-side app
Figure 13.1. The process of a client-side rendered app
Figure 13.2. The process of a server-side rendered app
Listing 13.2. HTML response for a server-side app
13.1.2. The disadvantages of SSR
Definition
Note
13.2. TESTING SERVER-SIDE RENDERED COMPONENTS
Note
Listing 13.3. Rendering a Vue instance to a string
13.2.1. Using Vue Server Test Utils
Note
Listing 13.4. Writing a snapshot test with renderToString
Note
Listing 13.5. Writing a snapshot test with renderToString
Note
Listing 13.6. Setting a Jest test file to run in a Node environment
Note
13.2.2. Traversing server-side rendered markup with render
Listing 13.7. Using render to assert against server-side rendered code
Note
13.3. TESTING STATUS CODES WITH SUPERTEST
Note
Listing 13.8. Testing an HTTP request with SuperTest
Note
Listing 13.9. Testing a 200 response with SuperTest
Listing 13.10. Testing that the server responds with 404 when the page isn’t found
Note
13.4. TESTING SSR IMPLICITLY
SUMMARY
EXERCISES
Chapter 14. Writing end-to-end tests
14.1. UNDERSTANDING END-TO-END TESTS
14.1.1. Using end-to-end tests effectively
Figure 14.1. The frontend testing pyramid
14.1.2. Understanding Nightwatch and WebDriver
Note
Listing 14.1. Testing that Google displays results
Figure 14.2. Clicking an element with Nightwatch
14.2. ADDING NIGHTWATCH TO A PROJECT
14.2.1. Installing dependencies
Note
14.2.2. Configuring Nightwatch
Listing 14.2. Nightwatch configuration file
14.2.3. Adding a sanity test
Listing 14.3. Nightwatch test that visits localhost:8080
Note
Note
14.2.4. Writing an end-to-end test script
Note
Note
Listing 14.4. Starting a server and running Nightwatch
14.3. WRITING END-TO-END TESTS WITH NIGHTWATCH
14.3.1. Deciding which end-to-end tests to write
14.3.2. Writing end-to-end tests for routes
Listing 14.5. Testing that a link navigates correctly
Listing 14.6. Checking that a route has updated
14.3.3. Writing end-to-end tests for dynamic data
Listing 14.7. Changing the list by clicking through the navigation
Listing 14.8. Checking a user journey with an end-to-end test
14.4. RUNNING END-TO-END TESTS IN MULTIPLE BROWSERS
Note
Listing 14.9. Defining a Firefox environment Nightwatch config
SUMMARY
WHERE TO GO FROM HERE
Appendix A. Setting up your environment
A.1 CHOOSING A TEXT EDITOR
Table A.1. Editors and plugins
A.2 USING THE COMMAND LINE
TIP
A.3 INSTALLING CHROME
A.3.1 Using Chrome DevTools
Figure A.1. Using the Chrome Console
A.4 INSTALLING THE VUE.JS DEVTOOLS CHROME EXTENSION
Figure A.2. Using Vue developer tools to inspect the Hacker News app
A.5 INSTALLING NODE AND NPM
A.5.1 Installing Node with the one-click installer
A.5.2 Installing Node with Homebrew (macOS only)
A.5.3 Installing Node with Linux package managers (Linux only)
A.5.4 Installing with NVM
A.5.5 Verifying that Node and npm are installed
A.6 INSTALLING GIT
A.7 STARTING A NEW CHAPTER
Note
Note
A.8 STARTING CHAPTER 5
A.9 INSTALLING THE JAVA DEVELOPMENT KIT
Appendix B. Running the production build
B.1 UNDERSTANDING THE PRODUCTION BUILD
Definition
B.2 RUNNING THE HACKER NEWS PRODUCTION BUILD LOCALLY
Appendix C. Exercise answers
CHAPTER 2
CHAPTER 3
CHAPTER 4
CHAPTER 5
CHAPTER 7
CHAPTER 8
CHAPTER 10
CHAPTER 11
CHAPTER 12
CHAPTER 13