Search code examples
javascriptmocha.jssetintervalsinon

test a callback to an outside function with in setInterval() using MochaJS


I need to test the call to the destroyTask() with in the setInterval() The setInterval() compares two time stamps and them calls the destroyTask() when they current time is equal to the finishTime

 async jobTimeout() {
    if (!this.timeout || !this.timeunits) return;
    const startTime = moment();
    const finishTime = moment().add(this.timeout, this.timeunits);
    // console.log('Duration - ', this.timeout, ' ' ,this.timeunits);

    console.log(`Start Time: ${startTime}`);
    console.log(`Finish Time: ${finishTime}`);

    this._timer = setInterval(() => {
      console.log(moment());
      if (moment().isAfter(finishTime)) {
        console.log("The task didn't finish in time. ", this.destroyTask());
        clearInterval(this._timer); // the clearInterval() method clears a timer set with the setInterval() method
      }
    }, 1000);
  }

I'm using sinon to spy on two function and fake timers to overwrite setInterval. My test case is bellow:

 describe('Generic Setup', () => {
    beforeEach(() => {
      // Overwrite the global timer functions (setTimeout, setInterval) with Sinon fakes
      this.clock = sinon.useFakeTimers();
    });

    afterEach(() => {
      // Restore the global timer functions to their native implementations
      this.clock.restore();
    });

    it('Job Should Timeout After Specified Duration', async () => {
      const task = new TASK(taskData, done);
      const result = sinon.spy(await task.jobTimeout());
      const destroyTask = sinon.spy(await task.destroyTask());

      setInterval(result, 1000);

      this.clock.tick(4000);
      expect(destroyTask).to.not.have.been.called;

      this.clock.tick(1000);
      expect(destroyTask).to.have.been.called;
    });
  });

I receive the following error TypeError: this.done is not a function. I think it's caused by destroyTask, but it is a function.

async destroyTask() {
    // TODO cleanup tmp directory - might want to collect stat on error
    clearInterval(this._timer);
    this.done();
  }

What can be the cause? Is it possible to test callback to outside function with in another function?


Solution

  • Had to modify a few things. I've changed the spy call, increased the second this.clock.tick() to 2000 and had to give a custom done function in class instantiation.

      describe('Generic Setup', () => {
        beforeEach(() => {
          // Overwrite the global timer functions (setTimeout, setInterval) with Sinon fakes
          this.clock = sinon.useFakeTimers();
        });
    
        afterEach(() => {
          // Restore the global timer functions to their native implementations
          this.clock.restore();
        });
    
        it('Job Should Timeout After Specified Duration', async () => {
          const task = new TASK(taskData, () => {});
    
          task.jobTimeout();
    
          const destroyTaskSpy = sinon.spy(task, 'destroyTask');
    
          this.clock.tick(4000);
          expect(destroyTaskSpy).to.not.have.been.called;
    
          this.clock.tick(2000);
          expect(destroyTaskSpy).to.have.been.called;
    
          // Remove the spy to prevent future errors
          destroyTaskSpy.restore();
        });
      });