I've got an AngularJS (v.1.7) app served by Rails. I just moved from Sprockets to Webpack.
While trying to migrate my Jasmine tests to Jest. I ran into an issue with html-loader which I'm using to import my directive templates into the directive.
For one simple directive where I import the template, Jest fails to load the test because the html-loader fails with the error
TypeError: Cannot read property 'query' of undefined
1 | const htmlLoader = require("html-loader");
2 | module.exports = {
> 3 | process: (src) => htmlLoader(src)
| ^
4 | };
5 |
at getOptions (node_modules/html-loader/node_modules/loader-utils/lib/getOptions.js:6:31)
I was following recommendations in this SO post and from this npm package html-loader-jest. In my package.json, I've added the following jest config
"jest": {
"moduleFileExtensions": [
"js",
"html"
],
"transform": {
"^.+\\.js$": "babel-jest",
"^.+\\.html$": "<rootDir>/jest/support/html_loader.js"
},
...
}
And the support file
// jest/support/html_loader.js
const htmlLoader = require("html-loader");
module.exports = {
process: (src) => htmlLoader(src)
};
The stacktrace points me to html-loader (from node_modules)
// node_modules/html-loader/node_modules/loader-utils/lib/getOptions.js
function getOptions(loaderContext) {
const query = loaderContext.query;
...
If I trace into here during the Jest run, I find this loaderContext undefined (as the error reports).
My question is... is this the correct way to use this htmlLoader? If so, what should I expect loaderContext to be? Is there a way to get jest to provide that value? Or is this not the way the htmlLoader is supposed to be called outside of the actual Webpack pipeline.
This problem only happens when I'm running via jest. webpack properly compiles the all assets for the app.
library versions
html-loader: 1.0.0
webpack: 4.42.1
jest: 25.2.4
code (for clarity)
// mailer.js
import angular from "angular";
import ngInject from "@js/ng-inject";
import template from "./index.html";
const mailer = ngInject(function () {
return {
restrict: "E",
scope: {
text: "@",
},
template: template,
};
});
angular.module("app-directives").directive("mailer", mailer);
<!-- index.html -->
<a>{{text}}</a>
// mailer.test.js
import expect from "expect";
import "./mailer";
describe("app-directives.mailer", function () {
it("works", () => {
expect(true).toBeTruthy();
})
});