HOME / ARTICLE

从 PhantomJS 到 babel-polyfill 的一次 debug

  • 2018/06/05

最近在写 JavaScript 项目的单元测试时遇到这样一个问题,一个测试用例简单到不可能有错误,但是还是报错了,类似于这样。(这个例子是经过简化的,以便说明问题)

import ExampleModel from '../example.js';

describe('Test Model', () => {
  let model;
  beforeEach(() => {
    model = new ExampleModel();
  });

  it('should pass', () => {
    expect(true).to.be(true);
  });
});

报错:

undefined is not a constructor (evaluating name.endsWith('%'))

错误内容看不懂,但至少知道是在执行 name.endsWith('%') 出错了。

测试是使用 PhantomJS 执行的,于是 Google 求助 「PhantomJS endsWith」,从搜索结果第一条就知道了答案,甚至都不用点进去看;

原因是 PhantomJS 不支持 ES6 特性,并不惊讶。但是我使用了 babeljs, 转化后的文件不应该能在 ES5 环境正常运行吗?去 babeljs 官网溜达一圈,看到这段文字

babel 是一个语法转换器,像 startsWith 这类新方法需要使用 polyfill 才能运行在 ES5 的环境中。到这里开头提到的问题的原因就很清楚了。

那么结束了吗?恐怕没有。因为在项目中的确是有引入 babel-polyfill 的,但是测试是按组件的,也就是说,在执行测试时,babel 转化后的代码里是没有加入全局的 polyfill 的。这个问题我一定很久之前遇到过,但没留意。因为我在 karma 的配置文件中发现了这样的配置。

files: [
  './node_modules/promise-polyfill/promise.js',
  './index.js',
],

当时一定是在执行测试时发现没有 Promise 对象,然后在 StackOverflow 上找到一段这样的代码,复制过来正好能用,就不了了之了。 所以一条龙解决方式是

files: [
  './node_modules/@babel/polyfill/dist/polyfill.min.js'
  './index.js',
]

直接把 polyfill 文件加进来就 Ok 了。