Francesco Belladonna
Francesco Belladonna

Reputation: 11689

How to setup Karma + Jasmine to use ES6 modules

I'm a bit stuck on this. I have a complex stack composed of middleman, karma, jasmine, babeljs to build a static website.

Considering this is an experiment, I wanted to use ES6 with modules. Everything fine on middleman side, though, I'm having hard times setting up karma + jasmine for testing.

The main problem lies within babel: if you set it to use modules: "ignore" you have to manually use System.import for all your modules in your specs, which is something I don't want. I would like to use the ES6 syntax, but if I set modules: "system", babeljs wraps all my tests into System.register, with something like the following:

System.register(["mymodule"], function (_export) {
  "use strict";

  var Mymodule;
  return {
    setters: [function (_mymodule) {
      Mymodule = _mymodule["default"];
    }],
    execute: function () {

      console.log("I'm here!!!");
      console.log(Mymodule);

      describe("Mymodule", function () {

        it("has version", function () {
          expect(Mymodule.VERSION).toEqual("1.0.0");
        });


      });
    }
  };
});

So the tests are not automatically executed. I then created the following script to work around it (which is included after all specs are included):

basePath = "/base/spec/"

modules = []

for own fileName, fileHash of window.__karma__.files
  if fileName.indexOf(basePath) is 0
    isRunner   = fileName.indexOf("spec_runner") >= 0
    isRunner ||= fileName.indexOf("spec_helper") >= 0
    unless isRunner
      moduleName = fileName.replace(basePath, "")
      moduleName = moduleName.replace(".js", "")
      modules.push(path: fileName, name: moduleName)

mappedModules = {}
baseSpecsPath = "http://localhost:9876"

for module in modules
  mappedModules[module.name] = baseSpecsPath + module.path

System.config
  baseURL: "http://localhost:4567/javascripts/"
  map:     mappedModules

for module in modules
  System.import(module.name)

This code is simple: it prepares the map configuration for SystemJS, I can correctly load modules from my app (located in http://localhost:4567) and tests wrapped in System.register (located in http://localhost:9876).

However, my tests are not run, and no error reported. Even worse, I correctly get the message logged "I'm here!!!" and Mymodule is logged in console correctly. I even tried to log the value of describe and it's correctly a Suite object. So, why on earth my tests are not run? (The it block is never run)

What solutions do I have? I'm ok with changing the setup a bit to get it working, but I want to keep the following things: Middleman, ES6 modules, no dynamic module loading (all my modules are exposed, in the end, in a single file or required with a bunch of <script> tags), jasmine

Upvotes: 5

Views: 969

Answers (1)

Francesco Belladonna
Francesco Belladonna

Reputation: 11689

I finally solved the issue. I include this file as last one:

basePath = "/base/spec/"

modules = []

for own fileName, fileHash of window.__karma__.files
  if fileName.indexOf(basePath) is 0
    isRunner   = fileName.indexOf("spec_runner") >= 0
    isRunner ||= fileName.indexOf("spec_helper") >= 0
    unless isRunner
      moduleName = fileName.replace(basePath, "")
      moduleName = moduleName.replace(".js", "")
      modules.push(path: fileName, name: moduleName)

mappedModules = {}
baseSpecsPath = "http://localhost:9876"
specModules   = []

for module in modules
  mappedModules[module.name] = baseSpecsPath + module.path
  specModules.push(module.name)

System.config
  baseURL: "http://localhost:4567/javascripts/"
  map:     mappedModules

moduleImports = specModules.map (moduleName) ->
  System.import(moduleName)

Promise.all(moduleImports).then ->
  window.__karma__.start     = window.__lastKarmaStart__
  window.__lastKarmaStart__  = null
  delete window.__lastKarmaStart__
  window.__karma__.start()

It does the following things:

  • Temporary disable karma start function replacing it with an empty one
  • Fetches each test stored in a System.register, run System.import for all tests (waits them with Promise.all)
  • After all imports are completed, it attaches back __karma__start and executes it, running Jasmine

Upvotes: 2

Related Questions