This chapter contains three small chapters in one, namely, Testing, Deployment, and Troubleshooting. They do not aim to be complete guides for these topics but to provide the essentials for those who are starting this journey and how they apply to a Vue on Rails approach.
Testing Approaches
The software testing world is a whole discipline in itself apart from the development world. Large companies have dedicated QA/QC departments to offload the burden from engineers. The theory is that engineers spend the time doing what they do best – engineering. But what if you work on a small team or project? What if you are a one-human shop? You’ll have to make some tradeoffs depending on the type of project you are working on and the consequences that could happen if a severe bug is introduced. Could one of your customers lose money? Is sensitive information at risk if the project is hacked? Is it a software system that could potentially cause human injury? Or even worse – death?
There are tradeoffs for everything, but the main goal in software testing is to catch bugs before they are released, and the best way to do this is to maintain a suite of regression tests so that bugs aren’t introduced after implementing a new feature. We’ll talk about how to do that in a Vue on Rails approach with the idea of keeping it simple and will be geared towards low-consequence projects where your small team may or may not have the time and money to spend on testing. If you work on a high-consequence project, make sure you have the budget for a proper QA/QC cycle before releasing. That being said, a low-consequence project doesn’t mean you have to produce a low-quality product. There is a good balance between development and testing that aligns with the Vue on Rails approach of keeping things with Vue’s simplicity and the conventions of Rails.
TDD – To Drive or Not to Drive?
TDD or test-driven development is a development process that encourages writing tests first before writing the actual code for the software. The idea is to write a test for a feature or a test that reproduces an existing bug in the software, make sure the test fails as expected, then write the code that makes the test pass, and finally refactor code if necessary and make sure the test still passes.
In my experience I have seen many developers and product managers argue about the benefits of TDD. First, stop arguing about it. Every developer and team is different, some do strictly TDD , some do it on occasion, and some not at all. We’ll leave that decision up to your team. I find TDD to be useful in scenarios that are not very straightforward and a solution is not easily attained. The test first approach could help jumpstart the problem-solving process in certain scenarios. TDD is often considered as a way to drive correctness of code from developers’ perspective.
What about RSpec and BDD?
An extension of TDD called behavior-driven development or BDD is a different way of looking at testing from a user’s or stakeholder’s perspective and created in a way that all parties involved in a project can understand. RSpec is a testing framework inspired by BDD that is widely adopted in the Ruby on Rails community. BDD and the decision to use RSpec should up to your team as well. If Rails testing that is supported out of the box is sufficient for the project, then there is not much need to use RSpec.
General Testing Guidelines
Unit test methods that aren’t trivial in the business model.
Write at least one integration test for get actions show/index.
Write two tests for create/update actions. One for success/and one that fails on validation errors also known as the happy path vs. dark path.
Write system tests/e2e tests for core features.
If bugs occur, write a test integration/or unit to reproduce it and fix the bug.
System tests will catch a lot of bugs on the Vue side, but it may also help to write unit tests for Vue components.
UI/browser tests can be fragile so don’t overdo it. More time will be spent fixing fragile tests than actual development.
System Tests
System tests are important in environments that integrate Vue and Rails because it provides an end-to-end solution to testing the integration of the two technologies. The latest version of Rails supports system tests out of the box. System tests are essentially a wrapper around Capybara for writing clean and simple tests that interact directly with the browser using helper methods such as click_on, fill_in, and assert_selector. Before system tests were integrated into the Rails framework, configuration was necessary for this to work, and JavaScript was not supported out of the box.
So, the preceding code covers a happy path of a game from start to end with one winner and one loser. We’ve defined a couple helper methods – play and assert_piece. The play method clicks on the appropriate board position and assert_piece checks that the appropriate piece has been played. For this to work, we also need to define an id attribute on the related SVG element such as “X5” denoting that an X is visible in the fifth board index. Helper methods can be defined in the ApplicationSystemTestCase class since all our test cases for system tests extend from that class.
What about other scenarios such as a tied game? Or a different board configuration? We could create a few helper methods to cover these scenarios in a system test, but it is not the best approach. Each system test adds a bit of overhead to the time it takes to run your test suite. These scenarios would be better covered in a typical Rails unit test. If there is a UI scenario that needs to be covered, we could also use Jest and Vue test utilities to create a unit for a particular Vue component. This leads us into the discussion of such testing tools and frameworks that we can use for unit testing Vue components.
Vue Test Utilities and Jest
When unit testing Vue components, it is easy to get carried away with testing lots of edge cases just like it can be with system tests. So, it is important to think about the important pieces of a component. Take the Board component in the Tic Tac Toe game, for example. It would be unrealistic to test every possible board configuration, and we aren’t necessarily even interested in that since a game object is passed down as a prop. The important part of the component is testing that when a player clicks on a certain board position, it results in the appropriate action being called; in this case, it is the Vuex action for games_players/UPDATE. The vue-test-utils documentation has some good examples on testing Vuex action, so we will follow those guidelines for testing this scenario.
Documentation
Vue test utilities and Jest have great documentation and can be found respectively at https://vue-test-utils.vuejs.org and https://jestjs.io
Generating a Vue Unit Test
This runs any test that matches the *.test.js pattern with app/javascript.
Testing the Tic Tac Toe Board Component
A simple test that ensures an SVG element is rendered
A test that ensures the games_players/update Vuex action is called for an empty board position
A test for checking that the games_player/update Vuex action is not called when a position has already been played
Heroku – The Ninja Deployment
For most small- to medium-sized projects, we recommend Heroku as a platform for publishing applications, especially if you don’t have the resources for a dedicated DevOps team or system admin. The Ninja command covers the basics, and Heroku now supports Webpacker and will build our necessary Vue component assets along with any assets handled by sprockets. You’ll still need to think about how to handle migrations and will need to think about Redis addons to support background jobs and Action Cable if needed by your application.
Heroku vs. Virtual Private Server
There are plenty of cloud providers that offer virtual private servers (VPS) such as Digital Ocean, Amazon Web Services, Google Cloud, and many other providers. A VPS is a server that runs in a virtual environment on shared physical hardware. Hardware is maintained by the cloud provider, so swapping out bad disks, CPUs, etc. VPS providers often give you the choice of which operating system you would like to run with different flavors of Linux such as CentOS or Ubuntu. This may be a viable option for developers who also like to get into the nitty gritty of system administration or have more resources to support maintenance and monitoring of the servers. Be sure to weigh in on all the tradeoffs of this approach. We have listed the advantages and disadvantages of each option for you to evaluate.
Ninja deployment in one command
Third-party addon support such as Redis support
Automated SSL certificates for hobby level
No time consumed by system monitoring and administration
Expensive for large-scale projects (some may argue that cost is offset by not needing some large ops team)
Less control over the environment
More control of the environment. So control over networking and firewalls if you need a private environment.
Inexpensive (as little as $5/month for basic VPS).
Learning how to setup NGINX/Apache along with a production Ruby environment using Passenger or Unicorn is a good learning experience and a very valuable skill.
Learning how to setup and administer a database such as Postgres or MySQL is also a valuable skill.
Setting up a Rails-ready production environment takes time.
Deployments can be automated using tools such as Capistrano, but configuring Capistrano is often non-trivial.
Overhead of maintaining and monitoring a server such as monitoring memory, CPU, and disk usage. Some cloud providers offer automatic scaling, but other service providers may not.
Continuous Integration and Deployment
Whether we are using Heroku or a VPS, we can take advantage of various continuous integration services such as Travis CI to combine and automate our test, build, and deploy process. This will come in handy especially if we want our application to support different browsers. If you are developing in Chrome on a Mac, how do you know if our Vue components are supported on Firefox on a PC? A great service for this is BrowserStack and provides the ability to test various browsers on multiple operating systems. We can ensure our testing phase passes before the application is deployed to production. Also, if we need a finer grained release management, then we can choose only to deploy when a release is tagged in our git repo or under other conditions. We will demonstrate how to set up Travis CI to include a custom test and deploy process which integrates with BrowserStack and Heroku. To get started you’ll want to sign up for accounts at travis-ci.org and browserstack.com.
Travis CI
Testing stage which runs our unit and integration tests including our Vue unit tests
A staging deployment phase which gets our latest code up to our Heroku staging environment
A BrowserStack phase which runs our system tests against our Heroku staging URL
This configuration allows us to perform multiple tasks in parallel within the three stages we mentioned. Running our Rails unit and integration tests along with the Heroku deployment are straightforward as long as we encrypt and add our api key for Heroku using the travis encrypt command. Using BrowserStack to run our system tests against multiple browsers is not as trivial. This stage is broken up into four tasks, one for each browser. Next, we’ll discuss how to configure BrowserStack to work properly.
BrowserStack
DOH! ... always causing problems IE. Good thing we didn’t deploy it to production. Note that our Travis CI configuration doesn’t include a deployment process to production, but this can be easily done by adding another deployment stage once all previous stages have completed in a similar manner to our staging deployment. Following a good process for getting your app into production isn’t always clear especially for small development teams that also need to do their own DevOps, so we wanted to make the testing and deployment phase of a project straightforward and hope you appreciate our approach which aligns with our philosophy of simplicity.
Troubleshooting Common Issues of Vue on Rails
- 1.
In a Vue on Rails project with Webpacker, can I import the Vue on Rails project into Vue UI?
- 2.
In a Vue on Rails project with Webpacker, how do I change the compile path from app/javascript/packs to something else?
- 3.
In a Vue on Rails project with Webpacker, how do I use embedded Ruby (Erb) inside your Webpacker project?
- 4.
How do I fix the error “Cannot find module <name_of_module>”?
- 5.
How do I solve an error that says “TypeError: undefined is not an object (evaluating ‘options.components’)”?
- 6.
In a Vue on Rails project with Webpacker, how do I disable fingerprinting to create Vue.js widget component?
- 7.
How do I solve the following Vue error: “Did you register the component correctly? For recursive components, make sure to provide the name option.”
- 8.
Is there a way to use npm instead of yarn as the default package manager?
- 9.
For Vue on Rails project with Webpacker, how do I manage Node and Rails environments?
- 10.
For Vue on Rails projects with Webpacker, is there a way to bypass the IE 11 issues on Windows?
- 11.
For Vue on Rails projects with Webpacker, shouldn’t package X be in the dependencies instead of devDependencies?
- 12.
How do I solve this Heroku error: “No default language could be detected for this app”?
- 13.
How do I solve this Heroku error: “App not compatible with buildpack”?
This chapter assumes your Vue on Rails uses Webpacker as the default Webpack manager.
1. In a Vue on Rails project with Webpacker, can I import the Vue on Rails project into Vue UI?
With the Vue UI installed, you can import the Vue on Rails project by clicking Import > Go to the Vue on Rails project and click Import this project.
2. In a Vue on Rails project with Webpacker, how do I change the compile path from app/javascript/packs to something else?
You may wish to use a different directory to store your Vue components or javascript. You can change the directory name or the path at Webpacker.yml.
3. In a Vue on Rails project with Webpacker, how do I use embedded Ruby (Erb) inside your Webpacker project?
4. How do I fix the error “Cannot find module <name_of_module>”?
5. How do I solve an error that says “TypeError: undefined is not an object (evaluating ‘options.components’)”?
6. In a Vue on Rails project with Webpacker, how do I disable fingerprinting to create Vue.js widget component?
7. How do I solve the following Vue error: “Did you register the component correctly? For recursive components, make sure to provide the name option.”
8. Is there a way to use npm instead of yarn as the default package manager?
Now you can install npm packages using the npm install command.
9. For Vue on Rails project with Webpacker, how do I manage Node and Rails environments?
Rails uses RAILS_ENV and Node traditionally uses NODE_ENV environment variables to manage whether an app is in development or production. A pull request was merged to ensure these two variables are reconciled.
See https://github.com/rails/webpacker/pull/1511
10. For Vue on Rails projects with Webpacker, is there a way to bypass the IE 11 issues on Windows?
11. For Vue on Rails projects with Webpacker, shouldn’t package X be in the dependencies instead of devDependencies?
The answer lies in how Webpacker works. Webpacker produces JavaScript code called packs that can be embedded into Rails view via the javascript_pack_tag. This requires certain development dependencies to be in the dependencies of package.json.
For further discussion or research, please visit the following links:
https://github.com/rails/webpacker/issues/1212
https://github.com/rails/webpacker/issues/1178
12. How do I solve this Heroku error: “No default language could be detected for this app”?
See https://github.com/rails/webpacker/issues/739#issuecomment-327546884
13. How do I solve this Heroku error: “App not compatible with buildpack”?
Wrap-up and the Final Step
This concludes the testing, deployment, and troubleshooting chapter of our book. We’ve shown you how to go from the development phase to a well-tested and deployed production quality application using various testing tools and continuous integration methods. We move on to the final chapter to conclude our book and leave you with some words of wisdom.