GithubHelp home page GithubHelp logo

boblauer / mockdate Goto Github PK

View Code? Open in Web Editor NEW
653.0 5.0 50.0 232 KB

A JavaScript Mock Date object that can be used to change when "now" is.

License: MIT License

JavaScript 65.82% TypeScript 34.18%

mockdate's Introduction

MockDate

A JavaScript Mock Date object that can be used to change when "now" is.

Build Status

Installation

npm install mockdate --save-dev

Environment Support

MockDate has been tested in Node, IE9+, Chrome, Firefox, and Opera.

Usage

import MockDate from 'mockdate'

API

MockDate.set(date)

date

date: Object

The Date to be returned when no parameters are passed to new Date(). Supports any object that has a .valueOf method that returns a value that can be passed to new Date().

date: String

The string representation of the date which is passed to the new Date() constructor. This creates the Date to be returned when no parameters are passed to new Date().

date: Number

The millisecond representation of the Date to be returned when no parameters are passed to new Date().

MockDate.reset();

Will restore the original Date object back to the native implementation.

Example

MockDate.set('2000-11-22');

new Date().toString() // "Tue Nov 21 2000 18:00:00 GMT-0600 (CST)"

MockDate.set('1/30/2000');

new Date().toString() // "Sun Jan 30 2000 00:00:00 GMT-0600 (CST)"

MockDate.set(new Date('2/20/2000'));

new Date().toString() // "Sun Feb 20 2000 00:00:00 GMT-0600 (CST)"

MockDate.set(moment('3/30/2000').toDate()); // using momentjs

new Date().toString() // "Thu Mar 30 2000 00:00:00 GMT-0600 (CST)"

MockDate.reset();

new Date().toString() // "Mon Mar 17 2014 18:08:44 GMT-0500 (CDT)"

Test

npm test

mockdate's People

Contributors

boblauer avatar brunoskonrad avatar capaj avatar dependabot[bot] avatar johnson-liang avatar keijokapp avatar maartenpaauw avatar osdiab avatar pfiver avatar popomore avatar tomgb avatar zpl0310 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

mockdate's Issues

Use with resetModules

Ultimately I want to set process.env values for a single test file that don't impact on other test files. To do so, I have something like...

let moduleA;

describe('module a', () => {
   beforeAll(() => {
       jest.resetModules();
       process.env.SOME_VAR = "value-while-testing-module-a";
       moduleA = require("./module_a");
   })
  afterAll( () => {
      jest.resetModules();
      process.env.SOME_VAR = undefined;
  }) 
  // it...
});

And I'm using various mongoose models as well (required in the same way as moduleA here). But in this setup I can't work out how to use MockDate, I feel like it should come after the jest.resetModules call, but when I do that it doesn't seem to actually do its job.

bug when time is set to epoch

var
  assert = require('assert'),
  MockDate = require('mockdate');

MockDate.set(1);

// passes
assert.equal(new Date().getTime(), 1);

MockDate.set(0);

// fails
assert.equal(new Date().getTime(), 0);

CommonJS build no longer works in browser

It looks like when mockdate was updated to typescript in version 3 it was changed from a UMD to a CJS build.

This means that it no longer works in a browser context. This breaks use cases, for example, the test-cafe repo has a recipe that breaks with version 3.

I have filed a ticket there to update the recipe DevExpress/testcafe-examples#49

Would it be possible to make a UMD build of mockdate? If so I would be interested in preparing the PR.

Thank you for the great project!

setHours doesn't respect timezone offset

For example, doing:

MockDate.set(0, 0);
a = new Date();
a.setHours(16);
console.log(a.toISOString());

would not produce 1970-01-01T16:00:00.000Z but 1970-01-01T14:00:00.000Z (when running in GMT+2)

toLocaleString() not working

When specifying toLocaleString() and using MockDate it always returns the US format:

MockDate.set('2022-01-31');

it('should format to UK time', () => {
   expect(new Date().toLocaleString('en-GB')).toBe('31/1/2022, 12:00:00 AM');
});
Expected: "31/1/2022, 12:00:00 AM"
Received: "1/31/2022, 12:00:00 AM"

Incorrect results based on format of date string

I came across a strange issue when using MockDate with a YYYY-MM-DD format date, versus MM/DD/YYYY. The results I see don't even agree with the first example shown in the README, so perhaps a recent bug?

Here's what I get in the node CLI:

> MockDate.set('2000-11-22')
> new Date().toString()
'Tue Nov 21 2000 16:00:00 GMT-0800 (Pacific Standard Time)'
> MockDate.set('11/22/2000')
> new Date().toString()
'Wed Nov 22 2000 00:00:00 GMT-0800 (Pacific Standard Time)'

I would expect that both of these should give the same result. I'm using node v12.6.0 on macOS, MockDate 2.0.3.

RFI: Any alternatives for mocking timezoneOffset?

I had been using the timezoneOffset in mockdate v2 to test some time/date utilities on a local machine and a server in a different timezone.

I have noticed you have removed this feature from the library which sounds fair enough, but I wondered if you had any pointers for users upgrading to 3 to use alternative approaches/libraries?

New Date() always get same value

I am using MockDate to synchronize a client device with server. The problem occurred when I am trying to get New Date() value in a loop event. The value always the same. When I disable the mock and back using native, the value I get is updated and works as expected.

Allow time to advance for new dates relative to set date/time

Background
In a project I am on, my team had a need to be able to replay time-based information. To our great excitement it was found that this project fulfilled the need to be able to mock a certain date/time with ease. However, one thing that was still needed was that each new date that was created needed to be forward offset by the amount of real time that had passed, relative to the date we had initially set.

Proposed Solution
To accomplish this, I am proposing introducing a way to allow configuring MockDate in which all dates created are offset forward by the difference since MockDate.set(date) was called.
MockDate.set would now have an added optional boolean parameter, advanceTime, that when set to true, would accomplish the new behavior.

Example

const start = new Date(2018, 6, 1); // Sun Jul 01 2018 00:00:00 GMT-0400
MockDate.set(start, true); // MockDate is now set to Sun Jul 01 2018 00:00:00 GMT-0400
// ... 1 second later
let now = new Date(); // Sun Jul 01 2018 00:00:01 GMT-0400
// ... 5 minutes later
now = new Date(); // Sun Jul 01 2018 00:05:01 GMT-0400
// etc ...

Request: add support for deterministic `Date.prototype.toString()` based on passed `timezoneOffset`

@boblauer you've mentioned that you don't consider this to be the purpose of this library: #19 (comment)

Does that mean you wouldn't entertain a pull request that implements something like:

MockDate.set(null, -60)

console.log(new Date('2019-11-13T23:41:46Z'))
  // Wed Nov 14 2019 00:41:46 GMT+0100

The full timezone representation is optional according to MDN, meaning we only need the GMT offset.

I'm proposing .toString() and all methods that implicitly rely on the local timezone (the list is fairly long: getDate, getDay, getHours, setHours, etc.) are mocked to use the passed offset only when such an offset is passed. Existing usages that do not pass timezoneOffset to MockDate.set() will continue to use the native implementations.

My motivation for this proposal is that MockDate is often used for deterministic snapshot testing (e.g. Jest's expect(...).toMatchSnapshot(), where dates are often displayed and modified based on the runtime's local timezone. This is a problem when your CI server runs on UTC time, while your development machine doesn't. And if many developers work in different timezones, snapshots will fail.

I'd be interested to attempt this, but I'm a bit put-off by having to write in ES5. Would it be okay if I added Babel as a devDependency?

After update to 2.0.3 receive an error stating that .set does not exist in MockDate

I have the following two lines of code in a TS file

import * as MockDate from 'mockdate';

MockDate.set('12/18/2017');

After updating to 2.0.3 both VSCode and in building phase I receive an error stating:

TS2339: Property 'set' does not exist on type 'typeof import("/path/to/project/node_modules/mockdate/index")'.

If I either downgrade to 2.0.2 or manually remove the index.d.ts file the error goes away

No default export in v3

So existing code like the following will error with Cannot read property set of undefined

import MockDate from 'mockdate';

MockDate.set('2020-01-01 09:00');

Date is mocked but timezone is not

I have a test where the ISO string representation of new Date() is displaying the following which includes my timezone.

2000-11-21T16:00:00.000-08:00

Our test is checking for:

2000-11-21T16:00:00.000-00:00

I've tried calling MockDate with these and had no luck.

MockDate.set('2000-11-22T00:00:00.000+00:00')
MockDate.set(new Date('2000-11-22T00:00:00.000+00:00'))
MockDate.set(new Date('2000-11-22T00:00:00.000Z'))

I'm creating the new date via new Date()
Which I would expect to return the same date that mockdate setup.
Maybe it is but I'm misunderstanding that my system's timezone is being taken into account when I'd prefer it not.
Maybe I need to mock my system's timezone as well?

I wonder if many of the other issues open are around the timezone?

Does not affect Date.prototype.toLocaleString

// I'm in America/Los_Angeles (+08:00) during non-saving time:
(new Date()).getTimezoneOffset()
// 480

// 4pm in America/Chicago (+06:00) is 2pm in my local time:
(new Date('2001-02-03T04:05+06:00')).toLocaleString([], {hour: "2-digit",minute: "2-digit"})
// '2:05 PM'

// If I change to America/Denver (+07:00):
const MD = require('mockdate')
MD.set('2002-03-04T05:06+07:00', -420)

// then getTimezoneOffset is mocked:
(new Date()).getTimezoneOffset()
// 420

// but toLocaleString isn't:
(new Date('2001-02-03T04:05+06:00')).toLocaleString([], {hour: "2-digit",minute: "2-digit"})
// '2:05 PM'

Allow set multiple dates to use in cycle

Allow setMultiple dates so you when you are differing dates you can do:

MockDate.setMultiple([new Date(2020, 0, 17), new Date(2020, 0, 24)], 120)

const begin = new Date()
begin.toString() // "Fri Jan 17 2020 00:00:00 GMT-0600 (CST)"

const end = new Date()
end.toString() // "Fri Jan 24 2020 00:00:00 GMT-0600 (CST)"

end - begin // diffs to fixed 604800000ms (1 week)

Lodash Debounce Breaks

When I have MockDate enabled, calls to lodash's debounce function never execute. Any ideas?

Thanks

'ReferenceError: Date is not defined' with Babel (Includes fix)

v3.0.2

I got ReferenceError: Date is not defined when calling reset().

My tests are Babel-compiled on the fly, and I believe this breaks the link between the Date reference and the actual global.Date class.

I have a fix, and would offer a PR but I'm not familiar with typescript.

I did copy your earlier js version (27a1a73 - Remove Dead Code) and replaced all Date references with global.Date. This works fine.

(Also, by the way, when you merged your ts branch, you accidentally undid the removal of the dead code in the mentioned commit).

Doesn't work with mongoose

It makes mongoose throw TypeError: Undefined type "MockDate" at "created", if it is loaded before schemas are created.

Timezone?

Is there a way to specify a fixed timezone offset to use?

NodeJS 10+ TimeoutOverflowWarning on MockDate.set

I was hoping to have a PR to give you with a fix instead of just opening an issue, but I've been bashing my head against a wall trying to track this one down. When I use MockDate.set() with NodeJS 10 and up, I get the following sample warning:

(node:63747) TimeoutOverflowWarning: 1560177835614 does not fit into a 32-bit signed integer.

I've tracked it down to this specific line in set: https://github.com/boblauer/MockDate/blob/master/src/mockdate.js#L76

If I comment that line out, I no longer get the warning. But what's really weird is, if I set now to any integer, I still get the error. Only commenting out or setting to null seems to silence the error.

Would love to understand what exactly is triggering node to throw this error and understand it. My curiosity isn't letting this one go.

Date.now not mocked

Hello,

Date itself is mocked, but Date.now is still returning the current time. Any ideas?

describe('My test', () => {
    beforeAll(() => {
      MockDate.set(1000);
    });
    afterAll(() => {
      MockDate.reset();
    });
    test('test 1', () => {      
      expect(Date.now()).toBe((new Date()).getTime());
    });
});

Mock getTimezoneOffset

Hello,

I found myself in need of mocking getTimezoneOffset to avoid flaky tests that should give deterministic results on CI and locally regardless of timezone of the environment running the suite.

Right now this is "unmockable", running the suite in different time zones will get different results for getTimezoneOffset and this library provides no remedy even though I think it could/should.

So for the company I work at we had to do this manually. But the question arose during code review if this is someting that would be interesting to contribute to the MockDate repo?

In the simplest form, there could be a new separate API such as:

> MockDate.setTimeZoneOffset("+08:00")
> const date = new Date()
> date.getTimeZoneOffset()
< -480

This is rougher idea, but could also be mentioned: If you were to provide a +HH:MM syntax one could override getTimeZoneOffset based on that syntax:

> MockDate.set("2020-04-13T00:00:00.000+08:00")
> const date = new Date()
> date.getTimeZoneOffset()
< -480

But I feel that could be unintuitive and presumptious.

Thoughts? ๐Ÿค”

inadequate documentation for set()

I'm not sure whether I'm using it wrong or whether it just plain doesn't work.

Say I want to set the current time to be 1pm on 15th June in Chicago

MockDate.set("2020-06-15T13:00:00", -5 * 60)
console.log(new Date().toString())
==>  Mon Jun 15 2020 13:00:00 GMT+0100 (British Summer Time)

It seems the value I'm passing into set is assumed to be specified relative to my current time zone (London in summertime), which kind of defeats the point of mocking, because I want my tests to run the same whichever time zone they run in.

I think the most people would assume the date you specify is be interpreted relative to the timezone you specify.

Edit: there's something else funny going on as well:

I worked around the previous problem by specifying the time zone when parsing the date like this:

MockDate.set("2020-06-15T13:00:00-05:00", -5 * 60)
const date = new Date()
console.log(date.toUTCString())
==> Mon, 15 Jun 2020 18:00:00 GMT

So far so good - 1pm in chicago is 6pm GMT - but now look at this:

console.log(`local hours ${date.getHours()} UTC hours ${date.getUTCHours()}
                offset=${date.getTimezoneOffset() / 60} hours`)
==> local hours 19 UTC hours 18 offset=-5 hours

The local hours is wrong, even though both the UTC hours and the offset are correct

This module can only be referenced with ECMAScript imports/exports by turning on the 'esModuleInterop' flag and referencing its default export

Getting the below error in typescript project

import * as MockDate from 'mockdate';
This module can only be referenced with ECMAScript imports/exports by turning on the 'esModuleInterop' flag and referencing its default export

and if I add below to tsconfig, there will be error on other imports such as import * as Rollbar from 'rollbar'

{
  "compilerOptions": {
    "esModuleInterop": true
  }
}

Add additional method for timestamp support?

I would rather test with timestamps, such as MockDate.setTimestamp(0);

such that I can test the behavior after a certain amount of seconds, minutes, etc. again.
e.g.: MockDate.setTimestamp(60000).

It would be awesome to have this functionality.

new Date(year, month, 0) behaves differently from native Date

We have a utility function to get the number of days in a month. The function works well with native Date object, but not with MockDate.

const daysInMonth = (month, year) => new Date(year, month, 0).getDate()
console.log(daysInMonth(8, 2017)) // returns 31, which is correct (there are 31 days in August)

const MockDate = require('mockdate')
MockDate.set('2017/8/3')
console.log(daysInMonth(8, 2017)) // returns 1, which is wrong.

The core difference is that for the native Date() function, when the third argument is given 0, the returned Date instance will be set to the last day of the previous month. (see setDate()). However, in MockDate it is set to the first day of the given month.

The root cause seems to be this line: https://github.com/boblauer/MockDate/blob/master/src/mockdate.js#L31

Since it is legitimate for d to be 0, we should use d===undefined ? 1 : d instead of d || 1 to set its default value.

Using MockDate with TypeORM breaks typeORM

I use MockDate for testing of my routes. However, when I set a MockDate, the TypeORM library breaks and is not automatically parsing dates to date Objects anymore:

My test code without mockdate:

    const obj = new DBObject("name", new Date("2020-06-23T10:00Z"));
    await obj.save();
    await obj.reload();
    console.log(obj); // DBObject { name: 'name', publishDate: 2020-06-23T10:00:00.000Z, id: 1 }

If I set the MockDate, TypeORM is not able to parse the datefields from the database properly:

    mockDate.set(new Date());
    const obj = new DBObject("name", new Date("2020-06-23T10:00Z"));
    await obj.save();
    await obj.reload();
    console.log(obj); // DBObject { name: 'name', publishDate: 1592906400000, id: 1 }

So the MockDate implementation is not behaving like the Javascript Date object is ans I expect there is a bug in the MockDate implementation. Any idea what the reason could be?

For reference, this is my Object class using TypeORM.

import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from "typeorm";

@Entity()
export default class DBObject extends BaseEntity {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column()
  name: string;

  @Column()
  publishDate: Date;

  constructor(name: string, publishDate: Date) {
    super();
    this.name = name;
    this.publishDate = publishDate;
  }
}

throw an error when wrong time is set

for example:

mockDate.set('30/9/2016');

should throw an error, because that date is invalid. If this goes unnoticed, it leads to weird values being returned from Date methods.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.