Setting up Rails 5 — Vue.js application testing
Rails 5 has been bundled with webpacker gem which offers great support for integrating popular JavaScript Frameworks (e.g. Vue, React Angular and Elm) for building Single-page application (SPA) front-end. Nevertheless, JavaScript testing facility doesn’t come out-of-the-box and it is left to developers to setup and configure it manually.
In this article, we are going to walk through step-by-step the creation of Vue.js application in Rails 5, and adding and configuring dependencies for JavaScript testing.
We are going to use Karma and Jasmine for our JavaScript testing. Karma is an awesome JavaScript test runner and I encourage you to also checkout Vojta’s talk for more on Karma.
System requirements
- Ruby 2.2+
- Rails 5.1+
- Node.js 6.0.0+
- Yarn 0.25.2+
Creating a new Vue.js app in Rails
If you do not have rails
installed yet, run the following command in your terminal:
gem install rails
Now, we can create a new rails application with --webpack
option:
rails new myapp --webpack
Or add to the Gemfile of your existing rails project:
# Gemfile
gem 'webpacker', '~> 3.5'
Remember to always run bundle install
from your terminal after changing your Gemfile.
Installing webpacker:
Run Webpacker installer from your terminal inside your project root directory.
rails webpacker:install
This will create webpack configuration files and executables, JavaScript app source directory and install JavaScript dependencies for the project.
# Files created by webpacker installer
app
└── javascript
│ └── packs
│ └── application.js
bin
├── webpack
└── webpack-dev-server
config
├── webpack
│ ├── development.js
│ ├── environment.js
│ ├── production.js
│ └── test.js
└── webpacker.yml
It will also turn on Yarn integrity check for Rails environment configurations.
# config/environments/development.rb
config.webpacker.check_yarn_integrity = true# config/environments/production.rb
config.webpacker.check_yarn_integrity = false
Integrate Vue in Rails
Run Webpacker Vue installer from your terminal:
rails webpacker:install:vue
This will add required configuration to Webpacker to enable Vue.js development, install dependencies and generate a sample component app/javascript/app.vue
and app/javascript/packs/hello_vue.js
which is an entry file to be included in our Rails view or layout files.
Use javascript_pack_tag
helper to link to the hello_vue.js
in the application layout file:
# app/views/layouts/application.html.erb
<%= javascript_pack_tag 'hello_vue' %>
Install JavaScript testing facilities
Add development dependencies to your package.json
file using yarn
command line tool from your terminal:
yarn add -D karma jasmine-core karma-jasmine karma-webpack karma-sourcemap-loader karma-spec-reporter karma-chrome-launcher @vue/test-utils
Configure Webpack
Edit config/webpack/test.js
file to match the following.
// config/webpack/test.js
process.env.NODE_ENV = process.env.NODE_ENV || 'development'const environment = require('./environment')// Re-generate manifest file when not in test env
// https://github.com/danethurber/webpack-manifest-plugin
environment.plugins.get('Manifest').opts.writeToFileEmit = process.env.NODE_ENV !== 'test'// Use inline-source-map devtool,
// https://webpack.js.org/configuration/devtool/
environment.config.set('devtool', 'inline-source-map')module.exports = environment.toWebpackConfig()
Configure Karma
Create new Karma configuration file in the project root and name it karma.conf.js
.
// karma.conf.js
const webpackConfig = require('./config/webpack/test.js')
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
plugins: [
'karma-jasmine',
'karma-webpack',
'karma-chrome-launcher',
'karma-spec-reporter',
'karma-sourcemap-loader'
],
files: [
'test/javascript/*.spec.js',
'test/javascript/**/*.spec.js'
],
exclude: [],
webpack: webpackConfig,
preprocessors: {
'test/javascript/*.spec.js': ['webpack', 'sourcemap'],
'test/javascript/**/*.spec.js': ['webpack', 'sourcemap']
},
reporters: ['spec'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
}
Update your package.json
file to include script for running karma:
// Add scripts section to package.json
{
"name": "myapp",
"private": true,
"scripts": {
"test": "NODE_ENV=test karma start"
},
...
}
Now, you can start Karma by running yarn test
from your terminal. The terminal will start watching *.spec.js
files under test/javascript/
directory as defined in karma.conf.js
. A chrome browser session for Karma will also open up.
Write some tests
Create new test file test/javascript/app.vue.spec.js
for testing app/javascript/app.vue
, the sample Vue component generated earlier.
// test/javascript/app.vue.spec.js
import { shallowMount } from '@vue/test-utils'
import App from '../../app/javascript/app'describe("app.vue", () => {
it("renders message", () => {
const wrapper = shallowMount(App)
expect(wrapper.text()).toEqual('Hello Vue!')
})
})
Upon saving the file, Karma will instruct Webpack to re-compile our Vue component and (re-)run the test. Back in the terminal where yarn test
is running, you will see the test is passing, something similar to mine as shown below (Chrome version, OS and execution time might defer).
# My `yarn test` terminalapp.vue
✓ renders messageChrome 67.0.3396 (Mac OS X 10.12.6): Executed 1 of 1 SUCCESS (0.003 secs / 0.003 secs)
TOTAL: 1 SUCCESS
Add new unit test
Let’s add new test for reversing the message data property of the component.
// test/javascript/app.vue.spec.js
...
it("reverse message text", () => {
const wrapper = shallowMount(App)
wrapper.vm.reverseMessage()
expect(wrapper.text()).toEqual('!euV olleH')
})
Save the file and you will see failing test in the terminal. Now, implement reverseMessage
method in app/javascript/app.vue
.
// app/javascript/app.vue
...
<script>
export default {
data: function () {
return {
message: "Hello Vue!"
}
},
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
}
</script>
Then all tests should pass.
# My `yarn test` terminalapp.vue
✓ reverse message text
✓ renders messageChrome 67.0.3396 (Mac OS X 10.12.6): Executed 2 of 2 SUCCESS (0.095 secs / 0.031 secs)
TOTAL: 2 SUCCESS
Bonus (debugging your test)
The fact that Karma runs tests on real device (e.g. Chrome browser) makes it super easy when it come to debugging your JavaScript module. You can simply drop debugger
statement inside your test files or Vue component where debugging is needed.
Enable DevTools for the Karma browser session then refresh the page.
Congratulation! You have just setup JavaScript testing for your Rails 5 — Vue.js application.
The repository for this post is available at https://github.com/lchanmann/rails5_vue/commits/master.
References
- https://github.com/rails/webpacker/blob/3-x-stable/README.md
- https://github.com/rails/webpacker/blob/3-x-stable/docs/testing.md
- https://webpack.js.org/
- https://github.com/danethurber/webpack-manifest-plugin
- https://karma-runner.github.io/2.0/index.html
- https://jasmine.github.io/
- https://vue-test-utils.vuejs.org/