Reputation: 31
I want ask about my Issue with Testing @Transactional
Decorator in NestJS/MikroORM Environment.
I'm encountering an issue while testing a command handler that uses MikroORM's @Transactional
decorator. While the code works properly in production, I'm getting the following error during testing:
Error: expect(received).rejects.toThrow(expected)
Expected constructor: OrganizationNameAlreadyRegisteredException
Received constructor: Error
Received message: "@Transactional() decorator can only be applied to methods of classes with `orm: MikroORM` property, `em: EntityManager` property, or with a callback parameter like `@Transactional(() => orm)` that returns one of those types. The parameter will contain a reference to current `this`. Returning an EntityRepository from it is also supported."
Here's my command handler:
import { EntityManager } from '@mikro-orm/postgresql';
@CommandHandler(OrganizationRegisterCommand)
export class OrganizationRegisterCommandHandler {
constructor(
@InjectRepository(Organization)
private readonly organizationRepository: OrganizationRepository,
@Inject(EntityManager)
private readonly em: EntityManager,
) {}
@Transactional()
async execute(command: OrganizationRegisterCommand): Promise<void> {
try {
const organization = await Organization.register({ ...command });
await this.em.persistAndFlush(organization);
// await this.organizationRepository.persist(organization);
} catch (error) {
if (error instanceof UniqueConstraintViolationException) {
logger.log('OrganizationNameAlreadyRegisteredException', error);
throw new OrganizationNameAlreadyRegisteredException();
}
console.log('etc error', error);
}
}
}
My module configuration:
@Module({
imports: [CqrsModule, MikroOrmModule.forFeature([Organization])],
providers: [
OrganizationEditCommandHandler,
OrganizationRemoveCommandHandler,
{
provide: OrganizationRegisterCommandHandler,
useFactory: (em: EntityManager, organizationRepository: EntityRepository<Organization>) => {
return new OrganizationRegisterCommandHandler(organizationRepository, em);
},
inject: [EntityManager, EntityRepository],
},
OrganizationRepository,
],
controllers: [OrganizationController],
})
export class OrganizationModule {}
And here's my test code:
describe('usecase', () => {
let handler: OrganizationRegisterCommandHandler;
let organizationRepository: jest.Mocked<OrganizationRepository>;
let entityManager: EntityManager;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
OrganizationRegisterCommandHandler,
{
provide: getRepositoryToken(Organization),
useValue: {
findOne: jest.fn(),
persist: jest.fn(),
flush: jest.fn(),
selectOrganizationBy: jest.fn(),
},
},
{
provide: EntityManager,
useValue: {
persistAndFlush: jest.fn(),
flush: jest.fn(),
},
},
],
}).compile();
handler = module.get<OrganizationRegisterCommandHandler>(OrganizationRegisterCommandHandler);
organizationRepository = module.get(getRepositoryToken(Organization));
entityManager = module.get(EntityManager);
});
});
I've injected EntityManager
into the handler and applied the @Transactional
decorator to the execute method. However, while this works fine in the actual application, it fails during testing.
I would greatly appreciate any advice on how to properly test code that uses the @Transactional
decorator with MikroORM in a NestJS environment.
Upvotes: 0
Views: 52