Jest: Verspotten der aktuellen Uhrzeit für Datum

Erstellt am 6. Dez. 2016  ·  72Kommentare  ·  Quelle: facebook/jest

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?

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:

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;

Alle 72 Kommentare

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 von jest 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 .

  • 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.

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 immer new 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._

Update vom Nov. 2020

_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!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen