简体   繁体   中英

How can I mock Date.now multiple times concurrently

I'm trying to implement my own mocking date function and I want it to works concurently.

I think the optimal usage would be:

mockDate(myFirstDate, async () => {
   // Here and only here Date.now() === myFirstDate
})

mockDate(mySecondDate, async () => {
   // Here and only here Date.now() === mySecondDate
})

// Outside Date.now is working as expected

Here is a minimal failing code sample for what I'm trying to achieve :

async function mockDate(timestamp, callback) {
    const original_now = Date.now

    Date.now = function() {
        if (/* How can I check Date.now have been called inside callback */ true) return timestamp
        else return original_now()
    }

    await callback()

    Date.now = original_now
}

const wait = ms => new Promise(res => setTimeout(res, ms))

mockDate(1600000000000, async () => {
    await wait(100)
    const result = Date.now()
    if (result !== 1600000000000) throw new Error('Fail: 1600000000000')
}).catch(console.error)

mockDate(1650000000000, async () => {
    const result = Date.now()
    if (result !== 1650000000000) throw new Error('Fail: 1650000000000')
    await wait(200)
}).catch(console.error)

My idea is to check inside the if if I can retrieve callback inside this.caller . Unfortunately accessing this.caller gives me an error.

Also I know tests frameworks usually have serial mode but I'm trying to avoid it.

禁用严格模式或使用串行模式。

This is a working solution:

async function mockDate(timestamp, callback) {
    const original_now = Date.now

    Date.now = function() {
        try {
            let caller = arguments.callee.caller
            while (caller !== callback && caller.caller) {
                caller = caller.caller
            }
            return caller === callback
                ? timestamp
                : original_now()
        } catch {
            return original_now()
        }
    }

    await callback()

    Date.now = original_now
}

A major drawback to this solution is that you can't use arrow function

mockDate(date, async () => {
    const date1 = (function() { return Date.now() })() // Date is mocked

    const date2 = (() => Date.now())() // Date wont be mocked
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM