I'm writing a unit test for a class which uses browser WebAPI interface.
I use ts-mockito to mock the interface (a WebGL2RenderingContext in my case).
When I run the test, Node throws ReferenceError: WebGL2RenderingContext is not defined
which is understandable, because the test is run under NodeJS environment, not browser, so the class/interface doesn't exist.
Is there any way to make NodeJS environment aware of the WebAPI interfaces, so that it's possible to be mocked?
NOTE: Since it's a unit test, it should NOT be run on a real browser.
jsdom seems to be a possible solution, but I have no idea how to mock it with ts-mockito.
The following snippet illustrate what I'm trying to do:
import { mock, instance, verify } from 'ts-mockito'
// ========== CLASS ==========
class DummyClass {
dummyMethod() : void {}
}
class TestedClass {
static testDummy(dummy : DummyClass) : void {
dummy.dummyMethod();
}
static testGlCtx(glCtx : WebGL2RenderingContext) : void {
glCtx.flush();
}
}
// ========== TEST ==========
describe('DummyClass', () => {
// This test passed successfully
it('works fine', () => {
const mockDummy = mock(DummyClass);
TestedClass.testDummy( instance(mockDummy) );
verify( mockDummy.dummyMethod() ).once();
});
});
describe('WebGL interface', () => {
it('works fine', () => {
// This line failed with 'ReferenceError: WebGL2RenderingContext is not defined'
const mockGLCtx = mock(WebGL2RenderingContext);
TestedClass.testGlCtx( instance(mockGLCtx) );
verify( mockGLCtx.flush() ).once();
});
});
Run using mocha with the command mocha --require ts-node/register 'test.ts'
.
There are two solutions: For common DOM APIs, and for generic mocking.
As detailed in this StackOverflow answer, jsdom can be used to bring DOM APIs into NodeJS runtime environment.
Run npm install --save-dev jsdom global-jsdom
and change Mocha's command to
mocha --require ts-node/register --require global-jsdom/register 'test.ts'
NOTE: global-jsdom is the newer & updated version of jsdom-global.
This solution works for common DOM APIs (such as HTMLElement
, SVGElement
, File
),
but it doesn't work for more specialized APIs (WebGL, Crypto, audio & video).
Turns out ts-mockito has a way to mock interfaces, including DOM & any browser Web APIs.
So the above test code can be changed to:
describe('WebGL interface', () => {
it('works fine', () => {
const mockGLCtx = mock<WebGL2RenderingContext>();
TestedClass.testGlCtx( instance(mockGLCtx) );
verify( mockGLCtx.flush() ).once();
});
});
and the test will run successfully.