Home > Software design >  Cannot use Fake Timer to test setTimeout for class method
Cannot use Fake Timer to test setTimeout for class method

Time:08-12

I can test setTimeout with a normal function like this:

function doAsync() {
  setTimeout(doAsync, 1000)
}

jest.useFakeTimers()

test("setTimeout with function", async () => {
  doAsync()
  jest.advanceTimersByTime(2500)
  expect(setTimeout).toBeCalledTimes(3)
})

But when I use it with class method, it cannot refer to this, Cannot read properties of null (reading 'doAsync'):

class Test {
  doAsync() {
    setTimeout(this.doAsync, 1000)
  }
}

jest.useFakeTimers()

test("setTimeout with class method", async () => {
  new Test().doAsync()
  jest.advanceTimersByTime(2500)
  expect(setTimeout).toBeCalledTimes(3)
})

How can I test with a class method like this?

CodePudding user response:

You need to write :

class Test {
  doAsync() {
    setTimeout(() => this.doAsync(), 1000)
  }
}

It's because when you write this.doAsync, at the moment of the setTimeout execution, this does exist anymore.

But if round it up around a lambda, the this reference is copied in it at his declaration and so it reference the good instance when it's called later.

Hope it's helps.

CodePudding user response:

Wrap this.doAsync call into an arrow function to preserve the reference to this

class Test {
    doAsync() {
        setTimeout(() => this.doAsync(), 1000)
    }
}
  • Related