Jasmine: Fixing common errors during initialization

Due to the way we setup Jasmine tests in our projects, you may run into various errors when Jasmine boots.

Setting jasmineRequire on undefined

Jasmine 4 may fail with an error like this:

Uncaught TypeError: Cannot set properties of undefined (setting 'jasmineRequire')

This is due to issues in Jasmine's environment detection Show archive.org snapshot . It must be fixed by patching the Jasmine sources.

Fix for Webpacker

Add the package string-replace-loader to your package.json. If you're on Webpacker 5 (Webpack 4) the latest version you can use is 2.x.

Now add the following loader to your config/webpack/environment.js:

environment.loaders.prepend('fix-jasmine4-global-detection', {
  test: /jasmine-core\/lib\/jasmine-core\/jasmine\.js$/,
  use: [{
    loader: 'string-replace-loader',
    options: {
      search: 'window.toString() === \'[object GjsGlobal]\'',
      replace: 'window.toString() === \'[object Window]\''
    }
  }]
})

Fix for ESBuild / jsbundling-rails

Add the package esbuild-plugin-text-replace to your package.json.

Now add the following plugin to your esbuild.config.js:

const textReplace = require('esbuild-plugin-text-replace')
const esbuild = require('esbuild')

esbuild.build({
  ...
  plugins: [
    textReplace({
      include: /jasmine-core\/lib\/jasmine-core\/jasmine\.js$/,
      pattern: [
        ['let jasmineRequire;', 'let jasmineRequire; const global = window;'], // Make Jasmine available at window.jasmine
        ['const loadedAsBrowserEsm =', 'const loadedAsBrowserEsm = false &&'], // Disable module detection in Jasmine 6.0
      ],
    }),
  ],
})

Jasmine 6

Starting with version 6, Jasmine tries to detect if it's running in a module context as this is officially unsupported. It then renders a deprecation warning message:

DEPRECATION: jasmine-core isn't an ES module but it was loaded as one. This is not a supported configuration.
Note: This message will be shown only once. Set the verboseDeprecations config property to true to see every occurrence.

The detection is a flawed when your <script> tag has a type="module" -- which is needed for code splitting in esbuild.

Note how we patch Jasmine's code to assume global = window which makes Jasmine be placed on window.jasmine.
Doing that actually doesn't run Jasmine in a module. But its detection looks at document.currentScript which is unavailable for type="module" script tags.

Because of this (and only when also placing it on window), we also need to switch off its detection with a simple false &&.

Jasmine < 4.3

If you are on Jasmine < 4.3.0, use var instead of let in the code above.

Missing getJasmineRequireObj()

If you get this error:

Uncaught ReferenceError: getJasmineRequireObj is not defined

then you need a manually expose getJasmineRequireObj() to your specs.

Fix for Webpack

Add a file

// app/webpack/spec/support/jasmine_provider.js
import jasmineRequire from 'jasmine-core/lib/jasmine-core/jasmine.js'

export default function getJasmineRequireObj() {
  return jasmineRequire;
}

Then expose the provider in your config/webpack/environment.js:

const webpack = require('webpack')

environment.plugins.prepend('Provide', new webpack.ProvidePlugin({
  getJasmineRequireObj: ['spec/support/jasmine_provider.js', 'default'],
}))

Fix for ESBuild / jsbundling-rails

TODO.

Henning Koch