Search code examples
typescriptunit-testingjestjsnestjstypeorm

How to stub EntityManager and Connection in TypeORM with Jest


I got an app on NestJS in Typescript using TypeORM and unit-tests written with Jest. I have a function that uses transactions like this:

async createMany(users: User[]) {
  await this.connection.transaction(async manager => {
    await manager.save(users[0]);
    await manager.save(users[1]);
  });
}

That's an example from NestJS docs. I do it roughly in the same way via this.connection.transaction but the business-logic is different.

The thing is I want to make a unit-test to test this service function. So I need to somehow mock both this.connection and its manager. Or at least the manager. I'm not sure how to do it using Jest. I can't create a manager without a connection. I can't create a mock connection with no manager to return inside it.

Using both TypeORM and Jest is standard in NestJS. There have to be a way to write unit-tests with transactions. But I am not sure how to do it.

Note that I am asking about unit-test mocking ORM. Not integration tests that would directly use a testing db instance.


Solution

  • You would need to create a TestingModule with a mocked Connection. Something likes this:

    import { Test } from "@nestjs/testing";
    
    describe("UsersService", () => {
        let usersService;
        let connection;
        const mockConnection = () => ({
            transaction: jest.fn()
        });
    
        beforeEach(async () => {
            const module = await Test.createTestingModule({
                providers: [
                    UsersService,
                    {
                        provide: Connection,
                        useFactory: mockConnection
                    }
                ],
            }).compile();
    
            usersService = await module.get<UsersService>(UsersService); 
            connection = await modle.get<Connection>(Connection);
        });
    
        describe("some tests", () => {
            it("should test something", async () => {
                const someMockedUsers = [/* some users */];
                const mockedManager = {
                    save: jest.fn()
                }
                connection.transaction.mockImplementation((cb) => {
                    cb(mockedManager);
                });
    
                await userService.createMany(someMockedUsers);
    
                expect(connection.transaction).toHaveBeenCalled();
                expect(mockedManager.save).toHaveBeenCalledTimes(2);
                // ...
    
            });
        });
    
    
    });