Jest: Mengejek waktu saat ini untuk Tanggal

Dibuat pada 6 Des 2016  ·  72Komentar  ·  Sumber: facebook/jest

EDIT oleh @SimenB 25-05-2020: Lihat jawaban yang diperbarui: https://github.com/facebook/jest/issues/2234#issuecomment -633402727

Apakah ada cara untuk mengejek tanggal saat ini? Sehingga new Date() atau Date.now() mengembalikan waktu tiruan alih-alih waktu saat ini?

Komentar yang paling membantu

Untuk siapa pun di luar sana yang mengalami kesalahan dengan ini, saya memiliki beberapa masalah karena objek Date global memiliki properti selain konstruktor. Saya melakukan hal berikut:

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;

Semua 72 komentar

Date.now = jest.fn atau global.Date = jest.fn() .

Untuk siapa pun di luar sana yang mengalami kesalahan dengan ini, saya memiliki beberapa masalah karena objek Date global memiliki properti selain konstruktor. Saya melakukan hal berikut:

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;

Jika Anda tidak perlu menegaskan bagaimana konstruktor dipanggil, maka perluasan sudah cukup:

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

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

Ini bekerja cukup baik untuk Date.now() .

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

Setiap kali Anda mengejek kencan, jangan lupa untuk mengembalikan versi aslinya.
Mengikuti komentar @callemo , Anda dapat menggunakan cuplikan berikut:

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

Diperdebatkan, Tanggal juga harus dimajukan saat menjalankan jest.runTimersToTime() dan fungsi mengejek waktu lainnya. Saya digigit oleh masalah yang sama, karena sebagian dari kode saya bergantung pada waktu, dan sebagian pada batas waktu. Mengejek keduanya pada saat yang sama -- yaitu menjalankan penghitung waktu tiruan DAN mengganti tiruan Date.now dan Performance.now bukanlah pengalaman terbaik.

Solusi untuk tiruan pengatur waktu "bersatu" adalah menggunakan lolex alih-alih jest bawaan, seperti ini:

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)
    // ...
  })
})

Tetapi akan sangat bagus untuk memiliki fitur ini bawaan.

Masalah lama, tetapi mockdate membuatnya mudah: 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 itu solusi yang bagus, namun AFAIK itu tidak mengejek performance.now() , yang merupakan jam maju-saja yang berguna (yaitu tidak akan disetel kembali oleh pengguna yang mengubah DateTime sistemnya).

Sebenarnya itu tidak berfungsi di Jest. Jest menggunakan Jasmine v1.5.2-lite, sehingga tidak memiliki jam. Saya menggunakan lolex .

Date.now() cukup bagus untuk sebagian besar aplikasi, permofrmance.now() belum ada di node —tidak dapat digunakan di SSR misalnya—, jadi sepertinya bukan masalah besar.

Tentu saja, lolex tidak terintegrasi dengan lelucon.

@drpicox ah, senang mengetahui itu tidak berhasil.
performance.now() ada di simpul, sejak v8.5.0 saya percaya. Anda dapat mengimpor performance dari modul bawaan 'perf_hooks' .

Namun, mengingat situasi saat ini dan jumlah suara/komentar yang diperoleh, saya ingin melakukan ping ke @cpojer untuk mempertimbangkan membuka kembali masalah ini.

FWIW Saya ingin mengintegrasikan lolex - itu satu-satunya perpustakaan yang saya gunakan di mana saya pikir Jest tidak memiliki baterai

@cpojer Dengan cara apa pun kami dapat membuka kembali ini. Sampai sekarang, sebenarnya tidak ada cara untuk mengejek tanggal DAN mensimulasikan berlalunya waktu dengan cara yang mudah.

melati memiliki kelas jam di mana Anda dapat mengejek tanggal DAN waktu sebelumnya, melalui:

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

Akan senang untuk memiliki fungsi yang sama asli. https://github.com/jasmine/jasmine/blob/master/src/core/Clock.js

Kami akan mencoba bermigrasi ke Lolex, yang mendukung kasus penggunaan Anda. Lihat #5165

Jika Anda perlu mengejek Date _outside_ dari lingkungan pengujian. Saya perlu mengambil snapshot gambar UI yang dapat diprediksi di mana tanggal ditampilkan.

Ini berhasil untuk saya:
https://github.com/schickling/timemachine

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

Saran @omegdadisc adalah yang terbaik menurut saya. Tanggal Mengejek untuk selalu mengembalikan tanggal yang sama (seperti yang disarankan dalam jawaban pertama) akan mengacaukan hal-hal seperti new Date(2018, 2, 3) jadi itu bukan opsi yang valid bagi saya.

Perhatikan bahwa Anda juga perlu menentukan zona waktu agar dapat berfungsi sepenuhnya di mana saja, misalnya di Travis dan menghasilkan hasil yang sama.

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

Tanggal stub pengujian berikut untuk mengembalikan konstanta selama siklus hidup pengujian.

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 hanyalah variabel proxy untuk memenuhi TypeScript.

Saya perlu mengejek Date.now()

mengatur baris di bawah ini dalam konfigurasi atau sebelum tes berhasil untuk saya:

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

Saya menyukai pendekatan @vcarel , tetapi dalam kasus saya konstruktor Date digunakan dengan argumen dalam beberapa kasus, jadi saya perlu memodifikasinya untuk menerima tanggal lain. Saya juga menambahkan 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')
  })
})

Saya menggunakan ini, yang saya senangi: https://github.com/boblauer/MockDate

Saya telah melakukan ini

~~~
deskripsikan('Uji', () => {
const constantDate = new Date('2018-01-01T12:00:00')

sebelumSemua(() => {
global.Date = kelas memperpanjang Tanggal {
konstruktor () {
super()
kembalikan tanggal konstan
}
}
})
~~~

Hanya ingin menambahkan sedikit ke jawaban @callemo dan @iwarner .

Mungkin lebih sedikit kesalahan yang rentan untuk melakukan sesuatu seperti itu mengembalikan contoh tanggal baru setiap kali:

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

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

Ini memungkinkan fungsi yang mengubah objek tanggal (misalnya setMinutes) untuk digunakan tanpa mengubah constantDate dan dengan demikian mengubah tanggal yang dikembalikan dari Tanggal baru misalnya

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

Inilah yang saya gunakan setelah membaca semua hal di atas:

let currentDate;

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

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

@samboylett Apakah ini mengacaukan tanggal global untuk tes di masa mendatang? Apakah Anda juga meresetnya dalam fungsi afterAll ?

Itu tidak akan mempengaruhi tes di file yang berbeda. Bagi saya semua yang ada di file saat ini memerlukan tanggal yang diejek, tetapi jika Anda perlu mengatur ulang di antara tes dalam file yang sama, Anda harus menggunakan beforeEach dan afterEach, dan atur kembali di afterEach:

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

@samboylett terima kasih! Saya berhasil membuat tes tanggal saya berfungsi dengan menggunakan contoh Anda sebagai basis.

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

Mungkin Anda perlu jest-date-mock .

Memberi Anda API sederhana untuk mengontrol stempel waktu saat ini untuk kasus pengujian Anda.

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

Solusi di atas tidak mencakup kasus penggunaan saya. Saya melakukan hal berikut berdasarkan @callemo yang tidak memiliki dukungan untuk instanceof dan menetapkan tanggal tertentu.

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 Apa kasus Anda?

@javadoug Apa kasus Anda?

@hustcc mockDate() instanceof Date === true .

@javadoug versi baru jest-date-mock didukung. https://github.com/hustcc/jest-date-mock/pull/7

'Saya tidak selalu mengolok-olok waktu, tetapi ketika saya melakukannya, itu adalah lelucon` - @satub yang terkenal

Saya perlu mengejek new Date() tetapi membutuhkan fungsionalitas Date lainnya agar berfungsi seperti biasa. Ini adalah solusi yang berhasil untuk saya.

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

Saya mendapatkan kesalahan setiap kali saya mencoba menetapkan ke 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)

Sepertinya masalahnya adalah saya menggunakan reporter JUnit yang dieksekusi dalam konteks pengujian dan menggunakan Date yang sudah dihancurkan karena kelas anonim dihancurkan.

Jadi ya, Tanggal global kacau ketika Anda menggunakan saran seperti semua hal di atas. Dan itu hanya masalah ketika Anda menggunakan reporter non-standar.

Wartawan tidak boleh dieksekusi di dalam kotak pasir. Wartawan Jasmine mungkin mengaitkan beberapa hal melati yang tidak sengaja didukung

Oh, jadi maksud Anda kode semacam ini tidak didukung?

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

Kesalahan terjadi di sini:
https://github.com/facebook/jest/blob/f9fd98fd4e38978e96a86f1c8796593cad7ac470/packages/jest-jasmine2/src/jasmine/ReportDispatcher.js#L63 -L72

Benar, Anda harus menggunakan
https://jestjs.io/docs/en/configuration#reporters -array-modulename-modulename-options.
Misalnya https://github.com/jest-community/jest-junit

@niieani ,

Solusi untuk tiruan pengatur waktu "bersatu" adalah menggunakan lolex alih-alih jest bawaan, seperti ini:

Saya mencoba contoh itu dan itu mengakibatkan pengujian saya menggantung selamanya (dalam CRA yang menggunakan [email protected]). Adakah yang berhasil menggunakan lolex dengan Jest?

@kentcdodds pastikan untuk tidak menggunakan penghitung waktu palsu secara bersamaan. Jika masih hang, keberatan membuat masalah dengan reproduksi? Lolex pasti berfungsi

Ya, itu bekerja dengan baik untuk saya dalam situasi yang terisolasi, jadi saya mungkin melakukan sesuatu yang aneh di tempat lain. Terima kasih!

Jika Anda hanya perlu mengejek kasus-kasus ini:

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

Inilah yang saya gunakan setelah membaca semua hal di atas:

let currentDate;

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

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

Terima kasih @samboylett

Ini bekerja untuk saya dalam mengejek Tanggal baru ()

@petromoldovan jelas merupakan jawaban terbaik.

Tambahkan panggilan ke mockRestore di akhir tes untuk mengembalikan tanggal asli:

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

Solusi @vcarel yang ditingkatkan sedikit, jika Anda ingin tiruan mengembalikan instance Date alih-alih salah satu kelas baru:

    const RealDate = Date

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

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

Saya mungkin memiringkan kincir angin di sini, tetapi ada baiknya menunjukkan pepatah lama: Jangan mengejek apa yang tidak Anda miliki . Sebagai gantinya, bungkus dalam sebuah fungsi. Saat ini sangat nyaman dengan nilai argumen default:

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

Sekarang dalam kode produksi Anda dapat memanfaatkan default:

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

Dan dalam kode pengujian Anda dapat memasukkan tanggal secara eksplisit, sehingga mengejeknya:

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

@yawaramin Pasti ada beberapa sudut pandang yang berbeda tentang ini. Ada sebuah kamp yang percaya bahwa tes harus dilakukan untuk melayani kode aplikasi, dan ada titik di mana ekor mulai mengibaskan anjing (Pete Hunt memiliki beberapa pendapat kuat tentang ini)

Tidak mengatakan bahwa metode yang Anda sarankan bukanlah opsi yang valid, tetapi mungkin itu dapat disajikan sebagai cara yang sesuai dengan situasi untuk pergi

@cheapsteak Saya pikir kesesuaian situasional adalah keadaan default. Tidak ada salahnya untuk mengingatkan orang dengan lembut bahwa selalu ada peluang untuk meningkatkan kemampuan pengujian dan hal itu biasanya meningkatkan kemampuan pemeliharaan :-)

Apakah ada cara untuk mendapatkan waktu lelucon saat ini karena mengirimkan penghitung waktu? Sesuatu seperti lelucon. Sekarang?

Misalkan saya memiliki timer DAN panggilan ke Date.now(). Saya memanggil jest.runAllTimers(). Akan lebih keren jika saya bisa memanggil jest.spyOn(Date, 'now').mockImplementation(() => something ) sehingga callback timer berjalan dan dapat memeriksa waktu simulasi.

Saya perlu mengejek Date.now()

mengatur baris di bawah ini dalam konfigurasi atau sebelum tes berhasil untuk saya:

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

lucu cara kerjanya untuk begitu banyak orang tetapi tidak untuk saya. Hmm.

Saya tidak tahu apa yang terjadi, tetapi tidak peduli bagaimana saya menetapkan kembali Date , Date.now() selalu ada dan selalu mengembalikan nilai yang valid.

Date.now = null tidak melakukan apa-apa.
global.Date.now = null tidak melakukan apa-apa.
jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000); tidak melakukan apa-apa.
Menginstal dan menggunakan lolex bekerja pada waktu habis, tetapi tidak berpengaruh pada Date.now()
MockDate tidak berpengaruh.

Saya kehilangan sesuatu yang jelas, saya pikir. Mungkin ketergantungan lain sedang melakukan sesuatu... jadi bingung.

@mherodev periksa pengujian Anda, apakah Anda mengejek tanggal sebelum fungsi pengujian Anda dijalankan/komponen dirender?

Di dalam blok uji saya melakukan sesuatu seperti ...

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

Tapi penggantian itu tidak menghasilkan apa-apa. Saya merasa sangat membingungkan.

Saya mengikuti tutorial Hugo dan akhirnya melakukan:

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

Jadi, new Date() akan selalu mengembalikan new Date('2019-06-19T00:07:19.309Z')

Pembaruan: Tampaknya olok-olok Tanggal saya tidak berfungsi karena bug dengan bagaimana babel berpindah-pindah di lingkungan saya. Sesuatu yang berhubungan dengan bagaimana kita menggunakan @babel/runtime-corejs2

Solusi Utama: jest-date-mock .

  • Install

Di package.json Anda di bawah jest, buat array setupFiles dan tambahkan jest-date-mock ke array.

{
  "jest": {
    "setupFiles": ["./__setups__/other.js", "jest-date-mock"]
  }
}
  • penggunaan

Memberi Anda API sederhana untuk mengontrol stempel waktu saat ini untuk kasus pengujian Anda.

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

Saya pikir: Semua solusi lain tidak sistematis, atau sementara.

sepertinya transformasi babel mematahkan solusi sebelumnya.

Solusi saya adalah menambahkan file baru bernama 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)

Di jest.config.js di setupFilesAfterEnv entri (atau setupFiles dalam versi lelucon lama), tambahkan '<rootDir>/jest/setupMockDate.js' .

Sekarang, Anda dapat berlari

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

Sinon bekerja dengan baik untuk saya https://sinonjs.org/releases/v1.17.7/fake-timers/

Terlambat ke pesta, tapi saya pikir lelucon memiliki semua fungsi yang Anda butuhkan untuk ini.

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

Saya menggunakan vue-moment dan lelucon, dan telah menemukan cara terbaik adalah melakukan sesuatu seperti ini:

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

Menggunakan ES6

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

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

Jika Anda menggunakan Date.now()

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

Untuk siapa pun di luar sana yang mengalami kesalahan dengan ini, saya memiliki beberapa masalah karena objek Date global memiliki properti selain konstruktor. Saya melakukan hal berikut:

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;

Saya ingin mengejek seluruh kelas Date dan metode yang disarankan oleh @kristojorg tampak ideal.

Saya tidak yakin apakah ini cara yang tepat untuk melakukannya, tetapi solusi ini berfungsi dengan baik di TypeScript dengan memperbaiki masalah pengetikan seperti yang disebutkan oleh @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());
  });
});

Perlu disebutkan bahwa ini hanya berfungsi ketika Anda membuat instance objek Date dan tidak akan berfungsi untuk Date.now() . Ada komentar tentang Date.now .

Di dalam blok uji saya melakukan sesuatu seperti ...

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

Tapi penggantian itu tidak menghasilkan apa-apa. Saya merasa sangat membingungkan.

Saya mengalami masalah yang sama: menguji sejumlah besar contoh kode yang ditemukan dalam masalah ini dan tidak ada yang berhasil untuk saya: tiruan tampaknya diabaikan.

Bagaimana Anda memperbaiki masalah Anda?

Kami juga menggunakan Babel jadi ini mungkin terkait juga.

Di dalam blok uji saya melakukan sesuatu seperti ...

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

Tapi penggantian itu tidak menghasilkan apa-apa. Saya merasa sangat membingungkan.

Saya mengalami masalah yang sama: menguji sejumlah besar contoh kode yang ditemukan dalam masalah ini dan tidak ada yang berhasil untuk saya: tiruan tampaknya diabaikan.

Bagaimana Anda memperbaiki masalah Anda?

Kami juga menggunakan Babel jadi ini mungkin terkait juga.

@warpdesign solusi ini tampaknya bekerja untuk saya dengan Jest di 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.
  });
});

Dari artikel ini tentang mengejek Date in Jest saat ini .

Solusi Utama: jest-date-mock .

  • Install

Di package.json Anda di bawah jest, buat array setupFiles dan tambahkan jest-date-mock ke array.

{
  "jest": {
    "setupFiles": ["./__setups__/other.js", "jest-date-mock"]
  }
}
  • penggunaan

Memberi Anda API sederhana untuk mengontrol stempel waktu saat ini untuk kasus pengujian Anda.

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

Saya pikir: Semua solusi lain tidak sistematis, atau sementara.

Terima kasih itu berhasil!!

Saya mengikuti tutorial Hugo dan akhirnya melakukan:

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

Jadi, new Date() akan selalu mengembalikan new Date('2019-06-19T00:07:19.309Z')

Apa-apaan pria ini. Anda mengatakan tutorial Hugo dan Hugo mengatakan tutorial Anda.... tolong jangan menyesatkan kami.

Jest 26 mendukung ejekan Date menggunakan penghitung waktu palsu modern: https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers

Jika Anda terjebak dengan mencoba mengejek konstruktor Date di TS, coba ini:

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 mendukung ejekan Date menggunakan penghitung waktu palsu modern: https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers

@SimenB Itu bagus dan saya baru saja memperbarui ke v26 tetapi tidak tahu bagaimana kami menggunakan lelucon untuk mengejek tanggal. Dokumen lelucon hanya berbicara tentang cara mengejek pengatur waktu sehingga Anda dapat menguji setTimeOut, tetapi bagaimana Anda melakukannya untuk mengejek "Tanggal baru ()"?

@gregveres Berikut adalah contoh test suite yang menetapkan waktu sistem ( metode Date ) ke tanggal tetap dan menangani memajukan waktu itu.

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: Termasuk afterEach() per @alexdanilowicz 's komentar below._

Pembaruan dari November 2020

_Bolding itu ^ karena utas ini semakin tua dan ditautkan ke posting stackoverflow yang populer_

@seansullivan Luar biasa! FYI, perbaiki saya jika saya salah, tetapi saya pikir akan lebih baik untuk menambahkan afterEach (atau afterAll) ke spesifikasi Anda untuk mengatur ulang tanggal kembali ke kenyataan. Hanya untuk aman.

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

@alexdanilowicz Sempurna. Ya, saya lupa memasukkan pembersihan dalam contoh saya. Saya akan memperbarui dengan afterEach() untuk memastikan kewarasan tetap terjaga bagi siapa saja yang menemukan utas ini. Terima kasih!

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

kgowru picture kgowru  ·  3Komentar

hramos picture hramos  ·  3Komentar

Secretmapper picture Secretmapper  ·  3Komentar

stephenlautier picture stephenlautier  ·  3Komentar

paularmstrong picture paularmstrong  ·  3Komentar