Search code examples
javascriptnode.jstestingcronjestjs

Testing a node-cron Job function with Jest


I have a javascript class that contains a function that starts a cron job using the node-cron library. But I can't seem to find a way to test the class and the function.

The variables that control the node-cron are in a .env file. To do the testing I'm using jest. My job is started when the app.js of my node application is started(the class file is imported and is export instantiated)

.env file

#CRON JOB
FREQUENCY_CRON='30 00 * * *'
TIMEZONE="America/Sao_Paulo"
SCHEDULED=true
INACTIVE_EXPIRATION_TIME=2592000000 #30 DAYS

CronJob.js

class CronJob {
  constructor() {
    this.startJob();
  }

  async startJob() {
    cron.schedule(
      process.env.FREQUENCY_CRON,
      async () => {
        //DO SOME DATA PROCESSING 
      },
      {
        scheduled: process.env.SCHEDULED,
        timezone: process.env.TIMEZONE
      }
    );
  }
}

export default new CronJob();


Solution

  • You could use jest.mock(moduleName, factory, options) to mock node-cron module. Use dotenv package load the environment variables from .env before running the test cases.

    E.g.

    cronJob.js:

    import cron from 'node-cron';
    
    class CronJob {
      constructor() {
        this.startJob();
      }
    
      async startJob() {
        cron.schedule(
          process.env.FREQUENCY_CRON,
          async () => {
            console.log('DO SOME DATA PROCESSING');
          },
          {
            scheduled: process.env.SCHEDULED,
            timezone: process.env.TIMEZONE,
          },
        );
      }
    }
    
    export default new CronJob();
    

    cronJob.test.js:

    import cron from 'node-cron';
    import path from 'path';
    
    require('dotenv').config({ path: path.resolve(__dirname, './.env') });
    
    jest.mock('node-cron', () => {
      return {
        schedule: jest.fn(),
      };
    });
    
    describe('61765291', () => {
      it('should pass', () => {
        const logSpy = jest.spyOn(console, 'log');
        cron.schedule.mockImplementationOnce(async (frequency, callback) => await callback());
        require('./cronJob');
        expect(logSpy).toBeCalledWith('DO SOME DATA PROCESSING');
        expect(cron.schedule).toBeCalledWith('30 00 * * *', expect.any(Function), {
          scheduled: 'true',
          timezone: 'America/Sao_Paulo',
        });
      });
    });
    

    .env:

    #CRON JOB
    FREQUENCY_CRON='30 00 * * *'
    TIMEZONE="America/Sao_Paulo"
    SCHEDULED=true
    INACTIVE_EXPIRATION_TIME=2592000000 #30 DAYS
    

    unit test results with 100% coverage:

     PASS  stackoverflow/61765291/cronJob.test.js (8.148s)
      61765291
        ✓ should pass (30ms)
    
      console.log
        DO SOME DATA PROCESSING
    
          at CustomConsole.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
    
    ------------|---------|----------|---------|---------|-------------------
    File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ------------|---------|----------|---------|---------|-------------------
    All files   |     100 |      100 |     100 |     100 |                   
     cronJob.js |     100 |      100 |     100 |     100 |                   
    ------------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        9.145s, estimated 10s