BEARBEITEN von https://github.com/facebook/jest/issues/2234#issuecomment -633402727
Gibt es eine Möglichkeit das aktuelle Datum zu verfälschen? So dass new Date()
oder Date.now()
eine verspottete Zeit statt der aktuellen Zeit zurückgibt?
Date.now = jest.fn
oder global.Date = jest.fn()
.
Für alle anderen, die damit auf Fehler stoßen, hatte ich einige Probleme, da das globale Date-Objekt andere Eigenschaften als den Konstruktor hat. Ich habe folgendes gemacht:
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;
Wenn Sie nicht angeben müssen, wie der Konstruktor aufgerufen wird, kann das Erweitern ausreichen:
const constantDate = new Date('2017-06-13T04:41:20')
/*eslint no-global-assign:off*/
Date = class extends Date {
constructor() {
return constantDate
}
}
Das funktioniert ziemlich gut für Date.now()
.
const now = Date.now()
Date.now = jest.genMockFunction().mockReturnValue(now)
Wenn Sie ein Date verspotten, vergessen Sie nicht, die echte Version zurückzusetzen.
Nach einem @callemo- Kommentar können Sie das folgende Snippet verwenden:
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')
})
})
Das Datum sollte wohl auch nach vorne verschoben werden, wenn jest.runTimersToTime()
und andere Zeitverspottungsfunktionen ausgeführt werden. Ich wurde von dem gleichen Problem gebissen, da ein Teil meines Codes von der Zeit und ein Teil von Timeouts abhing. Beide gleichzeitig zu verspotten – dh verspottete Timer laufen zu lassen UND die Mocks von Date.now
und Performance.now
wechseln, ist nicht die beste Erfahrung.
Eine Lösung für einen "vereinheitlichten" Timer-Mock war die Verwendung von lolex
anstelle von jest
Builtins, wie folgt:
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)
// ...
})
})
Aber es wäre toll, wenn diese Funktion eingebaut wäre.
Alte Ausgabe, aber mockdate
macht es einfach: 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 das ist eine nette Lösung, aber AFAIK verspottet es nicht performance.now()
, was eine nützliche Vorwärtsuhr ist (dh nicht zurückgesetzt wird, wenn der Benutzer die DateTime seines Systems ändert).
Tatsächlich funktioniert es in Jest nicht. Jest verwendet Jasmine v1.5.2-lite, hat also keine Uhr. Ich verwende lolex
.
Date.now()
ist für die meisten Anwendungen gut genug, permofrmance.now()
ist noch nicht im Knoten vorhanden — kann beispielsweise nicht in SSR verwendet werden —, also scheint es keine große Sache zu sein.
Natürlich ist lolex nicht in Scherz integriert.
@drpicox ah, gut zu wissen, dass es dann nicht funktioniert.
performance.now()
ist im Knoten vorhanden, seit v8.5.0 glaube ich. Sie können performance
aus dem eingebauten Modul 'perf_hooks'
importieren.
Angesichts der aktuellen Situation und der Anzahl der Stimmen/Kommentare möchte ich jedoch
FWIW Ich würde gerne lolex integrieren - es ist die einzige Bibliothek, die ich verwende, bei der ich denke, dass Jest eine Batterie fehlt
@cpojer Auf jeden Fall können wir das wieder öffnen. Derzeit gibt es nicht wirklich eine Möglichkeit, ein Datum zu verspotten UND den Zeitablauf auf einfache Weise zu simulieren.
Jasmin hat eine Uhrenklasse, in der Sie ein Datum UND eine
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);
Würde gerne eine ähnliche native Funktionalität haben. https://github.com/jasmine/jasmine/blob/master/src/core/Clock.js
Wir werden versuchen, zu Lolex zu migrieren, das Ihren Anwendungsfall unterstützt. Siehe #5165
Falls Sie das Datum _außerhalb_ einer Testumgebung verspotten müssen. Ich musste vorhersehbare Bildschnappschüsse der Benutzeroberfläche machen, auf der ein Datum angezeigt wird.
Bei mir hat das funktioniert:
https://github.com/schickling/timemachine
timemachine.config({
dateString: 'December 25, 1991 13:12:59'
});
console.log(new Date()); // December 25, 1991 13:12:59
Der Vorschlag von new Date(2018, 2, 3)
durcheinander bringen und war daher für mich keine gültige Option.
Beachten Sie, dass Sie auch die Zeitzone präzisieren müssen, damit es überall, zB auf Travis, vollständig funktioniert und das gleiche Ergebnis liefert.
timemachine.config({
dateString: 'December 25, 1991 13:12:59 GMT'
});
Die folgenden Test-Stubs Date geben während des Testlebenszyklus eine Konstante zurück.
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
ist nur eine Proxy-Variable, um Typskript zu erfüllen.
Ich musste mich über Date.now()
Das Einstellen der folgenden Zeile in der Konfiguration oder vor Tests hat bei mir funktioniert:
jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000)
Ich mochte den Ansatz von @vcarel , aber in meinem Fall wurde der Date-Konstruktor in einigen Fällen mit Argumenten verwendet, sodass ich ihn ändern musste, um andere Datumsangaben zu akzeptieren. Ich habe auch Date.now () hinzugefügt
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')
})
})
Ich benutze das, womit ich zufrieden bin: https://github.com/boblauer/MockDate
ich hab's gemacht
~~~
beschreiben('Test', () => {
const constantDate = neues Datum('2018-01-01T12:00:00')
vorAll(() => {
global.Date = Klasse erweitert Date {
Konstrukteur () {
Super()
Rückgabe konstantes Datum
}
}
})
~~~
Einfach etwas zur Antwort von @iwarner hinzufügen.
Es ist wahrscheinlich weniger fehleranfällig, so etwas zu tun, da es jedes Mal eine neue Datumsinstanz zurückgibt:
const constantDate = new Date('2018-01-01T12:00:00')
beforeAll(() => {
global.Date = class extends Date {
constructor () {
super(constantDate.getTime())
}
}
})
Dies ermöglicht die Verwendung von Funktionen, die Datumsobjekte mutieren (zB setMinutes), ohne dass constantDate mutiert und somit das Datum geändert wird, das von new Date zurückgegeben wird, zB
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
});
});
Dies ist, was ich verwende, nachdem ich alle oben genannten Punkte gelesen habe:
let currentDate;
beforeAll(() => {
currentDate = new Date();
const RealDate = Date;
global.Date = jest.fn(() => new RealDate(currentDate.toISOString()));
Object.assign(Date, RealDate);
});
@samboylett Wird dadurch das globale Datum für zukünftige Tests durcheinander gebracht? Hast du es auch in einer afterAll
Funktion zurückgesetzt?
Es wirkt sich nicht auf Tests in verschiedenen Dateien aus. Für mich brauchte alles in der aktuellen Datei das verspottete Datum, aber wenn Sie es zwischen den Tests in derselben Datei zurücksetzen müssen, sollten Sie ein beforeEach und afterEach verwenden und es einfach in afterEach zurücksetzen:
afterEach(() => {
global.Date = RealDate;
});
@samboylett danke! Ich habe es geschafft, meine Datumstests zum Laufen zu bringen, indem ich Ihr Beispiel als Grundlage verwendet habe.
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;
});
});
Vielleicht brauchst du Scherz-Date-Mock .
Geben Sie Ihnen eine einfache API, um den aktuellen Zeitstempel für Ihre Testfälle zu steuern.
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
});
Die obigen Lösungen deckten meinen Anwendungsfall nicht ab. Ich habe das Folgende basierend auf @callemo gemacht, dem die Unterstützung für Instanzen und das Festlegen bestimmter Daten fehlte.
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 Was ist dein Fall?
@javadoug Was ist dein Fall?
@hustcc mockDate() instanceof Date === true
.
@javadoug neue Version jest-date-mock
unterstützt. https://github.com/hustcc/jest-date-mock/pull/7
"Ich verspotte die Zeit nicht immer, aber wenn ich es tue, ist es ein Scherz" - der berüchtigte @satub
Ich musste new Date()
verspotten, brauchte aber den Rest der Date
Funktionalitäten, um wie gewohnt zu funktionieren. Dies ist die Lösung, die für mich funktioniert hat.
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
});
})
Ich erhalte eine Fehlermeldung, wenn ich versuche, global.Date zuzuweisen:
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)
Es sieht so aus, als ob das Problem darin besteht, dass ich den JUnit-Reporter verwende, der im Kontext des Tests ausgeführt wird, und das Datum verwende, das bereits zerstört wurde, da die anonyme Klasse zerstört wurde.
Also ja, das globale Datum ist durcheinander, wenn Sie Vorschläge wie alle oben genannten verwenden. Und es ist nur ein Problem, wenn Sie nicht standardmäßige Reporter verwenden.
Reporter sollten nicht in der Sandbox hingerichtet werden. Jasmine-Reporter könnten sich jedoch in einige Jasmin-Sachen einklinken, die nicht absichtlich unterstützt werden
Oh, Sie sagen also, dass diese Art von Code nicht unterstützt wird?
const jasmine = global.jasmine;
jasmine.getEnv().addReporter(junitReporter)
Fehler passiert hier:
https://github.com/facebook/jest/blob/f9fd98fd4e38978e96a86f1c8796593cad7ac470/packages/jest-jasmine2/src/jasmine/ReportDispatcher.js#L63 -L72
Richtig, du solltest verwenden
https://jestjs.io/docs/en/configuration#reporters -array-modulename-modulename-options.
ZB https://github.com/jest-community/jest-junit
@niieani ,
Eine Lösung für einen "vereinheitlichten" Timer-Mock war die Verwendung von
lolex
anstelle vonjest
Builtins, wie folgt:
Ich habe dieses Beispiel ausprobiert und es hat dazu geführt, dass meine Tests für immer hängen (in einer CRA, die [email protected] verwendet). Hat jemand Erfolg mit lolex mit Jest?
@kentcdodds stellen Sie sicher, dass Sie nicht gleichzeitig gefälschte Timer verwenden. Wenn es immer noch hängt, können Sie ein Problem mit einer Reproduktion erstellen? Lolex sollte auf jeden Fall funktionieren
Ja, es funktioniert gut für mich in einer isolierten Situation, also mache ich wahrscheinlich woanders etwas Seltsames. Vielen Dank!
Wenn Sie nur diese Fälle verspotten müssen:
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;
}
}
Dies ist, was ich verwende, nachdem ich alle oben genannten Punkte gelesen habe:
let currentDate; beforeAll(() => { currentDate = new Date(); const RealDate = Date; global.Date = jest.fn(() => new RealDate(currentDate.toISOString())); Object.assign(Date, RealDate); });
Danke @samboylett
Dies funktionierte für mich beim Verspotten des neuen Datums ()
@ petromoldovan ist definitiv die beste Antwort.
Fügen Sie am Ende der Tests einen Anruf bei mockRestore
, um das ursprüngliche Datum wiederherzustellen:
const dateNowMockFn = jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000);
// ... code with tests
dateNowMockFn.mockRestore();
@vcarel- Lösung ein wenig verbessert, falls Sie möchten, dass der Mock eine Date-Instanz anstelle einer der neuen Klasse
const RealDate = Date
const mockDate = (isoDate) => {
global.Date = class extends RealDate {
constructor () {
return super(isoDate)
}
}
}
afterEach(() => {
global.Date = RealDate
})
Ich mag hier vielleicht gegen Windmühlen kippen, aber es lohnt sich, auf das alte Sprichwort hinzuweisen: Verspotte nicht, was du nicht besitzt . Wickeln Sie es stattdessen in eine Funktion ein. Heutzutage ist es mit Standardargumentwerten so praktisch:
const myFunc = (msg, date = new Date()) => console.log(`${msg}! ${date}`);
Jetzt können Sie im Produktionscode die Vorgabe nutzen:
myFunc("Hello"); // => Hello! Fri Mar 22 2019 21:11:26 GMT-0400 (EDT)
Und im Testcode können Sie das Datum explizit übergeben und es so verspotten:
myFunc("Hello", dateObj) // => Hello! ...
@yawaramin Dazu gibt es sicherlich einige unterschiedliche Standpunkte. Es gibt ein Lager, das glaubt, dass Tests im Dienst des Anwendungscodes leben sollten, und es gibt einen Punkt, an dem der Schwanz mit dem Hund wedelt (Pete Hunt hat einige starke Meinungen dazu).
Ich sage nicht, dass Ihre vorgeschlagene Methode keine gültige Option ist, aber sie könnte vielleicht als situationsgerechter Weg präsentiert werden
@cheapsteak Ich denke, situative Angemessenheit ist der Standardzustand der Dinge. Es schadet nicht, die Leute sanft daran zu erinnern, dass es immer eine Möglichkeit gibt, die Testbarkeit zu verbessern und dass dies normalerweise die Wartbarkeit verbessert :-)
Gibt es eine Möglichkeit, die aktuelle Zeit von Jest zu erhalten, während Timer gesendet werden? So etwas wie Scherz.jetzt?
Angenommen, ich habe Timer UND Aufrufe von Date.now(). Ich rufe jest.runAllTimers() auf. Es wäre cool, wenn ich jest.spyOn(Date, 'now').mockImplementation(() => something ) aufrufen
Ich musste mich über
Date.now()
Das Einstellen der folgenden Zeile in der Konfiguration oder vor Tests hat bei mir funktioniert:
jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000)
Komisch, dass es bei so vielen Leuten funktioniert, aber nicht bei mir. Hmm.
Ich weiß nicht, was los ist, aber egal, wie ich Date
neu Date.now()
existiert immer und gibt immer einen gültigen Wert zurück.
Date.now = null
tut nichts.
global.Date.now = null
tut nichts.
jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000);
tut nichts.
Die Installation und Verwendung von lolex
funktioniert bei Zeitüberschreitungen, hat aber keine Auswirkung auf Date.now()
MockDate
hat keine Auswirkung.
Mir fehlt etwas Offensichtliches, denke ich. Vielleicht macht eine andere Abhängigkeit etwas... so verwirrt.
@mherodev Überprüfen Sie Ihren Test, stellen Sie ein Datum vor, bevor Ihre Testfunktion ausgeführt / Komponenten rendert?
In einem Testblock mache ich so etwas wie...
Date.now = () => 1;
Date = null;
global.Date = null;
console.log(`Date.now()`, Date.now()); // Date.now() 1560239936091
Aber diese Überschreibung bewirkt nichts. Ich finde es sehr verwirrend.
Ich bin Hugos Tutorial gefolgt und habe Folgendes getan:
// @ts-ignore
.spyOn(global.Date, 'constructor')
.mockImplementationOnce(() => new Date('2019-06-19T00:07:19.309Z'))
new Date()
gibt also immer new Date('2019-06-19T00:07:19.309Z')
Update: Es scheint, dass meine Date-Mocks aufgrund eines Fehlers mit der Transpilation von Babel in meiner Umgebung nicht funktioniert haben. Etwas im Zusammenhang mit der Verwendung von @babel/runtime-corejs2
Ultimative Lösung: jest-date-mock .
Erstellen Sie in Ihrer package.json unter dem jest ein setupFiles-Array und fügen Sie jest-date-mock zum Array hinzu.
{
"jest": {
"setupFiles": ["./__setups__/other.js", "jest-date-mock"]
}
}
Geben Sie Ihnen eine einfache API, um den aktuellen Zeitstempel für Ihre Testfälle zu steuern.
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
});
Ich denke: Alle anderen Lösungen sind weder systematisch noch temporär.
es sieht so aus, als ob die Babel-Transformation frühere Problemumgehungen bricht.
Meine Lösung ist das Hinzufügen einer neuen Datei namens 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)
Fügen Sie in jest.config.js
am Eintrag setupFilesAfterEnv
(oder setupFiles
in der alten Scherzversion) '<rootDir>/jest/setupMockDate.js'
.
Jetzt kannst du laufen
Date.mockNow(10)
expect(Date.now()).toBe(10)
Date.mockRestore()
expect(Date.now()).not.toBe(10)
Sinon funktioniert gut für mich https://sinonjs.org/releases/v1.17.7/fake-timers/
Zu spät zur Party, aber ich denke, Scherz hat alle Funktionen, die Sie dafür brauchen.
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)
})
Ich verwende vue-moment und scherz und habe festgestellt, dass der beste Weg darin besteht, so etwas zu tun:
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');
});
})
Verwenden von ES6
const fixedDate = new Date('2019-03-1');
const RealDate = Date;
beforeEach(() => { Date.now = () => fixedDate; });
afterEach(() => { global.Date = RealDate; });
Wenn Sie Date.now()
const dateSpy = jest.spyOn(Date, 'now');
dateSpy.mockReturnValue(TIMESTAMP);
Für alle anderen, die damit auf Fehler stoßen, hatte ich einige Probleme, da das globale Date-Objekt andere Eigenschaften als den Konstruktor hat. Ich habe folgendes gemacht:
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;
Ich wollte die gesamte Date-Klasse verspotten und die von @kristojorg vorgeschlagene
Ich bin mir nicht sicher, ob dies der richtige Weg ist, aber diese Lösung funktioniert in TypeScript gut, indem das von @nilobarp erwähnte
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());
});
});
Es ist erwähnenswert, dass dies nur funktioniert, wenn Sie ein neues Date
-Objekt instanziieren, und nicht für Date.now()
. Es gibt einen Kommentar zu Date.now .
In einem Testblock mache ich so etwas wie...
Date.now = () => 1; Date = null; global.Date = null; console.log(`Date.now()`, Date.now()); // Date.now() 1560239936091
Aber diese Überschreibung bewirkt nichts. Ich finde es sehr verwirrend.
Ich habe das gleiche Problem: Ich habe eine ganze Reihe von Codebeispielen getestet, die in dieser Ausgabe gefunden wurden, und keines hat für mich funktioniert: Mock scheint ignoriert zu werden.
Wie hast du dein Problem behoben?
Wir verwenden auch Babel, also könnte dies auch zusammenhängen.
In einem Testblock mache ich so etwas wie...
Date.now = () => 1; Date = null; global.Date = null; console.log(`Date.now()`, Date.now()); // Date.now() 1560239936091
Aber diese Überschreibung bewirkt nichts. Ich finde es sehr verwirrend.
Ich habe das gleiche Problem: Ich habe eine ganze Reihe von Codebeispielen getestet, die in dieser Ausgabe gefunden wurden, und keines hat für mich funktioniert: Mock scheint ignoriert zu werden.
Wie hast du dein Problem behoben?
Wir verwenden auch Babel, also könnte dies auch zusammenhängen.
@warpdesign diese Lösung scheint für mich mit Jest in TypeScript zu funktionieren.
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.
});
});
Von diesem Artikel über das Verspotten des aktuellen Datums in Jest .
Ultimative Lösung: jest-date-mock .
- Installieren
Erstellen Sie in Ihrer package.json unter dem jest ein setupFiles-Array und fügen Sie jest-date-mock zum Array hinzu.
{ "jest": { "setupFiles": ["./__setups__/other.js", "jest-date-mock"] } }
- Verwendungszweck
Geben Sie Ihnen eine einfache API, um den aktuellen Zeitstempel für Ihre Testfälle zu steuern.
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 });
Ich denke: Alle anderen Lösungen sind weder systematisch noch temporär.
Danke es hat funktioniert !!
Ich bin Hugos Tutorial gefolgt und habe Folgendes getan:
// @ts-ignore .spyOn(global.Date, 'constructor') .mockImplementationOnce(() => new Date('2019-06-19T00:07:19.309Z'))
new Date()
gibt also immernew Date('2019-06-19T00:07:19.309Z')
Was ist dieser Mann für ein Mist. Du sagst Hugos Tutorial und Hugo sagt deins... bitte führe uns nicht in die Irre.
Jest 26 unterstützt das Verspotten von Date
mit modernen gefälschten Timern: https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers
Wenn Sie nicht versuchen, den Date-Konstruktor in TS zu verspotten, versuchen Sie Folgendes:
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 unterstützt das Verspotten von
Date
mit modernen gefälschten Timern: https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers
@SimenB Das ist großartig und ich habe gerade auf v26 aktualisiert, kann aber nicht herausfinden, wie wir Scherze verwenden, um das Datum zu verspotten. Die Scherzdokumente sprechen nur darüber, wie man Timer verspottet, damit Sie setTimeOut testen können, aber wie macht man es, um "new Date()" zu verspotten?
@gregveres Hier ist eine Beispiel-Testsuite, die die Systemzeit ( Date
-Methoden) auf ein festes Datum setzt und das Vorrücken dieser Zeit behandelt.
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: Inklusive afterEach()
pro @alexdanilowicz s‘Kommentar below._
_Das ist fett ^ da dieser Thread alt wird und mit einem beliebten Stackoverflow-Post verknüpft ist_
@seansullivan Genial ! Zu Ihrer Information, korrigieren Sie mich, wenn ich falsch liege, aber ich denke, es wäre schön, Ihren Spezifikationen ein afterEach (oder afterAll) hinzuzufügen, um das Datum auf die Realität zurückzusetzen. Nur um sicher zu gehen.
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 Perfekt. Ja, ich habe die Bereinigung in meinem Beispiel vernachlässigt. Ich werde mit dem afterEach()
aktualisieren, um sicherzustellen, dass für jeden, der diesen Thread findet, die Vernunft gewahrt bleibt. Vielen Dank!
Hilfreichster Kommentar
Für alle anderen, die damit auf Fehler stoßen, hatte ich einige Probleme, da das globale Date-Objekt andere Eigenschaften als den Konstruktor hat. Ich habe folgendes gemacht: