1

(This seems partially overlapping with my previous question: Test interaction with two interval async functions)

Using jest 27.5.1 and sinon 13.0.1, I want to unit-test an async interval function.

Consider this code:

const fs = require("fs")
const { exec } = require("child_process")

module.exports = class MyClass {
    init() {
        setInterval(this.checkFileContent, 10)
    }
    
    async checkFileContent() {
            await new Promise((resolve) => { exec("sleep 0.4", resolve) })
            const fileContent = (await fs.promises.readFile("foo.txt")).toString()
            console.log(fileContent)
    }
}

and this test file

const MyClass = require(".")
const fs = require("fs")
const sinon = require("sinon")
const { exec } = require("child_process")

describe("MyClass", () => {
    let sandbox
    beforeAll(async () => {
        sandbox = sinon.createSandbox()
        await fs.writeFileSync("foo.txt", "fooContent")
    })

    afterAll(async () => {
        await fs.unlinkSync("foo.txt")
        await new Promise((resolve) => { exec("sleep 0.8", resolve) })
        sandbox.verifyAndRestore()
    })

    test("should test MyClass", async () => {
        const clock = sandbox.useFakeTimers()
        const instance = new MyClass()
        instance.init()
        clock.next()
        await Promise.resolve() // As suggested in this answer https://stackoverflow.com/a/52196951/2710714 - but doesn't seem to help at all
        clock.reset()
    })
})

Running the test, I'll always get ENOENT: no such file or directory, open 'foo.txt'. The reason being that await fs.unlinkSync("foo.txt") has already run when await fs.promises.readFile("foo.txt") is reached.

So, I need to somehow make sure that all promises in the interval function started by clock.next() are resolved before the tests stops. How do I do that?

Note: In real-life, it's not about file access but database queries. And the exec("sleep ..." is of course something artificial to replicate long-lasting operations. But the principles should be the same.

Edit: Also tried await clock.nextAsync() - didn't help.

cis
  • 1,259
  • 15
  • 48
  • `setInterval(this.checkFileContent, 10)` call `this.checkFileContent` every 10ms and never stop. So `Wait till promises inside interval done in unit tests` would wait forever? – t.niese Feb 25 '22 at 09:25
  • @t.niese The Sinon docs (https://sinonjs.org/releases/latest/fake-timers/): say about `clock.next()`: `Advances the clock to the the moment of the first scheduled timer, firing it.` In my understanding, that implies that the `interval` would run only once - as opposed to `clock.runAll`. – cis Feb 25 '22 at 09:30

0 Answers0