I've got a typescript module that uses the browser's native Blob
. I'd like to test it in node so I need that same module to see a global fake Blob
implementation. A very simple fake blob implementation will do for me
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
}
}
But how do I inject it into the global namespace of node so that my code that normally runs in the browser will see it when I run the tests in node?
In other words imagine I have a class that's expected to return a native browser Blob
export class BlobMaker {
static makeTextBlob(text):Blob {
return new Blob([text], {type: 'text/text'});
}
}
And now I want to test it in node (not in the browser) as in
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');
});
});
This fails to compile because Blob
doesn't exist in node.
Apparently I can claim it exists by adding?
export interface Global extends NodeJS.Global {
Blob: Blob;
}
But I still need to inject my fake Blob
class above so that the code I'm testing will use it. Is there a way to do that or am I supposed to solve this some other way?
It doesn't seem like I can abstract Blob
into some kind of interface since I need the signature of makeTextBlob
to be an actual native browser Blob
and not some custom type.
I guess I get that I could pass a Blob factory deep into my library from the tests. Passing a Blob factory that deep in seems like overkill. I actually tried this by typescript complained. I think because it thinks the type being returned by BlobMaker.makeBlob
is different
Here's that code
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'});
}
}
Then in the tests
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!
});
});
I get an error there is no getType
method on Blob
. I'm guessing TS thinks the Blob
returned by BlobMaker.makeTextBlob
is the native one. I tried casting it
const blob = BlobMaker.makeTextBlob('foo') as Blob;
But it didn't like that either.
Effectively this seems like it would all be solved if I could just inject my Blob
class into the global namespace in node. So, how do I do that?