nestjs icon indicating copy to clipboard operation
nestjs copied to clipboard

[NestJS][Jest] Exceeded timeout of 5000 ms for a hookfalse

Open anthonykrivonos opened this issue 2 years ago • 3 comments

Describe the bug My team has written multiple Jest tests in our NestJS/MikroORM backend with no issues. However, no matter what we try, we're getting the following error ONLY in our test file access.spec.ts: Exceeded timeout of 5000 ms for a hookfalse.

Stack trace

 FAIL  src/access/access.spec.ts (8.205 s)
  ● AccessTest › should be defined

    thrown: "Exceeded timeout of 5000 ms for a hookfalse.
    Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."

      72 |   }) as AccessGrant;
      73 |
    > 74 |   beforeAll(async () => {
         |   ^
      75 |     mockedMikroORM = mock<MikroORM>('mikro orm');
      76 |     mockedAccessGrantRepository = mock<EntityRepository<AccessGrant>>('grant repository');
      77 |     mockedPermissionRepository = mock<EntityRepository<Permission>>('permission repository');

      at access/access.spec.ts:74:3
      at Object.<anonymous> (access/access.spec.ts:20:1)

access.service.ts snippet

@Injectable()
export class AccessService {
  private readonly logger = new Logger('access-service');
  constructor(
    private readonly orm: MikroORM,
    @InjectRepository(AccessGrant)
    private accessGrantRepository: EntityRepository<AccessGrant>,
    @InjectRepository(Permission)
    private permissionRepository: EntityRepository<Permission>,
    @InjectRepository(RolePermission)
    private rolePermissionRepository: RolePermissionRepository,
    @InjectRepository(Role)
    private roleRepository: EntityRepository<Role>,
    @InjectRepository(RoleMembership)
    private roleMembershipRepository: EntityRepository<RoleMembership>,
    private organizationMembershipService: OrganizationMembershipService,
  ) {}
...
}

access.spec.ts snippet

describe('AccessTest', () => {
  let accessService: AccessService;

  let mockedMikroORM: Mock<MikroORM>;
  let mockedAccessGrantRepository: Mock<EntityRepository<AccessGrant>>;
  let mockedPermissionRepository: Mock<EntityRepository<Permission>>;
  let mockedRolePermissionRepository: Mock<RolePermissionRepository>;
  let mockedRoleRepository: Mock<EntityRepository<Role>>;
  let mockedRoleMembershipRepository: Mock<EntityRepository<RoleMembership>>;
  let mockedOrganizationMembershipService: Mock<OrganizationMembershipService>;

  beforeEach(async () => {
    mockedMikroORM = mock<MikroORM>('mikro orm');
    mockedAccessGrantRepository = mock<EntityRepository<AccessGrant>>('grant repository');
    mockedPermissionRepository = mock<EntityRepository<Permission>>('permission repository');
    mockedRolePermissionRepository = mock<RolePermissionRepository>('role permission repository');
    mockedRoleRepository = mock<EntityRepository<Role>>('role repository');
    mockedRoleMembershipRepository = mock<EntityRepository<RoleMembership>>(
      'role membership repository',
    );
    mockedOrganizationMembershipService = mock<OrganizationMembershipService>(
      'organization membership service',
    );

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        AccessService,
        {
          provide: MikroORM,
          useValue: instance(mockedMikroORM),
        },
        {
          provide: OrganizationMembershipService,
          useValue: instance(mockedOrganizationMembershipService),
        },
        {
          provide: getRepositoryToken(AccessGrant),
          useValue: mockedAccessGrantRepository,
        },
        {
          provide: getRepositoryToken(Permission),
          useValue: mockedPermissionRepository,
        },
        {
          provide: getRepositoryToken(RolePermission),
          useValue: mockedRolePermissionRepository,
        },
        {
          provide: getRepositoryToken(Role),
          useValue: mockedRoleRepository,
        },
        {
          provide: getRepositoryToken(RoleMembership),
          useValue: mockedRoleMembershipRepository,
        },
      ],
    }).compile();

    accessService = module.get(AccessService);
  });

  it('should be defined', () => {
    expect(accessService).toBeDefined();
  });
});

To Reproduce Steps to reproduce the behavior:

  1. Create NestJS service with MikroORM entities. Must contain one custom repository and one service injection from elsewhere.
  2. Instantiate mocks in a beforeEach or beforeAll.
  3. Run the test, and maybe this error will occur.

As mentioned above, we're not entirely sure why this error is happening or where it's coming from considering we've followed steps 1-3 in other services within our codebase with no errors.

In light of it being difficult to reproduce this issue, any pointers would be appreciated!

Expected behavior The test should run with no timeouts since all entities, repos, and MikroORM seem to be sufficiently mocked. A timeout implies something is trying to access the network or running an infinite loop.

Additional context We've tried:

  1. Providing the MikroORM mock with the following instantiation:
{
  provide: MikroORM,
  useValue: MikroORM.init(
    defineConfig({
      connect: false,
      clientUrl: "test",
      schema: "test",
      entities: [
        AccessGrant,
        Permission,
        Role,
        RoleMembership,
        RolePermission,
        OrganizationMembership,
      ],
      driver: PostgreSqlDriver,
    })
  )
},
  1. Commenting out OrganizationMembershipService from everywhere in the module.
  2. Commenting out the TestingModule instantiation from the test file. This lets the test run successfully, so that implies the issue is somewhere in the await Test.createTestingModule call.
  3. Removing the MikroORM dependency from the access.service.ts constructor and removing it from the test module.
  4. Changing the timeout to 60s via jest.setTimeout(60000);.
  • Setting timeout is not a viable solution because there are no asynchronous processes running in the setup hook. Also, it doesn't fix the issue.
  • We've refactored our codebase, so circular dependencies are likely not the issue here either.

Versions

Dependency Version
node 18
typescript ^4.9.0
mikro-orm ^5.6.11
nestjs ^9.3.9

Thanks in advance!

anthonykrivonos avatar Jul 20 '23 16:07 anthonykrivonos

Can you please provide a complete repro as a github repo?

B4nan avatar Jul 20 '23 16:07 B4nan

@B4nan Got it to repro here

anthonykrivonos avatar Jul 20 '23 17:07 anthonykrivonos

@B4nan Let me know when you take a look, still can't figure it out. You might have more context on the error, especially since we're trying to mock MikroORM. Thanks.

anthonykrivonos avatar Jul 24 '23 15:07 anthonykrivonos

Looks like this is a problem with jest itself, see https://github.com/jestjs/jest/issues/11607#issuecomment-877076592 for a possible workaround.

B4nan avatar May 19 '24 17:05 B4nan