quantumbutterfly
quantumbutterfly

Reputation: 1953

How to mock javascipt new Date to return different date from browser console

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

Upvotes: 0

Views: 1866

Answers (4)

Sebastian Nikkonen
Sebastian Nikkonen

Reputation: 11

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());

Upvotes: 1

Luckylooke
Luckylooke

Reputation: 4549

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
});

Upvotes: 2

paradigm111
paradigm111

Reputation: 396

You can use this to modify the content before it is loaded: https://developer.chrome.com/docs/extensions/reference/webRequest/

There is this extension which I haven't used that may be able to do it: https://chrome.google.com/webstore/detail/page-manipulator/mdhellggnoabbnnchkeniomkpghbekko?hl=en

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1075755

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));

Upvotes: 4

Related Questions