0

Ever since adding a mock CronJob to my unit tests, I'm getting the message below:

A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with --detectOpenHandles to find leaks. Active timers can also cause this, ensure that .unref() was called on them.

Running the test with --detectOpenHandles doesn't give me any extra information. How do I exit this test gracefully?

This is the test code:

import { Test, TestingModule } from '@nestjs/testing';
import { CronService } from './cron.service';
import { SchedulerRegistry } from '@nestjs/schedule';
import { CronJob } from 'cron';
import { PriceModule } from '../price/price.module';

describe('CronService', () => {
  let service: CronService;

  let mockCronJob: CronJob = new CronJob('*/5 * * * *', () => {
    return;
  });

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        CronService,
        {
          provide: SchedulerRegistry,
          useValue: {
            addCronJob: jest.fn().mockResolvedValue(mockCronJob),
          }
        }
      ], 
      imports: [PriceModule]
    }).compile();

    service = module.get<CronService>(CronService);
  });

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

With the actual service being tested:

import { Injectable, Logger } from '@nestjs/common';
import { SchedulerRegistry } from '@nestjs/schedule';
import { CronJob } from 'cron';
import { PriceService } from '../price/price.service';

@Injectable()
export class CronService {
    constructor(private schedulerRegistry: SchedulerRegistry, private priceService: PriceService) {
        this.addCronJob('startup',1)
    }
    private readonly logger = new Logger(CronService.name);

    addCronJob(name: string, minutes: number): number {
        let priceUpdateTimer = 'priceUpdateTimer'

        if(0 >= minutes || minutes >= 60) {
            this.logger.error(`Tried updating the priceUpdatetimer to ${minutes} minutes.`);
            return;
        }

        if(name === priceUpdateTimer || name == 'startup') {
            if(name === priceUpdateTimer && this.getCronByName(priceUpdateTimer)) {
                this.deleteCron(priceUpdateTimer);
            }

            let cronString = `*/${minutes} * * * *`;

            const priceUpdateJob = new CronJob(cronString, () => {
                this.logger.log('Updating prices.')
                this.priceService.updatePrices();
            });
            this.schedulerRegistry.addCronJob(priceUpdateTimer, priceUpdateJob);
            priceUpdateJob.start();
      
            this.logger.log(`Changed the priceUpdatetimer to ${minutes} minutes.`);

            return minutes;
        }
    }

    deleteCron(name: string) {
        this.schedulerRegistry.deleteCronJob(name);
        this.logger.warn(`job ${name} deleted!`);
    }

    getCronByName(name: string): number {
        try {
            const job = this.schedulerRegistry.getCronJob(name);
            let minutes: number = Number.parseInt(job.cronTime.source.toString().replace(/\D/g, ""));
            return minutes;

        } catch {
            this.logger.warn(`No cron job found by name ${name}`);
            return;
        }
    }
}

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.