0

There is a website I use which shows different content on different dates. In the JavaScript, it uses new Date() to determine the current date, which it uses to determine which content to show.

If I would like to view content from a different date, I can change my system time. However, this is tedious and interferes with other applications. I am trying to figure out if there is some code I can run in the browser's javascipt console that will mock out new Date() to return the date of my choosing

I see there are some questions that discuss creating a spy on Date with jest, but I do not see a way to mock this in my browser console

2
  • When does it use new Date? On page load? You'll struggle to run anything that could mock Date before the page's code runs if so (short of writing a browser extension). Commented Jan 26, 2022 at 8:41
  • sure, I can package the js into a browser extension if necessary Commented Jan 26, 2022 at 8:46

3 Answers 3

4

It's possible to replace the Date function with your own function that provides the results you want, but doing it before the page uses it will be tricky unless you write a browser extension.

The fundamental bit is (see comments):

// Save the original `Date` function
const OriginalDate = Date;
// Replace it with our own
Date = function Date(...args) {
    // Called via `new`?
    if (!new.target) {
        // No, just pass the call on
        return OriginalDate(...args);
    }
    // Determine what constructor to call
    const ctor = new.target === Date ? OriginalDate : new.target;
    // Called via `new`
    if (args.length !== 0) {
        // Date constructor arguments were provided, just pass through
        return Reflect.construct(ctor, args);
    }
    // It's a `new Date()` call, mock the date we want; in this
    // example, Jan 1st 2000:
    return Reflect.construct(ctor, [2000, 0, 1]);
};
// Make our replacement look like the original (which has `length = 7`)
// You can't assign to `length`, but you can redefine it
Object.defineProperty(Date, "length", {
    value: OriginalDate.length,
    configurable: true
});

// Save the original `Date` function
const OriginalDate = Date;
// Replace it with our own
Date = function Date(...args) {
    // Called via `new`?
    if (!new.target) {
        // No, just pass the call on
        return OriginalDate(...args);
    }
    // Determine what constructor to call
    const ctor = new.target === Date ? OriginalDate : new.target;
    // Called via `new`
    if (args.length !== 0) {
        // Date constructor arguments were provided, just pass through
        return Reflect.construct(ctor, args);
    }
    // It's a `new Date()` call, mock the date we want; in this
    // example, Jan 1st 2000:
};
// Make our replacement look like the original (which has `length = 7`)
// You can't assign to `length`, but you can redefine it
Object.defineProperty(Date, "length", {
    value: OriginalDate.length,
    configurable: true
});

console.log("new Date()", new Date());
console.log("new Date(2021, 7, 3)", new Date(2021, 7, 3));

Sign up to request clarification or add additional context in comments.

Comments

2

thank you @t-j-crowder 🙏 for the best solution I have found so far... I made some customisation to it so Date.now works as well.

Also one advise, put breakpoint at the very beginning of your script, run the code in console and resume execution for best date consistency 😌

my modification:

// Save the original `Date` function
const OriginalDate = Date;
const fakeDateArgs = [2022, 5, 3]; // beware month is 0 based
let fakeDate;
// Replace it with our own
Date = function Date(...args) {
    // Called via `new`?
    if (!new.target) {
        // No, just pass the call on
        return OriginalDate(...args);
    }
    // Determine what constructor to call
    const ctor = new.target === Date ? OriginalDate : new.target;
    // Called via `new`
    if (args.length !== 0) {
        // Date constructor arguments were provided, just pass through
        return Reflect.construct(ctor, args);
    }
    // It's a `new Date()` call, mock the date we want; in this
    fakeDate = Reflect.construct(ctor, fakeDateArgs);
    return fakeDate;
};
// Make our replacement look like the original (which has `length = 7`)
// You can't assign to `length`, but you can redefine it
Object.defineProperty(Date, "length", {
    value: OriginalDate.length,
    configurable: true
});

Object.defineProperty(Date, "now", {
    value: () => fakeDate.getTime(),
    configurable: true
});

Comments

1

Here's implementation for mocking the Date object in browser. Month is always zero based and default date is set to January 1st 2024 which can be changed. This is best to be used for test purposes only:

((originalDate) => {
    // Function to mock the Date object
    function MockDate(...args) {
        if (args.length) {
            return new originalDate(...args);
        }
        // Default date: January 1, 2024
        return new originalDate(2024, 0, 1);
    }

    MockDate.prototype = originalDate.prototype;
    MockDate.now = () => new MockDate().getTime();
    MockDate.UTC = originalDate.UTC;
    MockDate.parse = originalDate.parse;

    // Override the global Date object
    Date = MockDate;
})(Date);

Can be tested with:

console.log(new Date());

1 Comment

This worked for me instead of the accepted answer as the code I was testing needed to use Date.UTC

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.