Jannis
Jannis

Reputation: 17315

How can I use my webpack's html-loader imports in Jest tests?

I am just getting started with the Jest test framework and while straight up unit tests work fine, I am having massive issues testing any component that in its module (ES module via babel+webpack) requires a HTML file.

Here is an example:

import './errorHandler.scss';
import template from './errorHandler.tmpl';

class ErrorHandler {
    ...

I am loading the component specific SCSS file which I have set in Jest's package.json config to return an empty object but when Jest tries to run the import template from './errorHandler.tmpl'; line it breaks saying:

/Users/jannis/Sites/my-app/src/scripts/errorHandler/errorHandler.tmpl.html:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){<div class="overlay--top">
                                                                                         ^
    SyntaxError: Unexpected token <

        at transformAndBuildScript (node_modules/jest-runtime/build/transform.js:284:10)

My Jest config from package.json is as follows:

"jest": {
    "setupTestFrameworkScriptFile": "<rootDir>/test/setupFile.js",
    "moduleDirectories": ["node_modules"],
    "moduleFileExtensions": ["js", "json", "html", "scss"],
    "moduleNameMapper": {
        "^.+\\.scss$": "<rootDir>/test/styleMock.js"
    }
}

It seems that the webpack html-loader is not working correctly with Jest but I can't find any solution on how to fix this.

Does anyone know how I can make these html-loader imports work in my tests? They load my lodash template markup and i'd rather not have these at times massive HTML chunks in my .js file so i can omit the import template from x part.

PS: This is not a react project, just plain webpack, babel, es6.

Upvotes: 18

Views: 14990

Answers (6)

nicoespeon
nicoespeon

Reputation: 369

For Jest 28+ you can use jest-html-loader to make Jest work with code that requires HTML files.

npm install --save-dev jest-html-loader

In your jest config, add it as a transformer for .HTML files:

"transform": {
  "^.+\\.html?$": "jest-html-loader"
},

Upvotes: 5

WitoldW
WitoldW

Reputation: 898

For Jest > 28.x.x with html-loader:

  1. Create a custom transformer as documented here.
jest/html-loader.js
const htmlLoader = require("html-loader");

module.exports = {
  process(sourceText) {
    return {
      code: `module.exports = ${htmlLoader(sourceText)};`,
    };
  },
};
  1. Add it to your jest config.
jest.config.js
...

  // A map from regular expressions to paths to transformers
  transform: {
    "^.+\\.html$": "<rootDir>/jest/html-loader.js",
  },

...

It will fix the error : Invalid return value: process() or/and processAsync() method of code transformer found at "<PATH>" should return an object or a Promise resolving to an object.

Upvotes: 6

zucker
zucker

Reputation: 1112

html-loader-jest doesn't work for me. My workaround for this:

"transform": {
  '\\.(html)$': '<rootDir>/htmlTemplateMock.html'
}

htmlTemplateMock.html is empty file

Upvotes: 0

Samuel K
Samuel K

Reputation: 314

A bit late to the party, but wanted to add that there is also this html-loader-jest npm package out there to do this if you wanted to go that route.

Once you npm install it you will add it to your jest configuration with

"transform": {
        "^.+\\.js$": "babel-jest",
        "^.+\\.html?$": "html-loader-jest"
    }

Upvotes: 11

bnjmnhndrsn
bnjmnhndrsn

Reputation: 293

I encountered this specific problem recently and creating your own transform preprocesser will solve it. This was my set up:

package.json

"jest": {
    "moduleFileExtensions": [
      "js",
      "html"
    ],
    "transform": {
      "^.+\\.js$": "babel-jest",
      "^.+\\.html$": "<rootDir>/test/utils/htmlLoader.js"
    }
 }

NOTE: babel-jest is normally included by default, but if you specify a custom transform preprocessor, you seem to have to include it manually.

test/utils/htmlLoader.js:

const htmlLoader = require('html-loader');

module.exports = {
    process(src, filename, config, options) {
        return htmlLoader(src);
    }
}

Upvotes: 25

robi24
robi24

Reputation: 606

Maybe your own preprocessor file will be the solution:

ScriptPreprocessor

Custom-preprocessors

scriptpreprocessor: The path to a module that provides a synchronous function from pre-processing source files. For example, if you wanted to be able to use a new language feature in your modules or tests that isn't yet supported by node (like, for example, ES6 classes), you might plug in one of many transpilers that compile ES6 to ES5 here.

I created my own preprocessor when I had a problems with my tests after added transform-decorators-legacy to my webpack module loaders.

Upvotes: 0

Related Questions