4

我有一个由 Rails 提供的 AngularJS (v.1.7) 应用程序。我刚从 Sprockets 搬到了 Webpack。在尝试将我的 Jasmine 测试迁移到 Jest 时。我遇到了一个问题html-loader,我用它来将我的指令模板导入指令。

对于我导入模板的一个简单指令,Jest 无法加载测试,因为html-loader失败并出现错误

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)

我正在遵循此 SO 帖子此 npm 包 html-loader-jest中的建议。在我的package.json中,我添加了以下jest配置

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

和支持文件

// jest/support/html_loader.js
const htmlLoader = require("html-loader");
module.exports = {
  process: (src) => htmlLoader(src) 
};

堆栈跟踪将我指向html-loader(来自 node_modules)

// node_modules/html-loader/node_modules/loader-utils/lib/getOptions.js
function getOptions(loaderContext) {
  const query = loaderContext.query;
...

如果我在 Jest 运行期间追踪到这里,我会发现这个loaderContext未定义(如错误报告所示)。

我的问题是......这是使用它的正确方法htmlLoader吗?如果是这样,我应该期待什么loaderContext?有没有办法让开玩笑来提供这个价值?或者这不是htmlLoader应该在实际 Webpack 管道之外调用的方式。

这个问题只发生在我通过jest. webpack正确编译应用程序的所有资产。

库版本

html-loader: 1.0.0
webpack: 4.42.1
jest: 25.2.4

代码(为清楚起见)

// 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();
  })
});
4

1 回答 1

2

嗯,我想通了。似乎在jest运行时,它没有传递正确的上下文(正如我在上面所怀疑的那样)导致getOptions调用失败。

解决方案是编写一个非常简单的加载器,jest它不会打扰getOptions. 我能够jest/support/html_loader.js用以下代码替换我的代码(基本上抄自webpack-contrib/raw-loader.

// jest/support/html-loader.js
module.exports = {
  process: (content, _path) => {
    // escape newlines
    const json = JSON.stringify(content)
          .replace(/\u2028/g, '\\u2028')
          .replace(/\u2029/g, '\\u2029');
    return `module.exports = ${json};`
  }
};

这基本上将模板作为导出模板的 js 模块返回。replace似乎正在处理换行符。

我希望这可以节省其他人的一些挖掘。

于 2020-04-02T23:52:41.267 回答