如何将Global注入打字稿进行测试?

时间:2018-07-12 04:36:54

标签: typescript

我有一个使用浏览器的本机Blob的打字稿模块。我想在节点中对其进行测试,因此我需要相同的模块来查看全局假Blob的实现。一个非常简单的假blob实现将为我做

class Blob {

  parts?: any;
  options?: any;

  constructor(parts: any, options?: any) {
    this.parts = parts;
    this.options = options;
  }

  getType():string {
    return options.type;  // I know, hacky by just a demo
  }
}

但是如何将其注入到节点的全局名称空间中,以便当我在节点中运行测试时,通常在浏览器中运行的代码可以看到它?

换句话说,假设我有一个期望返回本机浏览器Blob

的类
export class BlobMaker {
  static makeTextBlob(text):Blob {
    return new Blob([text], {type: 'text/text'});
  }
}

现在我要像在

中那样在节点(而不是浏览器)中对其进行测试
import { BlobMaker } from '../src/blob-maker';
import * as expect from 'expect';

describe('BlobMaker', () =>  {
  it('makes a text blob', () => {
    const blob = BlobMaker.makeTextBlob('foo');

    expect(blob.getType()).equalTo('text/text');
  });
});

由于Blob在节点中不存在,因此无法编译。

显然我可以通过添加声明它存在吗?

export interface Global extends NodeJS.Global {
  Blob: Blob;
}

但是我仍然需要在上面注入伪造的Blob类,以便我正在测试的代码可以使用它。有办法做到这一点还是我应该以其他方式解决呢?

由于我需要Blob的签名才能成为实际的本机浏览器makeTextBlob,而不是某些自定义类型,因此我似乎无法将Blob抽象到某种接口中。

我想我可以从测试中将Blob工厂传递到我的库中。通过一个深处的Blob工厂似乎有些过分。我实际上是通过打字稿尝试过的。我认为是因为它认为BlobMaker.makeBlob返回的类型是不同的

这是代码

let makeBlob = function(...args):Blob {
   return new Blob(...args);
};

export function setMakeBlob(fn):void {
   makeBlob = fn;
};

export class BlobMaker {
  static makeTextBlob(text):Blob {
    return makeBlob([text], {type: 'text/text'});
  }
}

然后在测试中

import { BlobMaker, setMakeBlob } from '../src/blob-maker';
import { Blob } from "./fake-blob';
import * as expect from 'expect';

describe('BlobMaker', () =>  {
  it('makes a text blob', () => {
    setMakeBlob(function(parts, options) {
      return new Blob();
    });

    const blob = BlobMaker.makeTextBlob('foo');

    expect(blob.getType()).equalTo('text/text');   // ERROR!
  });
});

我收到一个错误,getType上没有Blob方法。我猜TS认为Blob返回的BlobMaker.makeTextBlob是本机的。我尝试过铸造

    const blob = BlobMaker.makeTextBlob('foo') as Blob;

但它也不喜欢。

实际上,如果我可以将Blob类注入node的全局名称空间中,这似乎将全部解决。那么,我该怎么做?

1 个答案:

答案 0 :(得分:1)

这就是我解决的方法。希望它不是太可怕了

首先根据this Q&A,我可以通过添加单独的文件来扩展节点中的全局对象。就我而言,我制作了test.d.ts并将其放入

declare namespace NodeJS {
    interface Global {
        Blob: any
    }
}

然后在我的测试中,我做到了

import { BlobMaker } from '../src/blob-maker';
import * as expect from 'expect';

class Blob {

  parts?: any;
  options?: any;

  constructor(parts: any, options?: any) {
    this.parts = parts;
    this.options = options;
  }

  getType():string {
    return options.type;  // I know, hacky by just a demo
  }
}

describe('BlobMaker', () =>  {
  it('makes a text blob', () => {

    global.Blob = Blob;

    const blob = BlobMaker.makeTextBlob('foo');

    expect(blob.getType()).equalTo('text/text');
  });
});

,它正在工作。我可能应该将修补global.Blob的部分移到另一个模块,但这至少建议一个解决方案。