I am currently facing a challenge while writing integration tests for my Nest.js application. The custom TypeORM repositories in my test context are being marked as undefined. This issue may be occurring because I am not utilizing @InjectRepository
. Instead, I have created request-scoped injectables that extend a BaseRepository to handle transactions within my requests. (I establish and manage one transaction per request, handling commit/rollback operations using interceptors. For more details on this approach, refer to the following article: https://medium.com/@dev.muhammet.ozen/advanced-transaction-management-with-nestjs-typeorm-43a839363491)
import { Test, TestingModule } from '@nestjs/testing';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ProductService } from '../../src/modules/product/product.service';
import { ProductRepository } from '../../src/repositories/product.repository';
describe('ProductService (integration)', () => {
let productService: ProductService;
let productRepo: ProductRepository;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
url: process.env.TEST_DB_URL,
migrationsRun: true,
logging: false,
migrations: [__dirname + '/../../src/migrations/**/*{.ts,.js}'],
entities: [__dirname + '/../../src/entities/*.entity{.ts,.js}'],
}),
],
providers: [
ProductRepository,
ProductService,
],
}).compile();
productService = module.get<ProductService>(ProductService);
productRepo = await module.resolve(ProductRepository);
});
it('repo test', async () => {
const result = await productService.getProductByName('randomName');
expect(result).toBeNull();
});
});
import { Injectable } from '@nestjs/common';
import { ProductEntity } from '../../entities/product.entity';
import { ProductRepository } from '../../repositories/product.repository';
@Injectable()
export class ProductService {
constructor(
private readonly productRepo: ProductRepository,
) {}
async getProductByName(name: string): Promise<ProductEntity> {
const product = await this.productRepo.getRepository().findOne({ where: { name: name } });
return product;
}
}
Now, diving into the repository:
import { Request } from 'express';
import { DataSource, EntityManager, Repository } from 'typeorm';
import { ENTITY_MANAGER_KEY } from '../utils/consts';
export class BaseRepository {
constructor(
private dataSource: DataSource,
private request: Request,
) {}
protected getRepository<T>(entityClass: new () => T): Repository<T> {
const entityManager: EntityManager = this.request
? this.request[ENTITY_MANAGER_KEY] ?? this.dataSource.manager
: this.dataSource.manager;
return entityManager.getRepository(entityClass);
}
}
import { Inject, Injectable, Scope } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
import { DataSource, Repository } from 'typeorm';
import { ProductEntity } from '../entities/product.entity';
import { BaseRepository } from './baseRepository';
@Injectable({ scope: Scope.REQUEST })
export class ProductRepository extends BaseRepository {
constructor(dataSource: DataSource, @Inject(REQUEST) req: Request) {
super(dataSource, req);
}
getRepository(): Repository<ProductEntity>;
getRepository<T>(entityClass: new () => T): Repository<T>;
getRepository<T>(entityClass?: new () => T | ProductEntity): Repository<T | ProductEntity> {
if (entityClass === undefined) {
return super.getRepository(ProductEntity);
}
return super.getRepository(entityClass);
}
}
Upon running the test, I encountered the following error:
TypeError: Cannot read properties of undefined (reading 'getRepository')
The productRepo
within ProductService.getProductByName
remains undefined. I have experimented with changing the scope to default, but this did not resolve the issue.
Interestingly, when I adjusted the test to directly use the repository provided within the TestingModule, it worked as expected:
it('test repo', async () => {
const result = await productRepo.getRepository().findOne({ where: { name: 'randomName' } });
expect(result).toBeNull();
});
I would appreciate any insights or guidance on solving this issue.