9

How do I configure Jasmine in the Rails 6 environment (where Webpack replaces the asset pipeline for Javascript) so I can test the Javascript modules I've written for my app?

I installed the jasmine gem, ran rails generate jasmine:install, and edited jasmine.yml to point to the location of my Javascript source and specs.

The problem is that I can't use import/export statements. (For example, attempting to load my first module to test results in this error in Chrome: Uncaught SyntaxError: Unexpected token 'export')

From what I can tell, I need to set up Jasmine to use babel; but, I'm not having any luck finding instructions on how to do this in the new Rails 6 layout.

Zack
  • 6,232
  • 8
  • 38
  • 68

1 Answers1

6

Yes, you're right. The main problem of jasmine-gem is that it doesn't pipe the spec through babel. Let me post the quickest solution to your problem and after that, I will think of the possible implementation of a similar approach in jasmine-gem.

The main idea is to pipe the specs through the rails webpack as long as it has all the required babel configurations.

  1. Install jasmine-core since we will not use jasmine-gem in this solution
    yarn add jasmine-core -D
    
  2. Now create two additional webpack packs. One is for Jasmine and will contain only Jasmine and the test runner

    // app/javascript/packs/jasmine.js
    
    import 'jasmine-core/lib/jasmine-core/jasmine.css'
    import 'jasmine-core/lib/jasmine-core/jasmine-html.js'
    import 'jasmine-core/lib/jasmine-core/boot.js'
    import 'jasmine-core/images/jasmine_favicon.png'
    

    And the second one for your application code and the specs

    // app/javascript/packs/specs.js
    
    // First load your regular JavaScript (copy all the JavaScript imports from your main pack).
    let webpackContext = require.context('../javascripts', true, /\.js(\.erb)?$/)
    for(let key of webpackContext.keys()) { webpackContext(key) }
    
    // Then load the specs
    let specsContext = require.context('../spec', true, /\.js(\.erb)?$/)
    for(let key of specsContext.keys()) { specsContext(key) }
    

    Pay attention to your '../javascripts' and '../spec' paths. For me it looked like '../../assets/javascripts' and '../../../spec' respectevly.

  3. Then add the Webpack ProvidePlugin for Jasmine (add this code to config/webpack/environment.js)

    // config/webpack/environment.js
    
    const webpack = require('webpack')
    
    environment.plugins.prepend('Provide', new webpack.ProvidePlugin({
       jasmineRequire: 'jasmine-core/lib/jasmine-core/jasmine.js',
    }))
    
  4. Add Jasmine ranner page to your application

    # config/routes.rb
    
    Rails.application.routes.draw do
      # ...
    
      if Rails.env.development? || Rails.env.test?
        get 'jasmine', to: 'jasmine#index'
      end
    end
    
    # app/controllers/jasmine_controller.rb
    
    class JasmineController < ApplicationController
      layout false
    
      def index
      end
    end
    
    # app/views/jasmine/index.html.haml
    
    <html>
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
      <%= stylesheet_pack_tag 'jasmine', :media => 'all' %>
    </head>
    <body>
      <%= javascript_pack_tag 'jasmine' %>
      <%= javascript_pack_tag 'specs' %>
    </body>
    </html>
    
  5. Now your Jasmine should work on /jasmine route

This answer is prepared on the basis of this post, however, I've rechecked the instructions on ruby 2.6.3, rails 6.0.2, added appropriate changes to the recommendations and prove that this works.

Please, let me know if my answer was helpful for you or you need some additional information. However, I'm going to work on a solution that will succeed with jasmine gem or similar implementation.

Sergey Mell
  • 7,780
  • 1
  • 26
  • 50
  • Can I ask you to test somethin? I followed these instructions, jasmine is working, but suddenly `bootstrap.min.js` is throwing an error that basically means `jquery` is not being loaded before `bootstrap`. However, ]I can't find what in this code changes JS load order... especially since my bootstrap is being loaded via CDN in the application layout after the `javascript_pack_tag 'application'` line and my `application.js` already has a `require('jquery')`. If you have this set-up in a local environment, can you load bootstrap via CDN in application layout, and see if it works? – james Feb 19 '20 at 00:27
  • I figured it out. Step 3 was overriding the code that added the jquery plugin. This answer fixed it: https://stackoverflow.com/questions/51447443/adding-plugin-to-webpack-with-rails – james Feb 19 '20 at 00:54