Post

How to set up JavaScript testing for Rails 7 with Jest

Prerequisites for Ruby, Rails, and JS environment

Here are the tools I used for this tutorial.

1
2
3
4
5
6
7
8
$> ruby --version  
=> 3.1.2  
$> rails --version  
=> 7.0.3.1  
$> node --version  
=> 18.6.0  
$> yarn --version  
=> 1.22.19  

Create new Rails app - no JavaScript yet

1
$> rails new myapp && cd myapp  

Now wait for a minute… okay ! you have now a fresh new default Rails app.

Add the bare minimum files

Create a controller as follow in app/controllers/welcome_controller.rb

1
2
3
# inside app/controllers/welcome_controller.rb  
class WelcomeController < ApplicationController  
end

Configure a default route in config/routes.rb as follow

1
2
3
4
5
# inside config/routes.rb  
Rails.application.routes.draw do  
  get "welcome/index"  
  root to: "welcome#index"  
end  

Add a view inside app/views/welcome/index.html.erb

1
2
<!-- inside app/views/welcome/index.html.erb -->
<h1>Hello !<h1>

Add and use an ES6 module

Create an ES6 module by creating a new file under app/javascript/magicAdd.js

1
2
3
4
5
// inside app/javascript/magicAdd.js
const  magicAdd = (a, b) => {
  return a + b;
}
export default  magicAdd;

And reference this file from the main pack :

1
2
3
4
5
6
7
8
9
// inside app/javascript/packs/application.js

// You can left pre-existing JavaScript, that's ok :)

import magicAdd from './magicAdd.js'

let a = magicAdd(2, 4);

console.log(`From mainjs, magicAdd result is ${a}`)

Stop your local web server, and run

1
$/myapp> bin/rails server

If no error is shown, you can run the local web server :

1
$/myapp> bin/rails s

Now open your browser and check the browser’s console to see if everything works properly.

Create a test for the JavaScript module

Create a new file inside test/javascript/magicAdd.spec.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// inside test/javascript/magicAdd.spec.js
import magicAdd from 'magicAdd.js'

describe('magicAdd', () => {

  test('add two numbers', () => {
    // given
    let result = 0;
    // when
    result = magicAdd(1, 3)
    // then
    expect(result).toEqual(4);
  });
  
});

Add JavaScript dependencies to run the unit test

We need now :

  • jest, which is our testing framework,
  • @babel/preset-env and babel-jest because of the use of ES6,
  • istanbul-reports to have a nice code coverage report.

So let’s run

1
$/myapp> yarn add --dev @babel/preset-env babel-jest jest istanbul-reports 

Configure Jest

Open package.json, it should look like this :

1
2
3
4
5
6
7
8
{
  "devDependencies": {
    "@babel/preset-env": "^7.18.10",
    "babel-jest": "^28.1.3",
    "istanbul-reports": "^3.1.5",
    "jest": "^28.1.3"
  }
}

Add the following property to package.json, so that Jest will know which directories and file to watch, and which one to ignore :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
   // all properties as above remain the same...
   "devDependencies": {
    "@babel/preset-env": "^7.18.10",
    "babel-jest": "^28.1.3",
    "istanbul-reports": "^3.1.5",
    "jest": "^28.1.3"
  },
   // add the following property to package.json
  "jest": {
    "testPathIgnorePatterns": [
      "node_modules/",
      "config/webpack/test.js",
      "vendor/bundle/ruby"
    ],
    "moduleDirectories": [
      "node_modules",
      "app/javascript"
    ],
    "collectCoverage": true,
    "coverageReporters": [
      "text",
      "html"
    ],
    "coverageDirectory": "coveragejs"
  }

Configure babel with your Rails app

Add the following code inside babel.config.js, at the root of your Rails project.

1
2
3
module.exports = { 
  presets: ["@babel/preset-env"],
};

Launch tests

That’s the big moment.

Run

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
$/myapp> yarn jest

**yarn run v1.22.19**

**PASS** **test/javascript/****magicAdd.spec.js**

**magicAdd**

**✓**  **add two numbers (2 ms)**

  

**-------------|---------|----------|---------|---------|-------------------**

**File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s**

**-------------|---------|----------|---------|---------|-------------------**

**All files** **|** **100** **|** **100** **|** **100** **|** **100** **|**

**magicAdd.js** **|** **100** **|** **100** **|** **100** **|** **100** **|**

**-------------|---------|----------|---------|---------|-------------------**

**Test Suites:** **1 passed****, 1 total**

**Tests:** **1 passed****, 1 total**

**Snapshots:** **0 total**

**Time:** **0.656 s**

**Ran all test suites.**

**✨  Done in 1.54s.**

And open coveragejs/index.html in your browser to get coverage.

Summary

Nothing complicated, but as often with npm projects, you have to take of dependencies and insert libs in the right order. Start from a simple example like this one to understand how things work, we hope it helped!

This post is licensed under CC BY 4.0 by the author.