Jest: Burlarse de la hora actual para la fecha

Creado en 6 dic. 2016  ·  72Comentarios  ·  Fuente: facebook/jest

EDITAR por @SimenB 25-05-2020: Ver respuesta actualizada: https://github.com/facebook/jest/issues/2234#issuecomment -633402727

¿Hay alguna forma de burlarse de la fecha actual? ¿Entonces new Date() o Date.now() devuelve una hora simulada en lugar de la hora actual?

Comentario más útil

Para cualquier otra persona que tenga errores con esto, tuve algunos problemas porque el objeto Date global tiene propiedades distintas del constructor. Hice lo siguiente:

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;

Todos 72 comentarios

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

Para cualquier otra persona que tenga errores con esto, tuve algunos problemas porque el objeto Date global tiene propiedades distintas del constructor. Hice lo siguiente:

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;

Si no necesita afirmar cómo se llama al constructor, extender podría ser suficiente:

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

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

Esto funciona bastante bien por Date.now() .

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

Siempre que simule una cita, no olvide volver a colocar la versión real.
Después del comentario de @callemo , puede usar el siguiente fragmento:

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

Podría decirse que Date también debería adelantarse al ejecutar jest.runTimersToTime() y otras funciones de simulación de tiempo. Me mordió el mismo problema, ya que parte de mi código dependía del tiempo y parte de los tiempos de espera. Burlarse de ambos al mismo tiempo, es decir, ejecutar temporizadores simulados Y cambiar los simulacros Date.now y Performance.now no es la mejor experiencia.

Una solución para un simulacro de temporizadores "unificados" era usar lolex lugar de jest incorporados, así:

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

Pero sería genial tener esta función incorporada.

Problema antiguo, pero mockdate facilita esto: 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 es una buena solución, sin embargo, AFAIK, no se burla de performance.now() , que es un reloj útil que solo avanza (es decir, no se retrasará si el usuario cambia la fecha y hora de su sistema).

De hecho, no funciona en Jest. Jest usa Jasmine v1.5.2-lite, por lo que no tiene reloj. Estoy usando lolex .

Date.now() es suficientemente bueno para la mayoría de las aplicaciones, permofrmance.now() aún no está presente en el nodo —no se puede usar en SSR, por ejemplo—, por lo que no parece ser un gran problema.

Por supuesto, lolex no está integrado con jest.

@drpicox ah, es bueno saber que entonces no funciona.
performance.now() está presente en el nodo, desde v8.5.0, creo. Puede importar performance desde el módulo integrado 'perf_hooks' .

Aún así, dada la situación actual y la cantidad de votos / comentarios que está recibiendo, me gustaría hacer ping a @cpojer para considerar la reapertura de este problema.

FWIW Me encantaría integrar lolex: es la única biblioteca que uso donde creo que a Jest le falta una batería

@cpojer De cualquier forma podemos reabrir esto. A partir de ahora, no hay realmente una manera de burlarse de una cita Y simular el paso del tiempo de una manera fácil.

jazmín tiene una clase de reloj donde puede simular una fecha Y una hora avanzada, a través de:

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

Me encantaría tener una funcionalidad nativa similar. https://github.com/jasmine/jasmine/blob/master/src/core/Clock.js

Intentaremos migrar a Lolex, que es compatible con su caso de uso. Ver # 5165

En caso de que necesite simular Date _outside_ de un entorno de prueba. Necesitaba tomar instantáneas de imágenes predecibles de la interfaz de usuario donde se muestra una fecha.

Esto funcionó para mí:
https://github.com/schickling/timemachine

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

La sugerencia de @omegdadisc es la mejor, creo. Mocking Date para devolver siempre la misma fecha (como se sugirió en las primeras respuestas) estropearía cosas como new Date(2018, 2, 3) por lo que no era una opción válida para mí.

Tenga en cuenta que también necesita precisar la zona horaria para que funcione completamente en todas partes, por ejemplo, en Travis y produzca el mismo resultado.

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

Los siguientes apéndices de prueba Date para devolver una constante durante el ciclo de vida de la prueba.

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 es solo una variable proxy para satisfacer el mecanografiado.

Necesitaba burlarme de Date.now()

establecer la siguiente línea en la configuración o antes de que las pruebas funcionen para mí:

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

Me gustó el enfoque de @vcarel , pero en mi caso, el constructor Date se usó con argumentos en algunos casos, así que tuve que modificarlo para aceptar otras fechas. También agregué 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')
  })
})

Estoy usando esto, con lo que estoy contento: https://github.com/boblauer/MockDate

He hecho esto

~~~
describe ('Prueba', () => {
const constantDate = nueva fecha ('2018-01-01T12: 00: 00')

beforeAll (() => {
fecha global = la clase extiende la fecha {
constructor () {
súper()
return constantDate
}
}
})
~~~

Solo quisiera agregar un poco a la respuesta de @iwarner .

Probablemente sea menos propenso a errores hacer algo como, ya que devuelve una nueva instancia de fecha cada vez:

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

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

Esto permite que las funciones que mutan los objetos de fecha (por ejemplo, setMinutes) se utilicen sin mutar la fecha constante y, por lo tanto, alterar la fecha que se devuelve de la nueva fecha, por ejemplo

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

Esto es lo que estoy usando después de leer todo lo anterior:

let currentDate;

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

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

@samboylett ¿Esto estropea la fecha global para las pruebas en el futuro? ¿También lo restableció en una función afterAll ?

No afectará las pruebas en diferentes archivos. Para mí, todo en el archivo actual necesitaba la fecha simulada, pero si necesita restablecerlo entre pruebas en el mismo archivo, debe usar un beforeEach y afterEach, y simplemente volver a configurarlo en afterEach:

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

@samboylett gracias! Me las arreglé para que mis pruebas de fecha funcionaran usando tu ejemplo como base.

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

Quizás necesites broma-cita-simulacro .

Proporcionarle una API simple para controlar la marca de tiempo actual para sus casos de prueba.

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

Las soluciones anteriores no cubrieron mi caso de uso. Hice lo siguiente en función de @callemo, que

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 ¿Cuál es tu caso?

@javadoug ¿Cuál es tu caso?

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

@javadoug nueva versión jest-date-mock compatible. https://github.com/hustcc/jest-date-mock/pull/7

'No siempre me burlo del tiempo, pero cuando lo hago, es en broma' - el infame @satub

Necesitaba simular new Date() pero necesitaba que el resto de las funcionalidades de Date funcionaran normalmente. Esta es la solución que funcionó para mí.

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

Recibo un error cada vez que intento asignar a global.

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)

Parece que el problema es que estoy usando JUnit reporter que se ejecuta en el contexto de la prueba y está usando Date que ya está destruido porque la clase anónima está destruida.

Así que sí, la fecha global se estropea cuando usa sugerencias como todas las anteriores. Y solo es un problema cuando usa reporteros no estándar.

Los reporteros no deberían ser ejecutados dentro de la caja de arena. Sin embargo, los reporteros de Jasmine podrían estar enganchados con algunas cosas de jasmime que no son compatibles a propósito

Oh, ¿estás diciendo que este tipo de código no es compatible?

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

El error ocurre aquí:
https://github.com/facebook/jest/blob/f9fd98fd4e38978e96a86f1c8796593cad7ac470/packages/jest-jasmine2/src/jasmine/ReportDispatcher.js#L63 -L72

Correcto, deberías usar
https://jestjs.io/docs/en/configuration#reporters -array-modulename-modulename-options.
Por ejemplo, https://github.com/jest-community/jest-junit

@niieani ,

Una solución para un simulacro de temporizadores "unificados" era usar lolex lugar de jest incorporados, así:

Probé ese ejemplo y resultó en que mis pruebas se bloquearan para siempre (en un CRA que usa [email protected]). ¿Alguien ha tenido éxito usando lolex con Jest?

@kentcdodds asegúrese de no usar temporizadores falsos de broma al mismo tiempo. Si todavía se cuelga, ¿le importaría crear un problema con una reproducción? Lolex definitivamente debería funcionar

Sí, me está funcionando bien en una situación aislada, así que probablemente esté haciendo algo extraño en otra parte. ¡Gracias!

Si solo necesita burlarse de estos casos:

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

Esto es lo que estoy usando después de leer todo lo anterior:

let currentDate;

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

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

Gracias @samboylett

Esto funcionó para mí al burlarme de la nueva fecha ()

@petromoldovan es definitivamente la mejor respuesta.

Agregue una llamada a mockRestore al final de las pruebas para restaurar la fecha original:

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

Se mejoró un poco la solución

    const RealDate = Date

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

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

Puede que me esté inclinando por los molinos de viento aquí, pero vale la pena señalar el viejo adagio: No te burles de lo que no tienes . En su lugar, envuélvalo en una función. Hoy en día es muy conveniente con valores de argumento predeterminados:

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

Ahora, en el código de producción, puede aprovechar el valor predeterminado:

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

Y en el código de prueba puede pasar la fecha explícitamente, burlándose de ella:

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

@yawaramin Ciertamente, hay algunos puntos de vista divergentes al respecto. Hay un campamento que cree que las pruebas deberían funcionar al servicio del código de la aplicación, y hay un punto más allá del cual la cola comienza a menear al perro (Pete Hunt tiene algunas opiniones sólidas sobre esto)

No digo que el método sugerido no sea una opción válida, sino que quizás podría presentarse como una forma apropiada de hacerlo según la situación.

@cheapsteak Creo que la adecuación situacional es el estado predeterminado de las cosas. No está de más recordarle gentilmente a la gente que siempre existe la oportunidad de mejorar la capacidad de prueba y que hacerlo generalmente mejora la capacidad de mantenimiento :-)

¿Hay alguna forma de obtener la hora actual de Jest ya que está enviando temporizadores? Algo como broma, ¿ahora?

Supongamos que tengo temporizadores Y llamadas a Date.now (). Llamo a jest.runAllTimers (). Sería genial si pudiera llamar a jest.spyOn (Date, 'now'). MockImplementation (() => algo ) para que las devoluciones de llamada del temporizador se ejecuten y puedan verificar el tiempo simulado.

Necesitaba burlarme de Date.now()

establecer la siguiente línea en la configuración o antes de que las pruebas funcionen para mí:

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

Es curioso cómo funciona para tanta gente, pero no para mí. mmm.

No sé qué está pasando, pero no importa cómo reasigne Date , Date.now() siempre existe y siempre devuelve un valor válido.

Date.now = null no hace nada.
global.Date.now = null no hace nada.
jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000); no hace nada.
La instalación y el uso de lolex funcionan en tiempos de espera, pero no tienen ningún efecto en Date.now()
MockDate no tiene ningún efecto.

Me estoy perdiendo algo obvio, creo. Quizás otra dependencia esté haciendo algo ... tan confuso.

@mherodev verifique su prueba, ¿

Dentro de un bloque de prueba estoy haciendo algo como ...

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

Pero esa anulación no hace nada. Lo encuentro muy confuso.

Seguí el tutorial de Hugo y terminé haciendo:

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

Entonces, new Date() siempre devolverá new Date('2019-06-19T00:07:19.309Z')

Actualización: Parece que mis simulacros de fecha no funcionaban debido a un error con la forma en que babel se transmite en mi entorno. Algo relacionado con cómo estamos usando @babel/runtime-corejs2

Solución definitiva: broma-fecha-simulacro .

  • Instalar en pc

En su package.json debajo de jest, cree una matriz setupFiles y agregue jest-date-mock a la matriz.

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

Proporcionarle una API simple para controlar la marca de tiempo actual para sus casos de prueba.

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

Pienso: todas las demás soluciones no son sistemáticas ni temporales.

Parece que la transformación de Babel rompe las soluciones anteriores.

Mi solución es agregar un nuevo archivo llamado 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)

En jest.config.js en setupFilesAfterEnv entrada (o setupFiles en la versión de broma anterior), agregue '<rootDir>/jest/setupMockDate.js' .

Ahora, puedes correr

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

Tarde para la fiesta, pero creo que broma tiene toda la funcionalidad que necesitas para esto.

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

Estoy usando vue-moment y jest, y he encontrado que la mejor manera es hacer algo como esto:

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

Usando ES6

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

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

Si está utilizando Date.now()

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

Para cualquier otra persona que tenga errores con esto, tuve algunos problemas porque el objeto Date global tiene propiedades distintas del constructor. Hice lo siguiente:

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;

Quería burlarme de toda la clase Date y el método sugerido por @kristojorg parecía ideal.

No estoy seguro de si esta es la forma adecuada de hacerlo, pero esta solución funciona bien en TypeScript al solucionar el problema de escritura como lo menciona @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());
  });
});

Vale la pena mencionar que esto solo funciona cuando crea una instancia de un nuevo objeto Date y no funcionará para Date.now() . Hay un comentario sobre Date.now .

Dentro de un bloque de prueba estoy haciendo algo como ...

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

Pero esa anulación no hace nada. Lo encuentro muy confuso.

Estoy teniendo el mismo problema: probé un montón de ejemplos de código encontrados en este problema y ninguno funcionó para mí: parece que se ignora el simulacro.

¿Cómo solucionaste tu problema?

También estamos usando Babel, por lo que esto también puede estar relacionado.

Dentro de un bloque de prueba estoy haciendo algo como ...

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

Pero esa anulación no hace nada. Lo encuentro muy confuso.

Estoy teniendo el mismo problema: probé un montón de ejemplos de código encontrados en este problema y ninguno funcionó para mí: parece que se ignora el simulacro.

¿Cómo solucionaste tu problema?

También estamos usando Babel, por lo que esto también puede estar relacionado.

@warpdesign, esta solución parece funcionar para mí con Jest en 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.
  });
});

De este artículo sobre burlarse de la fecha actual en broma .

Solución definitiva: broma-fecha-simulacro .

  • Instalar en pc

En su package.json debajo de jest, cree una matriz setupFiles y agregue jest-date-mock a la matriz.

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

Proporcionarle una API simple para controlar la marca de tiempo actual para sus casos de prueba.

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

Pienso: todas las demás soluciones no son sistemáticas ni temporales.

¡Gracias, funcionó!

Seguí el tutorial de Hugo y terminé haciendo:

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

Entonces, new Date() siempre devolverá new Date('2019-06-19T00:07:19.309Z')

Qué mierda es este hombre. Dices el tutorial de Hugo y Hugo dice el tuyo ... por favor no nos engañes.

Jest 26 admite burlarse de Date usando temporizadores falsos modernos: https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers

Si está atascado intentando simular el constructor Date en TS, intente esto:

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 admite burlarse de Date usando temporizadores falsos modernos: https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers

@SimenB Eso es genial y acabo de actualizar a la v26, pero no puedo entender cómo usamos broma para burlarnos de la fecha. Los documentos de broma solo hablan sobre cómo simular temporizadores para que pueda probar setTimeOut, pero ¿cómo se hace para simular "new Date ()"?

@gregveres Aquí hay un conjunto de pruebas de ejemplo que establece la hora del sistema ( Date métodos) en una fecha fija y maneja el avance de esa hora.

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: Incluido afterEach() por @alexdanilowicz 's comentario below._

Actualización de noviembre de 2020

_Negrita eso ^ a medida que este hilo está envejeciendo y vinculado a una publicación popular de stackoverflow_

@seansullivan ¡Impresionante! Para su información, corríjame si me equivoco, pero creo que sería bueno agregar un afterEach (o afterAll) a sus especificaciones para restablecer la fecha a la realidad. Solo para estar seguros.

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 Perfecto. Sí, me olvidé de incluir la limpieza en mi ejemplo. Actualizaré con afterEach() para asegurar que se mantenga la cordura para cualquiera que encuentre este hilo. ¡Gracias!

¿Fue útil esta página
0 / 5 - 0 calificaciones