Jest: يسخر من الوقت الحالي للتاريخ

تم إنشاؤها على ٦ ديسمبر ٢٠١٦  ·  72تعليقات  ·  مصدر: facebook/jest

تحرير بواسطة SimenB 25-05-2020: راجع الإجابة المحدثة: https://github.com/facebook/jest/issues/2234#issuecomment -633402727

هل هناك طريقة للسخرية من التاريخ الحالي؟ بحيث يُرجع new Date() أو Date.now() وقتًا سخرًا منه بدلاً من الوقت الحالي؟

التعليق الأكثر فائدة

بالنسبة لأي شخص آخر يواجه أخطاء بهذا ، واجهت بعض المشكلات لأن كائن التاريخ العالمي له خصائص أخرى غير المُنشئ. قمت بما يلي:

const DATE_TO_USE = new Date('2016');
const _Date = Date;
global.Date = jest.fn(() => DATE_TO_USE);
global.Date.UTC = _Date.UTC;
global.Date.parse = _Date.parse;
global.Date.now = _Date.now;

ال 72 كومينتر

Date.now = jest.fn أو global.Date = jest.fn() .

بالنسبة لأي شخص آخر يواجه أخطاء بهذا ، واجهت بعض المشكلات لأن كائن التاريخ العالمي له خصائص أخرى غير المُنشئ. قمت بما يلي:

const DATE_TO_USE = new Date('2016');
const _Date = Date;
global.Date = jest.fn(() => DATE_TO_USE);
global.Date.UTC = _Date.UTC;
global.Date.parse = _Date.parse;
global.Date.now = _Date.now;

إذا لم تكن بحاجة إلى التأكيد على كيفية استدعاء المنشئ ، فقد يكون التمديد كافيًا:

const constantDate = new Date('2017-06-13T04:41:20')

/*eslint no-global-assign:off*/
Date = class extends Date {
  constructor() {
    return constantDate
  }
}

هذا يعمل بشكل جيد مقابل Date.now() .

const now = Date.now()
Date.now = jest.genMockFunction().mockReturnValue(now)

عندما تسخر من التاريخ ، لا تنس إعادة الإصدار الحقيقي.
بعد تعليق callemo ، يمكنك استخدام المقتطف التالي:

describe('getTimestamp', () => {
  const RealDate = Date

  function mockDate (isoDate) {
    global.Date = class extends RealDate {
      constructor () {
        return new RealDate(isoDate)
      }
    }
  }

  afterEach(() => {
    global.Date = RealDate
  })

  it('should return timestamp', () => {
    mockDate('2017-11-25T12:34:56z')
    expect(getTimestamp()).toEqual('20171125123456')
  })
})

يمكن القول ، يجب أيضًا نقل التاريخ إلى الأمام عند تشغيل jest.runTimersToTime() ووظائف محاكاة الوقت الأخرى. لقد تعرضت للعض من نفس المشكلة ، لأن جزءًا من الكود الخاص بي يعتمد على الوقت ، وجزءًا من المهلات. الاستهزاء بهما في نفس الوقت - أي تشغيل أجهزة ضبط الوقت التي تم الاستهزاء بها والتبديل بين الوظائفتين Date.now و Performance.now ليست أفضل تجربة.

كان أحد الحلول لمحاكاة المؤقتات "الموحدة" هو استخدام lolex بدلاً من jest ، مثل هذا:

import lolex from 'lolex'

describe('tests', () => {
  let clock
  beforeEach(() => {clock = lolex.install()})
  afterEach(() => {clock = clock.uninstall()})

  test('garbage collects after keep alive', () => {
    // ...
    clock.tick(500)
    // ...
  })
})

ولكن سيكون من الرائع أن تكون هذه الميزة مدمجة.

إصدار قديم ، لكن mockdate يجعل ذلك سهلاً: https://www.npmjs.com/package/mockdate

https://jasmine.github.io/2.2/introduction؟spec=jasmine.any#section -Mocking_the_Date

   describe("Mocking the Date object", function(){
     it("mocks the Date object and sets it to a given time", function() {
       var baseTime = new Date(2013, 9, 23);
       jasmine.clock().mockDate(baseTime);
       jasmine.clock().tick(50);
       expect(new Date().getTime()).toEqual(baseTime.getTime() + 50);
     });
   });

drpicox هذا حل رائع ، لكن AFAIK لا يسخر من performance.now() ، وهي ساعة مفيدة للأمام فقط (على سبيل المثال ، لن يتراجع المستخدم عن تغيير DateTime لنظامه).

في الواقع لا يعمل في Jest. Jest يستخدم Jasmine v1.5.2-lite ، لذلك ليس لديه ساعة. أنا أستخدم lolex .

Date.now() جيد بما يكفي لمعظم التطبيقات ، permofrmance.now() غير موجود في العقدة حتى الآن - لا يمكن استخدامه في SSR على سبيل المثال - ، لذلك لا يبدو أنه مشكلة كبيرة.

بالطبع ، لا تتكامل lolex مع الدعابة.

drpicox آه ، من الجيد معرفة أنه لا يعمل بعد ذلك.
performance.now() موجود في العقدة ، منذ v8.5.0 على ما أعتقد. يمكنك استيراد performance من الوحدة المدمجة 'perf_hooks' .

ومع ذلك ، نظرًا للوضع الحالي وعدد الأصوات / التعليقات التي تحصل عليها ، أود أن أرسل pingcpojer للنظر في إعادة فتح هذه المشكلة.

FWIW أود دمج lolex - إنها المكتبة الوحيدة التي أستخدمها حيث أعتقد أن Jest تفتقد إلى البطارية

cpojer بأي طريقة يمكننا إعادة فتح هذا. حتى الآن، ليس هناك حقا وسيلة للسخرية التاريخ ومحاكاة مرور الوقت بطريقة سهلة.

الياسمين لديها فئة مدار الساعة حيث يمكنك يسخر من التاريخ والوقت والتقدم، عن طريق:

jasmine.clock().install(); //in a beforeEach
jasmine.clock().uninstall(); // in a AfterEach
jasmine.clock().mockDate(new Date('1984/12/15'));

// and very important... the pass of time!
jasmine.clock().tick(100);

أحب أن يكون لديك وظائف مماثلة أصلية. https://github.com/jasmine/jasmine/blob/master/src/core/Clock.js

سنحاول الانتقال إلى Lolex ، والذي يدعم حالة الاستخدام الخاصة بك. انظر # 5165

في حال احتجت إلى محاكاة التاريخ _ خارج_ بيئة الاختبار. كنت بحاجة لأخذ لقطات صورة يمكن التنبؤ بها لواجهة المستخدم حيث يتم عرض التاريخ.

نجح هذا بالنسبة لي:
https://github.com/schickling/timemachine

timemachine.config({
  dateString: 'December 25, 1991 13:12:59'
});
console.log(new Date()); // December 25, 1991 13:12:59

اقتراحomegdadisc هو أفضل ما أعتقد. إن عرض التاريخ الساخر دائمًا نفس التاريخ (كما تم اقتراحه في الإجابات الأولى) سيؤدي إلى العبث بأشياء مثل new Date(2018, 2, 3) لذا لم يكن خيارًا صالحًا بالنسبة لي.

لاحظ أنك تحتاج أيضًا إلى تحديد المنطقة الزمنية بدقة حتى تعمل بشكل كامل في كل مكان ، على سبيل المثال على ترافيس وتنتج نفس النتيجة.

timemachine.config({
  dateString: 'December 25, 1991 13:12:59 GMT'
});

يقوم الاختبار التالي بإيقاف التاريخ لإرجاع ثابت أثناء دورة حياة الاختبار.

let timeNow;
const realDate = Date;

describe("Stubbed Date", () => {
  beforeAll(() => {
    timeNow = Date.now();
    const _GLOBAL: any = global;
    _GLOBAL.Date = class {
      public static now() {
        return timeNow;
      }

      constructor() {
        return timeNow;
      }

      public valueOf() {
        return timeNow;
      }
    };
  });

  afterAll(() => {
    global.Date = realDate;
  });

  it("provides constant timestamps", () => {
    const ts1 = Date.now();
    const ts2 = +new Date();
    expect(ts1).toEqual(ts2);
    expect(ts2).toEqual(timeNow);
  });
});

_GLOBAL هو مجرد متغير وكيل لإرضاء الكتابة المطبوعة.

كنت بحاجة إلى السخرية من Date.now()

تعيين السطر أدناه في التكوين أو قبل أن تعمل الاختبارات بالنسبة لي:

jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000)

أعجبني أسلوبvcarel ، ولكن في حالتي ، تم استخدام مُنشئ التاريخ مع الوسائط في بعض الحالات ، لذلك كنت بحاجة إلى تعديله لقبول تواريخ أخرى. لقد أضفت أيضًا Date.now ()

describe('getTimestamp', () => {
  const RealDate = Date

  function mockDate (isoDate) {
    global.Date = class extends RealDate {
      constructor(...theArgs) {
        if (theArgs.length) {
          return new RealDate(...theArgs);
        }
        return new RealDate(isoDate);
      }

      static now() {
        return new RealDate(isoDate).getTime();
      }
    }
  }

  afterEach(() => {
    global.Date = RealDate
  })

  it('should return timestamp', () => {
    mockDate('2017-11-25T12:34:56z')
    expect(getTimestamp()).toEqual('20171125123456')
  })
})

أنا أستخدم هذا ، وأنا سعيد به: https://github.com/boblauer/MockDate

وقد فعلت هذا

~~~
وصف ('اختبار' ، () => {
const ConstantDate = تاريخ جديد ('2018-01-01T12: 00: 00')

beforeAll (() => {
global.Date = الفئة تمتد التاريخ {
البناء () {
ممتاز()
إرجاع ثابت التاريخ
}
}
})
~~~

فقط أود أن أضيف قليلاً إلى إجابةcallemo و iwarner .

من المحتمل أن يكون القيام بشيء ما مثل عرض نسخة تاريخ جديدة في كل مرة أقل عرضة للخطأ:

  const constantDate = new Date('2018-01-01T12:00:00')

  beforeAll(() => {
    global.Date = class extends Date {
      constructor () {
        super(constantDate.getTime())
      }
    }
  })

يتيح ذلك استخدام الوظائف التي تغير كائنات التاريخ (مثل setMinutes) دون تغيير تاريخ ثابت وبالتالي تغيير التاريخ الذي يتم إرجاعه من التاريخ الجديد مثل

describe('Test', () => {
  const constantDate = new Date('2018-01-01T12:00:00')

  beforeAll(() => {
    global.Date = class extends Date {
      constructor () {
        super()
        return constantDate
      }
    }
  });

  it('it should not be possible to mutate the  original date but it is.', () => {
    const date1 = new Date();
    date1.setMinutes(5);
    const date2 = new Date();
    console.log(date2.getMinutes()); // Will print 5
  });
});

هذا ما أستخدمه بعد قراءة كل ما سبق:

let currentDate;

beforeAll(() => {
  currentDate = new Date();

  const RealDate = Date;
  global.Date = jest.fn(() => new RealDate(currentDate.toISOString()));
  Object.assign(Date, RealDate);
});

samboylett هل هذا afterAll ؟

لن يؤثر على الاختبارات في الملفات المختلفة. بالنسبة لي ، احتاج كل شيء في الملف الحالي إلى التاريخ المزعج ، ولكن إذا كنت بحاجة إلى إعادة تعيينه بين الاختبارات في نفس الملف ، فيجب عليك استخدام BeforeEach و afterEach ، ثم قم بتعيينه مرة أخرى في afterEach:

afterEach(() => {
  global.Date = RealDate;
});

samboylett شكرا! تمكنت من الحصول على اختبارات التاريخ الخاصة بي تعمل باستخدام مثالك كقاعدة.

const myDate = new Date(2018, 6, 11);

const RealDate = Date;

describe('testcase', () => {
  beforeEach(() => {
    global.Date = jest.fn(
      (...props) =>
        props.length
          ? new RealDate(...props)
          : new RealDate(myDate)
    );
    Object.assign(Date, RealDate);
  });

  afterEach(() => {
    global.Date = RealDate;
  });
});

ربما تحتاج لتاريخ الدعابة وهمية .

يمنحك واجهة برمجة تطبيقات بسيطة للتحكم في الطابع الزمني الحالي لحالات الاختبار.

import { advanceBy, advanceTo, clear } from 'jest-date-mock';

test('usage', () => {
  advanceTo(new Date(2018, 5, 27, 0, 0, 0)); // reset to date time.

  const now = Date.now();

  advanceBy(3000); // advance time 3 seconds
  expect(+new Date() - now).toBe(3000);

  advanceBy(-1000); // advance time -1 second
  expect(+new Date() - now).toBe(2000);

  clear();
  Date.now(); // will got current timestamp
});

الحلول المذكورة أعلاه لا تغطي حالة الاستخدام الخاصة بي. لقد قمت بما يلي بناءً على callemo الذي يفتقد إلى الدعم على سبيل المثال وتعيين تواريخ محددة.

export function mockDate({year = 2017, month = 9, day = 16}) {
    const globalDate = global.Date
    global.Date = class MockDate extends Date {
        constructor() {
            super()
            this.setFullYear(year)
            this.setMonth(month)
            this.setDate(day)
        }
    }
    global.Date.mockRestore = () => global.Date = globalDate
}

javadoug ما هي حالتك؟

javadoug ما هي حالتك؟

hustcc mockDate() instanceof Date === true .

javadoug الإصدار الجديد jest-date-mock معتمد. https://github.com/hustcc/jest-date-mock/pull/7

"أنا لا أسخر من الوقت دائمًا ، ولكن عندما أفعل ذلك ، يكون الأمر مزاحًا" -satub سيئ السمعة

كنت بحاجة إلى السخرية من new Date() لكنني كنت بحاجة إلى باقي وظائف Date لتعمل كالمعتاد. هذا هو الحل الذي نجح معي.

describe('...', () => {
  const RealDate = Date;

  function mockDate(isoDate) {
    global.Date = class extends RealDate {
      constructor(...args) {
        if (args.length) return new RealDate(...args);
        return new RealDate(isoDate);
      }
    };
  }

  afterEach(() => {
    global.Date = RealDate;
  });

  it('...', () => {
    mockDate('2018-01-01');
    // rest of the code
  });
})

أتلقى خطأ عندما أحاول التعيين إلى global.Date:

Error: Error: ReferenceError: Date is not defined
    at Object.<anonymous>.exportObject.JUnitXmlReporter.self.specDone (/src/node_modules/jasmine-reporters/src/junit_reporter.js:274:33)
    at dispatch (/src/node_modules/jest-jasmine2/build/jasmine/report_dispatcher.js:70:26)
    at ReportDispatcher.specDone (/src/node_modules/jest-jasmine2/build/jasmine/report_dispatcher.js:62:247)
    at Object.specResultCallback (/src/node_modules/jest-jasmine2/build/jasmine/Env.js:411:18)
    at Spec.attr.resultCallback (/src/node_modules/jest-jasmine2/build/setup_jest_globals.js:67:24)
    at complete (/src/node_modules/jest-jasmine2/build/jasmine/Spec.js:111:10)
    at currentRun.then (/src/node_modules/jest-jasmine2/build/jasmine/Spec.js:107:30)

يبدو أن المشكلة تكمن في أنني أستخدم مراسل JUnit الذي يتم تنفيذه في سياق الاختبار ويستخدم التاريخ الذي تم إتلافه بالفعل بسبب إتلاف فئة مجهولة.

حسنًا ، يتم إفساد التاريخ العالمي عند استخدام اقتراحات مثل كل ما سبق. وهي مشكلة فقط عندما تستخدم مراسلين غير عاديين.

لا ينبغي إعدام المراسلين داخل صندوق الحماية. قد يكون صحفيو الياسمين مهتمين ببعض عناصر الياسمين التي لم يتم دعمها عن قصد

أوه ، إذن أنت تقول أن هذا النوع من الكود غير مدعوم؟

const jasmine = global.jasmine;
jasmine.getEnv().addReporter(junitReporter)

يحدث خطأ هنا:
https://github.com/facebook/jest/blob/f9fd98fd4e38978e96a86f1c8796593cad7ac470/packages/jest-jasmine2/src/jasmine/ReportDispatcher.js#L63 -L72

صحيح ، يجب عليك استخدام
https://jestjs.io/docs/en/configuration#reporters -array-modulename-modulename-options.
على سبيل المثال https://github.com/jest-community/jest-junit

niieani ،

كان أحد الحلول لمحاكاة المؤقتات "الموحدة" هو استخدام lolex بدلاً من jest ، مثل هذا:

لقد جربت هذا المثال ونتج عنه تعليق اختباراتي إلى الأبد (في CRA الذي يستخدم [email protected]). هل نجح أي شخص في استخدام lolex مع Jest؟

@ kentcdodds تأكد من عدم استخدام أجهزة ضبط الوقت المزيفة المزيفة في نفس الوقت. إذا كان لا يزال معلقًا ، فهل تمانع في إنشاء مشكلة في التكاثر؟ يجب أن تعمل Lolex بالتأكيد

نعم ، إنه يعمل بشكل جيد بالنسبة لي في موقف منعزل ، لذلك من المحتمل أن أفعل شيئًا غريبًا في مكان آخر. شكرا!

إذا كنت تحتاج فقط إلى السخرية من هذه الحالات:

new Date()
new Date('2018-09-20T23:00:00Z') 
const currentDate = new Date('2018-09-20T23:00:00Z');
Date = class extends Date {
  constructor(date) {
    if (date) {
        return super(date);
    }

    return currentDate;
  }
}

هذا ما أستخدمه بعد قراءة كل ما سبق:

let currentDate;

beforeAll(() => {
  currentDate = new Date();

  const RealDate = Date;
  global.Date = jest.fn(() => new RealDate(currentDate.toISOString()));
  Object.assign(Date, RealDate);
});

شكرا samboylett

لقد نجح هذا بالنسبة لي في السخرية من تاريخ جديد ()

petromoldovan هو بالتأكيد أفضل إجابة.

أضف استدعاء إلى mockRestore في نهاية الاختبارات لاستعادة التاريخ الأصلي:

const dateNowMockFn = jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000);
// ... code with tests
dateNowMockFn.mockRestore();

تم تحسين حل vcarel قليلاً ، إذا كنت تريد أن يقوم النموذج بإرجاع مثيل التاريخ بدلاً من الفئة الجديدة:

    const RealDate = Date

    const mockDate = (isoDate) => {
      global.Date = class extends RealDate {
        constructor () {
          return super(isoDate)
        }
      }
    }

    afterEach(() => {
      global.Date = RealDate
    })

ربما أميل إلى طواحين الهواء هنا ، لكن الأمر يستحق الإشارة إلى القول المأثور القديم: لا تسخر من ما لا تملكه . بدلا من ذلك ، لفها في وظيفة. في الوقت الحاضر ، من الملائم جدًا استخدام قيم الوسيطة الافتراضية:

const myFunc = (msg, date = new Date()) => console.log(`${msg}! ${date}`);

الآن في كود الإنتاج يمكنك الاستفادة من الافتراضي:

myFunc("Hello"); // => Hello! Fri Mar 22 2019 21:11:26 GMT-0400 (EDT)

وفي كود الاختبار ، يمكنك تمرير التاريخ بشكل صريح ، وبالتالي الاستهزاء به:

myFunc("Hello", dateObj) // => Hello! ...

yawaramin هناك بالتأكيد بعض وجهات النظر المتباينة حول هذا الموضوع. هناك معسكر يعتقد أن الاختبارات يجب أن تعيش في خدمة كود التطبيق ، وهناك نقطة بعد أن بدأ الذيل يهز الكلب (لدى Pete Hunt بعض الآراء القوية حول هذا)

عدم القول إن طريقتك المقترحة ليست خيارًا صالحًا ، ولكن ربما يمكن تقديمها كطريقة مناسبة ظرفية للعمل

Cheapsteak أعتقد أن ملاءمة الموقف هي الحالة الافتراضية للأشياء. لا يضر تذكير الأشخاص بلطف بأن هناك دائمًا فرصة لتحسين قابلية الاختبار وأن القيام بذلك عادة ما يؤدي إلى تحسين قابلية الصيانة :-)

هل هناك طريقة للحصول على وقت jest الحالي لأنه يرسل مؤقتات؟ شيء مثل الدعابة الآن؟

افترض أن لدي مؤقتات ومكالمات إلى Date.now (). أدعو jest.runAllTimers (). سيكون رائعًا إذا كان بإمكاني استدعاء jest.spyOn (التاريخ ، "الآن"). mockImplementation (() => شيء ما ) حتى تعمل عمليات رد نداء المؤقت ويمكنها التحقق من وقت المحاكاة.

كنت بحاجة إلى السخرية من Date.now()

تعيين السطر أدناه في التكوين أو قبل أن تعمل الاختبارات بالنسبة لي:

jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000)

مضحك كيف يعمل لكثير من الناس ولكن ليس بالنسبة لي. همم.

لا أعرف ما الذي يحدث ، ولكن بغض النظر عن كيفية إعادة تعيين Date ، فإن Date.now() موجود دائمًا ويعيد قيمة صالحة دائمًا.

Date.now = null لا يفعل شيئًا.
global.Date.now = null لا يفعل شيئًا.
jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000); لا يفعل شيئًا.
تثبيت واستخدام lolex يعمل عند انتهاء المهلة ، لكن ليس له تأثير على Date.now()
MockDate ليس له تأثير.

أنا أفتقد شيئًا واضحًا ، على ما أعتقد. ربما تقوم تبعية أخرى بفعل شيء ما ... مرتبك للغاية.

mherodev تحقق من اختبارك ، هل تسخر من التاريخ قبل تنفيذ وظيفة الاختبار / عرض المكونات؟

داخل كتلة اختبار أفعل شيئًا مثل ...

      Date.now = () => 1;
      Date = null;
      global.Date = null;
      console.log(`Date.now()`, Date.now()); // Date.now() 1560239936091

لكن هذا التجاوز لا يفعل شيئًا. أجده محيرا جدا.

لقد اتبعت البرنامج التعليمي لـ Hugo وانتهى بي الأمر بما يلي:

  // @ts-ignore
  .spyOn(global.Date, 'constructor')
  .mockImplementationOnce(() => new Date('2019-06-19T00:07:19.309Z'))

لذا ، فإن new Date() سيعود دائمًا new Date('2019-06-19T00:07:19.309Z')

تحديث: يبدو أن موكب التاريخ الخاص بي لم يكن يعمل بسبب خطأ في كيفية نقل بابل في بيئتي. شيء متعلق بكيفية استخدامنا @babel/runtime-corejs2

الحل النهائي: المزاح والتاريخ والسخرية .

  • تثبيت

في package.json الخاص بك تحت jest ، أنشئ مصفوفة setupFiles وأضف jest-date-mock إلى المصفوفة.

{
  "jest": {
    "setupFiles": ["./__setups__/other.js", "jest-date-mock"]
  }
}
  • الاستخدام

يمنحك واجهة برمجة تطبيقات بسيطة للتحكم في الطابع الزمني الحالي لحالات الاختبار.

import { advanceBy, advanceTo, clear } from 'jest-date-mock';

test('usage', () => {
  advanceTo(new Date(2018, 5, 27, 0, 0, 0)); // reset to date time.

  const now = Date.now();

  advanceBy(3000); // advance time 3 seconds
  expect(+new Date() - now).toBe(3000);

  advanceBy(-1000); // advance time -1 second
  expect(+new Date() - now).toBe(2000);

  clear();
  Date.now(); // will got current timestamp
});

أعتقد: كل الحلول الأخرى ليست منهجية أو مؤقتة.

يبدو أن تحول بابل يكسر الحلول السابقة.

الحل هو إضافة ملف جديد باسم setupMockDate.js

const mockDate = DateClass => {
  function Mock(...args) {
    return args.length === 0
      ? new DateClass(Mock.now())
      : new DateClass(...args)
  }
  Object.setPrototypeOf(Mock, DateClass)
  Mock.prototype = DateClass.prototype
  let now
  Mock.now = () => now === undefined ? DateClass.now() : now
  Mock.mockNow = value => now = value
  Mock.mockRestore = () => Mock.mockNow()
  return Mock
}
global.Date = mockDate(Date)

في jest.config.js عند الإدخال setupFilesAfterEnv (أو setupFiles في إصدار الدعابة القديم) ، أضف '<rootDir>/jest/setupMockDate.js' .

الآن ، أنت قادر على الجري

Date.mockNow(10)
expect(Date.now()).toBe(10)
Date.mockRestore()
expect(Date.now()).not.toBe(10)

يعمل Sinon جيدًا بالنسبة لي https://sinonjs.org/releases/v1.17.7/fake-timers/

متأخر على الحفلة ، لكنني أعتقد أن المزاح لديه كل الوظائف التي تحتاجها لهذا الغرض.

describe('how to mock date.now()', function() {
  beforeEach(() => {
    this.timestamp = 0
    global.Date.now = jest.fn().mockImplementation(() => this.timestamp)
  })

  afterEach(() => {
    jest.clearAllMocks()
  })

  it('can advance in time', () => {
    const then = Date.now()

    this.timestamp += 1000

    const now = Date.now()

    expect(now - then).toBe(1000)
  })

أنا أستخدم لحظات vue و jest ، ووجدت أن أفضل طريقة للقيام بشيء مثل هذا:

import { mount, createLocalVue } from '@vue/test-utils';
import TripList from 'components/trip-list.vue';

const localVue = createLocalVue();
localVue.use(require('vue-moment'));

describe('TripList', () => {

it('text shows current date', () => {
    const myDate = new Date(2019, 5, 5);

    const wrapper = mount(TripList, {
      localVue,
    });

    wrapper.vm.$moment.now = () => myDate;
    wrapper.vm.$forceUpdate();

    expect(wrapper.html()).toContain('Thu, Oct 3rd');
  });
})

باستخدام ES6

const fixedDate = new Date('2019-03-1');
const RealDate = Date;

beforeEach(() => { Date.now = () => fixedDate; });
afterEach(() => { global.Date = RealDate; });

إذا كنت تستخدم Date.now()

const dateSpy = jest.spyOn(Date, 'now');
dateSpy.mockReturnValue(TIMESTAMP);

بالنسبة لأي شخص آخر يواجه أخطاء بهذا ، واجهت بعض المشكلات لأن كائن التاريخ العالمي له خصائص أخرى غير المُنشئ. قمت بما يلي:

const DATE_TO_USE = new Date('2016');
const _Date = Date;
global.Date = jest.fn(() => DATE_TO_USE);
global.Date.UTC = _Date.UTC;
global.Date.parse = _Date.parse;
global.Date.now = _Date.now;

كنت أرغب في الاستهزاء بفصل Date بأكمله وكانت الطريقة التي اقترحها

لست متأكدًا مما إذا كانت هذه هي الطريقة المناسبة للقيام بذلك ، ولكن هذه الحلول تعمل بشكل جيد في TypeScript من خلال إصلاح مشكلة الكتابة كما هو مذكور بواسطة nilobarp :

describe('Mock Date', () => {
  const realDateNow = Date.bind(global.Date);

  beforeAll(() => {
    // Fix the time to 2020-1-1 1hr:1min:1sec in order to match
    // snapshots for the DownloadConfirmDialog component.
    const fixedDate = new Date(2020, 0, 1, 1, 1, 1);
    const d = Date;

    // This will only mock any Date objects instantiated with new 
    // and not Date.now().
    const _global: NodeJS.Global = global;
    _global.Date = jest.fn(() => fixedDate);
    _global.Date.parse = d.parse;
    _global.Date.UTC = d.UTC;
    _global.Date.now = d.now;
  });

  it('shows mocked date', () => {
    // Shows 2020-01-01T01:01:01.000Z as the current Date
    // for an instantiated Date object.
    console.log(new Date().toISOString());
  });

  afterAll(() => {
    // Reverts to the current Date object.
    global.Date = realDateNow;
    console.log(new Date().toISOString());
  });
});

من الجدير بالذكر أن هذا لا يعمل إلا عند إنشاء كائن جديد Date ولن يعمل مع Date.now() . هناك تعليق بخصوص Date.now .

داخل كتلة اختبار أفعل شيئًا مثل ...

      Date.now = () => 1;
      Date = null;
      global.Date = null;
      console.log(`Date.now()`, Date.now()); // Date.now() 1560239936091

لكن هذا التجاوز لا يفعل شيئًا. أجده محيرا جدا.

أواجه نفس المشكلة: اختبرت مجموعة كاملة من أمثلة التعليمات البرمجية الموجودة في هذه المشكلة ولم ينجح أي منها بالنسبة لي: يبدو أنه تم تجاهل الوهمية.

كيف أصلحت مشكلتك؟

نحن نستخدم Babel أيضًا ، لذلك قد يكون هذا مرتبطًا أيضًا.

داخل كتلة اختبار أفعل شيئًا مثل ...

      Date.now = () => 1;
      Date = null;
      global.Date = null;
      console.log(`Date.now()`, Date.now()); // Date.now() 1560239936091

لكن هذا التجاوز لا يفعل شيئًا. أجده محيرا جدا.

أواجه نفس المشكلة: اختبرت مجموعة كاملة من أمثلة التعليمات البرمجية الموجودة في هذه المشكلة ولم ينجح أي منها بالنسبة لي: يبدو أنه تم تجاهل الوهمية.

كيف أصلحت مشكلتك؟

نحن نستخدم Babel أيضًا ، لذلك قد يكون هذا مرتبطًا أيضًا.

warpdesign يبدو أن هذا الحل يعمل معي مع Jest في TypeScript.

describe('Mock Date.now', () => {
  // Bind to the original Date so we can set it back after all tests are finished.
  const realDateNow = Date.now.bind(global.Date);

  beforeAll(() => {
    // Return 1 millisecond when calling Date.now() in tests.
    const dateNowStub = jest.fn(() => 1);
    global.Date.now = dateNowStub;
  });

  it('shows mocked date', () => {
    console.log(Date.now());  // Returns 1.
  });

  afterAll(() => {
    // Set back to the original Date object.
    global.Date.now = realDateNow;
    console.log(Date.now()); // Returns current time in milliseconds.
  });
});

من هذه المقالة عن السخرية من التاريخ الحالي في Jest .

الحل النهائي: المزاح والتاريخ والسخرية .

  • تثبيت

في package.json الخاص بك تحت jest ، أنشئ مصفوفة setupFiles وأضف jest-date-mock إلى المصفوفة.

{
  "jest": {
    "setupFiles": ["./__setups__/other.js", "jest-date-mock"]
  }
}
  • الاستخدام

يمنحك واجهة برمجة تطبيقات بسيطة للتحكم في الطابع الزمني الحالي لحالات الاختبار.

import { advanceBy, advanceTo, clear } from 'jest-date-mock';

test('usage', () => {
  advanceTo(new Date(2018, 5, 27, 0, 0, 0)); // reset to date time.

  const now = Date.now();

  advanceBy(3000); // advance time 3 seconds
  expect(+new Date() - now).toBe(3000);

  advanceBy(-1000); // advance time -1 second
  expect(+new Date() - now).toBe(2000);

  clear();
  Date.now(); // will got current timestamp
});

أعتقد: كل الحلول الأخرى ليست منهجية أو مؤقتة.

شكرا لك انها عملت !!

لقد اتبعت البرنامج التعليمي لـ Hugo وانتهى بي الأمر بما يلي:

  // @ts-ignore
  .spyOn(global.Date, 'constructor')
  .mockImplementationOnce(() => new Date('2019-06-19T00:07:19.309Z'))

لذا ، فإن new Date() سيعود دائمًا new Date('2019-06-19T00:07:19.309Z')

يا له من هراء هذا الرجل. أقول لك البرنامج التعليمي لـ Hugo ويقول Hugo لك .... من فضلك لا تضللنا.

يدعم Jest 26 السخرية من Date باستخدام مؤقتات وهمية حديثة: https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers

إذا واجهتك مشكلة في محاولة السخرية من مُنشئ التاريخ في TS ، فجرب هذا:

const mockDate = new Date('Tue, 23 Jun 2020 14:34:56');
const RealDate = Date;
(global as any).Date = class extends RealDate {
  constructor() {
    super();
    return mockDate;
  }
};

// test some date related functionality

global.Date = RealDate;

يدعم Jest 26 السخرية من Date باستخدام مؤقتات وهمية حديثة: https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers

SimenB هذا رائع ولقد قمت للتو بالتحديث إلى الإصدار 26 ولكن لا يمكنني معرفة كيف نستخدم المزاح للسخرية من التاريخ. يتحدث مستندات الدعابة فقط عن كيفية الاستهزاء بالمؤقتات حتى تتمكن من اختبار setTimeOut ، ولكن كيف تفعل ذلك للسخرية من "التاريخ الجديد ()"؟

gregveres هنا مثال على مجموعة اختبار تحدد وقت النظام (طرق Date ) إلى تاريخ ثابت ويتعامل مع تقدم ذلك الوقت.

const FIXED_SYSTEM_TIME = '2020-11-18T00:00:00Z';

describe('Set Fixed Date', () => {
    beforeEach(() => {
        jest.useFakeTimers('modern');
        jest.setSystemTime(Date.parse(FIXED_SYSTEM_TIME));
    });

    afterEach(() => {
        jest.useRealTimers();
    });

    it('Should reflect fixed date', () => {
        expect(new Date().toISOString()).toEqual(FIXED_SYSTEM_TIME);

        const MS_TO_ADVANCE = 5000;

        jest.advanceTimersByTime(MS_TO_ADVANCE);

        expect(new Date().toISOString()).toEqual(new Date(Date.parse(FIXED_SYSTEM_TIME) + MS_TO_ADVANCE).toISOString());
    });
});

_Update: وشملت afterEach() لكلalexdanilowicz الصورة below._ تعليق

التحديث من نوفمبر 2020

_تبني ذلك ^ لأن هذا الخيط يتقدم في العمر ومرتبطًا بمنشور شائع للتكديس

تضمين التغريدة لمعلوماتك ، صححني إذا كنت مخطئًا ، لكنني أعتقد أنه سيكون من الجيد إضافة كل ما بعد (أو بعد الكل) إلى المواصفات الخاصة بك لإعادة التاريخ إلى الواقع. مجرد أن تكون آمنة.

describe('Test', () => {
  // to avoid race conditions between expected and actual date values
  beforeAll(() => {
    jest.useFakeTimers('modern'); // tell Jest to use a different timer implementation.
    jest.setSystemTime(new Date('20 Aug 2020 00:12:00 GMT').getTime())
  });

  afterAll(() => {
    // Back to reality...
    jest.useRealTimers();
  });

تضمين التغريدة نعم ، لقد أهملت تضمين عملية التنظيف في المثال الخاص بي. سأقوم بالتحديث باستخدام afterEach() لضمان الحفاظ على سلامة أي شخص يجد هذا الموضوع. شكرا!

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات