Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NestJS Unit Testing of the Service: Mocking getManager resulting in 'Connection "default" was not found' error

I am currently unit testing my NestJS Service. My entity is called 'User' and I established a basic Service that allows me to interact with a MS SQL server, with GET and POST endpoints established in my Controller.

One of the service methods I am trying to mock is the deleteV2 function, which you can find below:


// service file 
import { Injectable } from '@nestjs/common';
import { InjectConnection, InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { Connection, createConnection, EntityManager, getConnection, getManager, getRepository, Repository } from "typeorm";
import {User} from '../entities/user.entity';


@Injectable()
export class ServiceName {
  constructor(@InjectRepository(User) private usersRepository: Repository<User>,
              @InjectConnection() private connection: Connection,
              @InjectEntityManager() private manager: EntityManager
              ) {}

  async delete(id: number): Promise<any> {
    return await this.manager.delete(User, id);
  }
  async deleteV2(id: number): Promise<any> {
    return await getManager().delete(User, id);
  }

Note that the reason I have imported EntityManager AND injected (with @InjectEntityManager()) a manager: EntityManager into my service is for the simple reason that I wanted some more practice working with different methods (I'm a new intern working with NestJS). The fact that I have the delete method defined where I use the injected manager and then the deleteV2 method defined where I use the imported getManager is also for the pure reason of practicing unit testing with different ways. And the fact that I'm injecting Repository, Connection, and EntityManager, is also for the same reason.

In my spec.ts unit testing file for the service, I have:

// unit testing file for the service

type MockType<T> = { 
    [P in keyof T]?: jest.Mock<{}>;
};

describe('service tests', () => {
    const mockManagerFactory = jest.fn(() => ({
        delete: jest.fn().mockReturnValue(undefined),
    }))
 
    let service: ServiceName;
    // mock repository and mock connection also defined similarly to mockManager
    let mockManager: MockType<EntityManager>; 

    beforeEach(async () => {     
        const module: TestingModule = await Test.createTestingModule({
            providers: [
                ServiceName,
                // tokens for Repository and Connection are also provided along with their respective Factories
                {
                    provide: getEntityManagerToken(),
                    useFactory: mockManagerFactory,
                },
            ],
        }).compile();

        service = module.get<ServiceName>(ServiceName);
        // mockRepository and mockConnection also defined but not shown
        mockManager = module.get(getEntityManagerToken());
    });
})

Staying on the same spec.ts file, I defined multiple tests. The one that is causing problem is the one that involves deleteV2 below:

// same unit testing file for the service 
         
        // first test
        it('first test', async () => {
            expect(await service.delete(1000)).toEqual(undefined);
            expect(mockManager.delete).toBeCalled();
        });
        
        // second test 
        it('second test', async () => {
            expect(await service.deleteV2(1000)).toEqual(undefined);
            expect(mockManager.delete).toBeCalled();
        })

While the first test has no problem running (the first test is associated with delete in the service file), the second test (associated with deleteV2 in the service file) does not pass and results in the following error:

● service tests › Service Functions › second test

ConnectionNotFoundError: Connection "default" was not found.

      at new ConnectionNotFoundError (error/ConnectionNotFoundError.ts:8:9)
      at ConnectionManager.Object.<anonymous>.ConnectionManager.get (connection/ConnectionManager.ts:40:19)
      at Object.getManager (index.ts:260:35)

Any ideas how to approach this error? It seems as though providing getEntityManagerToken() works with the injected manager but not with the getManager that is imported, since deleteV2 uses getManager while delete (which passes the test) uses the imported manager

like image 216
Etfrerrr Avatar asked Dec 18 '25 10:12

Etfrerrr


1 Answers

This is where a huge benefit of using dependency injection comes in. @InjectEntityManager() just injects the object that (theoretically) already has the connection set up for you, and you can just use the methods without concern about the connection. It makes testing significantly easier (in my opinion). With getMananger() you have to worry about TypeORM trying to get the entity manger from the current active connection, which shouldn't be there in tests. You can mock this using jest by using something like the following

const deleteMock = jest.fn();
jest.mock('typeorm', () => ({
  getManager: () => ({
    delete: deleteMock,
  })
}))

This works well enough, but I would avoid calling methods like getConnection and getManager from TypeORM directly if possible.

like image 124
Jay McDoniel Avatar answered Dec 21 '25 04:12

Jay McDoniel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!