如何在typescript中注入全局变量进行测试?

如何在typescript中注入全局变量进行测试?,typescript,Typescript,我有一个typescript模块,它使用浏览器的本机脚本。我想在节点中测试它,所以我需要相同的模块来查看全局伪Blob实现。一个非常简单的假blob实现就可以了 class Blob { parts?: any; options?: any; constructor(parts: any, options?: any) { this.parts = parts; this.options = options; } getType():string {

我有一个typescript模块,它使用浏览器的本机脚本。我想在节点中测试它,所以我需要相同的模块来查看全局伪
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'});
  }
}
现在我想在节点(而不是浏览器)中测试它,如中所示

这无法编译,因为节点中不存在
Blob

显然,我可以通过添加来声明它的存在

export interface Global extends NodeJS.Global {
  Blob: Blob;
}
但是我仍然需要在上面注入我的伪
Blob
类,以便我正在测试的代码将使用它。有办法吗?或者我应该用其他方法来解决这个问题吗

似乎我无法将
Blob
抽象为某种接口,因为我需要
makeTextBlob
的签名作为实际的本机浏览器
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!
  });
});
我发现一个错误,
Blob
上没有
getType
方法。我猜TS认为
BlobMaker.makeTextBlob
返回的
Blob
是本地的。我试着投下它

    const blob = BlobMaker.makeTextBlob('foo') as Blob;
但它也不喜欢这样


实际上,如果我可以将我的
Blob
类注入节点中的全局名称空间,这一切似乎都会得到解决。那么,我该怎么做呢?

我就是这样解决的。希望不会太可怕

首先,我可以通过添加一个单独的文件来扩展节点中的全局对象。在我的例子中,我做了
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
的部分移动到另一个模块,但它至少提出了一个解决方案。

我的印象是
///对不起,这是我第一次使用打字脚本,但这如何帮助Blob制作者找到
Blob
?哦,等等,我误读了,你的
Blob
是一个
类,不是
接口
(这应该意味着它在一个普通的
.ts
文件中。你的
BlobMaker
模块应该
从“/Blob”
导入Blob,或者从任何导出它的地方导入Blob。即使它被理解为一个全局变量,在使用TypeScript时作为模块的一部分处理它要容易得多。我不确定这有什么帮助。这段代码仍然需要s在浏览器中运行并返回浏览器本地
Blob
(更新了问题)。我只想在node中运行的测试中使用一个假blob来测试它。我自己还不是特别精通TypeScript,但从这里的上下文来看,我认为您应该考虑模拟
blob
模块。我发现这可能对您有用,也可能对您没有用处,但您可以做的是重写
blob
要处理的文件只有在
global.Blob
上没有定义的情况下,才能使用
global.Blob
。这样做是有效的,但为了确保它不会潜在地干扰其他测试,我会通过重写
descripe('BlobMaker',()=>{const{Blob}=global;beforeach(()=>{global.Blob=require('./Blob');})更明确地说明模拟;afterEach(()=>{global.Blob=Blob;});it(…);});
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');
  });
});