DEV Community

Mario Saul
Mario Saul

Posted on • Edited on

Testing Vue.js in Rails with Webpacker and Jest

Originally published in WyeWorks blog.

In the project I'm working on, I was given the task of investigating how to integrate Vue.js with our existing Rails app. So I started reading the official guide, watching tutorials and reading various posts until I finally got a fully working Vue component.

Finally it was time to write some tests, but unfortunately, the Webpacker gem doesn't include testing configuration, so I had to do it on my own.

To my surprise, I found that there wasn't much documentation on how to do the setup. So I figured I'd make this post to share with you how I managed to eventually get it working.

1. Install Jest

I decided to go with Jest for no personal preference, I just noticed that vue-cli ships with it and went for it.

To install Jest all you have to do is run yarn add --dev jest from the root of your project.
Then, add a test script to your package.json:

{
  "scripts": {
    "test": "jest",
    ...
  },
  ...
}
Enter fullscreen mode Exit fullscreen mode

Now you can run your tests with yarn test.

2. Define the location of your tests

If you try to run yarn test at this point, you'll see that config/webpack/test.js failed. This is because of the way Jest looks for test files in the project. It basically executes all files matching .spec.js or .test.js in the whole project. In this case, the file matched *.test.js so it tried to run it as a test.

Since we don't want the Webpack config file as well as other files in the project that meet this criteria to run with our tests, we need to tell Jest where to look for them.

In my case since I'm using Rspec, I decided to point it to the spec/javascripts directory. But you can feel free to choose whichever directory fits your project the best.

To do this you just have to add roots to your package.json:

"jest": {
  "roots": [
    "spec/javascript"
  ]
},
Enter fullscreen mode Exit fullscreen mode

Note: If your package.json is quite big and you don't want to keep adding more stuff to it, you can define the jest configuration through the --config <path/to/js|json>; option. If you choose to do so, your package.json should now be like:

  {
    "scripts": {
      β€œtest”: β€œjest --config spec/javascript/jest.conf.js”,
      ...
    },
    ...
  }
Enter fullscreen mode Exit fullscreen mode

To verify it worked, you can create a spec/javascript/team.spec.js file with a simple test like:

test('there is no I in team', () => {
  expect('team').not.toMatch(/I/);
});
Enter fullscreen mode Exit fullscreen mode

Now run yarn test again and you should see a green "PASS" in the output meaning that it worked πŸŽ‰.

3. Babel to the rescue

Now that we got our first test working, let's take it one step further and try to test a Vue component.

The first thing you'd probably try is to create a file under the spec/javascript/ directory and name it something like my_component.spec.js. Then try to import your component from within your spec with the import statement like:

  import MyComponent from '../../app/javascript/my_component.vue';
Enter fullscreen mode Exit fullscreen mode

If you did try this, go ahead and run your tests. You'll see a SyntaxError: Unexpected token import in the output.

The problem here is that import is part of ECMAScript 6, so we need the help of a transpiler such as Babel.

To get it working you need to install two packages by running yarn add --dev babel-jest babel-preset-es2015 and add the "es2015" preset to your .babelrc file:

{
  "presets": ["es2015",
    ["env", {
            ...
Enter fullscreen mode Exit fullscreen mode

If you want to take it one step further, you can add moduleDirectories to your .package.json so you don't have to type out the full path to your modules:

"jest": {
    ...
  "moduleDirectories": [
    "node_modules",
    "app/javascript"
    ]
}
Enter fullscreen mode Exit fullscreen mode

So what we had before as

  import MyComponent from '../../app/javascript/my_component.vue';
Enter fullscreen mode Exit fullscreen mode

can now be written as

  import MyComponent from 'my_component.vue';
Enter fullscreen mode Exit fullscreen mode

4. Where's Vue?

If you followed every step, you should be getting a SyntaxError when trying to run your tests. This means that it successfully imported your component, but it can't yet understand .vue file's format.

Fortunately, we have a package that will take care of it for us, vue-jest.
So go ahead and run yarn add --dev vue-jest along with adding "moduleFileExtensions", "transform" and "mapCoverage" as explained in the README.
Your package.json should look something like this:

"jest": {
  ...
    "moduleFileExtensions": [
    "js",
    "json",
    "vue"
  ],
  "transform": {
    "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
    ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
  },
  "mapCoverage": true
}
Enter fullscreen mode Exit fullscreen mode

With moduleFileExtensions we no longer need the .vue when importing Single File Components. So what we had before as

  import MyComponent from 'my_component.vue';
Enter fullscreen mode Exit fullscreen mode

can now be written as

  import MyComponent from 'my_component';.
Enter fullscreen mode Exit fullscreen mode

You should now be able to use import seamlessly.

The rules in the transform section indicate which package is responsible for the transformation of testing files. In our case, we want vue-jest to handle all our .vue files, so they are converted to plain javascript before being handled by Jest.

mapCoverage is set in order to use source maps that the transformer emits. Jest will use them to try and map code coverage against the original source code when writing reports and checking thresholds.

Lastly, let's add the official unit testing utility library for Vue, vue-test-utils. Just run yarn add --dev @vue/test-utils and you are good to go.

You can now start writing tests for your Vue components πŸŽ‰

Top comments (1)

Collapse
 
mtancoigne profile image
Manuel Tancoigne

A bit late on this, but thank you; I was searching for a way to test Vue components in a Rails 6 application.

By the way, babel-preset-es2015 is deprecated in favor of babel-preset-env. All I had to do was to add the latter in place of the former and use this as .babelrc:

{
  "presets": [
    "env"
  ]
}
Enter fullscreen mode Exit fullscreen mode

For now, that's all I have to say, but will update if new things pops up... Time to write tests!