Mocking TypeORM with Jest
Jest markets itself as a "delightful Javascript Testing Framework" and for the most part, it is. That is, until you have to mock something that simply does not want to be mocked. The latest issue has been mocking TypeORM. Despite Expert Google-Fu, and trial and error, Jest and TypeORM just didn't seem to want to be friends. Cue War's "Why can't we be friends?"
What you should already know
- TypeScript
- How to use Jest
- Setting up ts-jest
- How to use TypeORM
There are links to all of the documentation under the Articles section of this post.
Just came here for the solution?
Fast forward to the solution
Attempt #1 - Getting the mocks set up.
The first go at this was using the generic "mock the whole module" approach and looked like this:
jest.config.ts:
export default {
preset: 'ts-jest',
testEnvironment: 'node',
};
login.test.ts:
jest.mock('typeorm');
...
test("Test Login Process - Good Login", () => {
loginHandler({
userName: goodUser.userName,
password: password
}).then((value) => {
expect(value).toBeDefined();
expect(value).toEqual(token);
}).catch((rejected) => {
fail(rejected);
});
})
Unfortunately the result was a glorious failure, so we took a second pass.
Attempt #2 - Using Jest Extended to mock more
The first attempt failed to really mock anything at all. Undeterred, we tried out using jest-extended to help out with mocking classes one-by-one.
This, unfortunately, still did not yield the results we were after. We ended up with the dreaded decorator is not a function
error.
Solution - Mocking The Correct Compenents
After much testing, and looking at different approaches, the solution finally showed up in the form of mocking the correct components.
import { User } from '@dominion-solutions/user-permission';
import * as faker from 'faker';
import { loginHandler } from '../handler';
import * as jwt from 'jsonwebtoken';
import * as dotenv from 'dotenv';
import { fail } from 'assert';
import Sinon from 'sinon';
import { BaseEntity, Connection, ConnectionManager, Repository } from 'typeorm';
import 'jest-extended'
describe('handler => loginHandler()', () => {
const sandbox = Sinon.createSandbox();
const goodUser: User = new User;
const password: string = faker.internet.password();
goodUser.userName = faker.internet.userName();
beforeAll(async () => {
dotenv.config();
await goodUser.setPassword(password);
});
beforeEach(() => {
const mockRepository = sandbox.stub(Repository.prototype, 'find').returns(Promise.resolve([goodUser]));
sandbox.stub(ConnectionManager.prototype, 'get').returns({
getRepository: sandbox.mock().returns(mockRepository)
} as unknown as Connection);
sandbox.stub(BaseEntity, 'find').returns(Promise.resolve([goodUser]));
});
afterEach(() => {
sandbox.restore();
});
We also settled on using Sinon to help with mocking after trying different methods with jest alone.
Articles
To be fair, there were a ton of articles on this, and I'm sure that they contributed big time to the success of getting the whole stack working. Some articles worth noting are:
- Jest with Typescript - Anthony Ng Put together this great how-to quick start guide on running Jest with TypeScript.
- Jest Documentation - This was a good place to get started.
- ts-jest Documentation - Documentation for how to set up ts-jest
- Jest Extended's GitHub - Docutentation for Jest Extended
- TypeORM's GitHub - Includes lots of great info about how TypeORM works.
- TypeScript Documentation - The documentation for the TypeScript Language
- SinonJs Documentation - Sinon Page. You will have to select the Documentation page at the top right to get the latest and greatest documentation.
Update: February 17, 2022
It turns out that the original SinonJS Documentation does not stay stable and cannot be permalinked, as the page keeps breaking. I included a link above to the base page.
Comments
Comments have been temporarily disabled while we transition to our new site.
© 2024 Dominion Solutions LLC, All Rights Reserved