Reputation: 9688
I would like to make an unit test for a module that is using jsonfile
to read the data.
import * as jsonfile from 'https://deno.land/x/jsonfile/mod.ts'
would like to mock out the jsonfile.readJsonSync to return the test data and avoid writing to disk. Can this be done?
Hope this abstract example describes what I want to archive:
index.ts
import * as jsonfile from 'https://deno.land/x/jsonfile/mod.ts'
export function readAndReturn() {
return jsonfile.readJsonSync('./example.json')
}
index.test.ts
import { assertEquals } from 'https://deno.land/[email protected]/testing/asserts.ts'
import { readAndReturn } from './index.ts'
const dataFixture = {hello: "word"}
// mock out jsonfile.readJsonSync to return dataFixture and not the actual file content
Deno.test("Reads the data", () => {
assertEquals(readAndReturn(), dataFixture)
})
A huge thanks to @mfulton26 and @jsejcksn for pointing me in the right direction.
unit.test.importmap.json
{
"imports": {
"https://deno.land/x/jsonfile/mod.ts": "./mocks/jsonfile.ts"
}
}
mocks/jsonfile.ts
import sinon from 'https://cdn.skypack.dev/[email protected]?dts'
const readJsonSync = sinon.stub()
const writeJsonSync = sinon.stub()
export { readJsonSync, writeJsonSync }
index.test.ts
import { readJsonSync as readJsonSyncMock } from './mocks/jsonfile.ts'
Deno.test(
'Reads the data', () => {
const data = ["hello world"]
readJsonSyncMock.withArgs(`./example.json`).returns(data)
assertEquals(readAndReturn(), data)
}
)
deno test --import-map=unit.test.importmap.json
Upvotes: 4
Views: 1761
Reputation: 2280
Wrapping your module with another module might work in some cases, but if your module has side effects with errors in them, this won't work.
I've created a small module to get around this issue: Fake Imports.
It might not be possible to mock static imports, but dynamic imports certainly can be mocked!
import { Importer } from "https://deno.land/x/fake_imports/mod.js";
const importer = new Importer(import.meta.url);
importer.fakeModule("https://deno.land/x/jsonfile/mod.ts", `
function readJsonSync() {}
export {readJsonSync};
`);
// Then load your main module asynchronously
const mainModule = await importer.import("./main.ts");
// And perform your test on mainModule like you usually would
Upvotes: 1
Reputation: 33796
You can substitute modules using an import map.
Just create a local module ./jsonfile.mock.ts
containing your mocked functions and export them using the same names as the real module at https://deno.land/x/jsonfile/mod.ts
. Then, create an import map with the correct mapping and use it when you run your test:
./jsonfile.mock.ts
:
export function readJsonSync (filePath: string): unknown {
// implement mocked fn
}
// and any other imports you use from the module
./index.importmap.json
:
{
"imports": {
"https://deno.land/x/jsonfile/mod.ts": "./jsonfile.mock.ts"
}
}
deno test --import-map=index.importmap.json index.test.ts
Upvotes: 4
Reputation: 31254
ES modules cannot be stubbed.
You can however wrap the functionality you want to stub in a class or object and export that and then you can stub methods on it using Sinon.JS or other libraries.
For getting started with Sinon.JS in Deno I suggest checking out Integration with testing libraries | Testing | Manual | Deno which references a sinon_example.ts.
Upvotes: 1