Jest: Simulando a hora atual para a data

Criado em 6 dez. 2016  ·  72Comentários  ·  Fonte: facebook/jest

EDITAR por @SimenB 25-05-2020: Veja a resposta atualizada: https://github.com/facebook/jest/issues/2234#issuecomment -633402727

Existe uma maneira de zombar da data atual? Então new Date() ou Date.now() retorna uma hora simulada em vez da hora atual?

Comentários muito úteis

Para qualquer outra pessoa que tenha cometido erros com isso, tive alguns problemas porque o objeto global Date tem propriedades diferentes de construtor. Eu fiz o seguinte:

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 comentários

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

Para qualquer outra pessoa que tenha cometido erros com isso, tive alguns problemas porque o objeto global Date tem propriedades diferentes de construtor. Eu fiz o seguinte:

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;

Se você não precisa afirmar como o construtor está sendo chamado, a extensão pode ser suficiente:

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

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

Isso funciona muito bem para Date.now() .

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

Sempre que você simular um encontro, não se esqueça de colocar de volta a versão real.
Após o comentário de @callemo , você pode usar o seguinte snippet:

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

Indiscutivelmente, a data também deve ser movida para a frente ao executar jest.runTimersToTime() e outras funções de simulação de tempo. Fui mordido pelo mesmo problema, já que parte do meu código dependia do tempo e parte dos tempos limite. Zombar de ambos ao mesmo tempo - ou seja, executar timers simulados E trocar as simulações Date.now e Performance.now não é a melhor experiência.

Uma solução para uma simulação de timers "unificada" era usar lolex vez de jest builtins, como este:

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

Mas seria ótimo ter esse recurso integrado.

Problema antigo, mas mockdate torna isso mais fácil: 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 é uma boa solução, no entanto AFAIK não zomba de performance.now() , que é um relógio útil, apenas para a frente (ou seja, não será atrasado pelo usuário alterando o DateTime de seu sistema).

Na verdade, não funciona no Jest. Jest usa Jasmine v1.5.2-lite, portanto, não tem relógio. Estou usando lolex .

Date.now() é bom o suficiente para a maioria dos aplicativos, permofrmance.now() ainda não está presente no nó —não pode ser usado em SSR, por exemplo—, então não parece ser um grande problema.

Claro, lolex não é integrado com jest.

@drpicox ah, bom saber que não funciona então.
performance.now() está presente no nó, desde v8.5.0 eu acredito. Você pode importar performance do módulo embutido 'perf_hooks' .

Ainda assim, dada a situação atual e o número de votos / comentários que isso está obtendo, gostaria de enviar um ping para

FWIW Eu adoraria integrar lolex - é a única biblioteca que uso onde acho que está faltando uma bateria para Jest

@cpojer De qualquer maneira, podemos reabrir isso. No momento, não há realmente uma maneira de simular uma data E simular a passagem do tempo de uma maneira fácil.

jasmine tem uma classe de relógio onde você pode simular uma data E hora de antecedência, por meio 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);

Adoraria ter uma funcionalidade nativa semelhante. https://github.com/jasmine/jasmine/blob/master/src/core/Clock.js

Tentaremos migrar para o Lolex, que oferece suporte ao seu caso de uso. Veja # 5165

No caso de você precisar simular Data _fora_ de um ambiente de teste. Eu precisava tirar instantâneos de imagens previsíveis da IU, onde uma data é exibida.

Isso funcionou para mim:
https://github.com/schickling/timemachine

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

A sugestão de @omegdadisc é a melhor, eu acho. Zombar de data para sempre retornar a mesma data (como foi sugerido nas primeiras respostas) iria atrapalhar coisas como new Date(2018, 2, 3) então não era uma opção válida para mim.

Observe que você também precisa precisar o fuso horário para que funcione totalmente em qualquer lugar, por exemplo, no Travis e produza o mesmo resultado.

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

O teste a seguir stubs Data para retornar uma constante durante o ciclo de vida do teste.

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 é apenas uma variável proxy para satisfazer o typescript.

Eu precisava zombar de Date.now()

definir a linha abaixo na configuração ou antes dos testes funcionarem para mim:

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

Eu gostei da abordagem de @vcarel , mas no meu caso o construtor Date foi usado com argumentos em alguns casos, então eu precisei modificá-lo para aceitar outras datas. Também adicionei 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')
  })
})

Estou usando isso, e estou feliz com: https://github.com/boblauer/MockDate

eu fiz isso

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

beforeAll (() => {
global.Date = class extends Date {
construtor () {
super()
return constantDate
}
}
})
~~~

Apenas gostaria de acrescentar um pouco à resposta de @iwarner .

Provavelmente, é menos sujeito a erros fazer algo como, pois retorna uma nova instância de data a cada vez:

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

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

Isso permite que funções que alteram objetos de data (por exemplo, setMinutes) sejam usadas sem alterar constantDate e, assim, alterar a data que é retornada de nova Data, por exemplo

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

Isso é o que estou usando depois de ler tudo acima:

let currentDate;

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

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

@samboylett Isso atrapalha a data global para testes no futuro? Você também o redefiniu em uma função afterAll ?

Isso não afetará os testes em arquivos diferentes. Para mim, tudo no arquivo atual precisava da data simulada, mas se você precisar redefini-la entre os testes no mesmo arquivo, você deve usar beforeEach e afterEach, e apenas defini-la novamente no afterEach:

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

@samboylett obrigado! Consegui fazer meus testes de data funcionarem usando seu exemplo 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;
  });
});

Talvez você precise jest-date-mock .

Fornece API simples para controlar o carimbo de data / hora atual para seus casos de teste.

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

As soluções acima não cobriram meu caso de uso. Fiz o seguinte com base em @callemo, que não tinha suporte para instanceof e definição de datas específicas.

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 Qual é o seu caso?

@javadoug Qual é o seu caso?

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

@javadoug nova versão jest-date-mock suportada. https://github.com/hustcc/jest-date-mock/pull/7

'Eu nem sempre brinco com o tempo, mas quando o faço, é de brincadeira` - o infame @satub

Eu precisava simular new Date() mas precisava que o restante das funcionalidades de Date funcionassem normalmente. Esta é a solução que funcionou para mim.

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

Estou recebendo um erro sempre que tento atribuir a 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)

Parece que o problema é que estou usando o repórter JUnit que é executado no contexto do teste e está usando a Data que já foi destruída porque a classe anônima foi destruída.

Então, sim, o Date global fica confuso quando você usa sugestões como todas as anteriores. E isso só é um problema quando você usa repórteres fora do padrão.

Os repórteres não devem ser executados dentro da sandbox. Os repórteres do Jasmine podem estar se conectando a algumas coisas de jasmime que não são propositalmente suportadas, embora

Ah, então você está dizendo que esse tipo de código não é compatível?

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

O erro acontece aqui:
https://github.com/facebook/jest/blob/f9fd98fd4e38978e96a86f1c8796593cad7ac470/packages/jest-jasmine2/src/jasmine/ReportDispatcher.js#L63 -L72

Correto, você deve usar
https://jestjs.io/docs/en/configuration#reporters -array-modulename-modulename-options.
Por exemplo, https://github.com/jest-community/jest-junit

@niieani ,

Uma solução para uma simulação de timers "unificada" era usar lolex vez de jest builtins, como este:

Eu tentei esse exemplo e resultou em meus testes travando para sempre (em um CRA que está usando [email protected]). Alguém teve sucesso usando lolex com Jest?

@kentcdodds certifique-se de não usar timers falsos jest ao mesmo tempo. Se ainda travar, importa criar um problema com uma reprodução? Lolex definitivamente deve funcionar

Sim, está funcionando bem para mim em uma situação isolada, então provavelmente estou fazendo algo estranho em outro lugar. Obrigado!

Se você só precisa simular esses 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;
  }
}

Isso é o que estou usando depois de ler tudo acima:

let currentDate;

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

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

Obrigado @samboylett

Isso funcionou para mim ao zombar de new Date ()

@petromoldovan é definitivamente a melhor resposta.

Adicione uma chamada para mockRestore no final dos testes para restaurar a data original:

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

Melhorou um pouco a solução @vcarel , caso você queira que o mock retorne uma instância de Date em vez de uma da nova classe:

    const RealDate = Date

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

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

Posso estar atacando moinhos de vento aqui, mas vale a pena ressaltar o velho ditado: Não zombe do que você não possui . Em vez disso, envolva-o em uma função. Hoje em dia é muito conveniente com valores de argumento padrão:

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

Agora, no código de produção, você pode aproveitar o padrão:

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

E no código de teste você pode passar a data explicitamente, zombando dela:

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

@yawaramin Existem certamente alguns pontos de vista divergentes sobre isso. Há um grupo que acredita que os testes devem viver a serviço do código do aplicativo, e há um ponto após o qual o rabo começa a abanar o cachorro (Pete Hunt tem algumas opiniões fortes sobre isso)

Não estou dizendo que o seu método sugerido não seja uma opção válida, mas talvez possa ser apresentado como uma maneira apropriada para a situação

@cheapsteak Eu acho que a adequação situacional é o estado de coisas padrão. Não custa lembrar gentilmente às pessoas que sempre há uma oportunidade para melhorar a testabilidade e que isso geralmente melhora a sustentabilidade :-)

Existe uma maneira de obter a hora atual de jest, uma vez que está despachando cronômetros? Algo como jest.now?

Suponha que eu tenha temporizadores E chamadas para Date.now (). Eu chamo jest.runAllTimers (). Seria legal se eu pudesse chamar jest.spyOn (Date, 'now'). MockImplementation (() => something ) para que os callbacks do cronômetro sejam executados e possam verificar o tempo simulado.

Eu precisava zombar de Date.now()

definir a linha abaixo na configuração ou antes dos testes funcionarem para mim:

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

engraçado como funciona para tantas pessoas, mas não para mim. Hmm.

Eu não sei o que está acontecendo, mas não importa como eu reatribuo Date , Date.now() sempre existe e sempre retorna um valor válido.

Date.now = null não faz nada.
global.Date.now = null não faz nada.
jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000); não faz nada.
Instalar e usar lolex funciona em tempos limite, mas não tem efeito em Date.now()
MockDate não tem efeito.

Estou perdendo algo óbvio, eu acho. Talvez outra dependência esteja fazendo algo ... tão confuso.

@mherodev verifique seu teste, você

Dentro de um bloco de teste, estou fazendo algo como ...

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

Mas essa substituição não faz nada. Acho muito confuso.

Segui o tutorial do Hugo e acabei fazendo:

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

Portanto, new Date() sempre retornará new Date('2019-06-19T00:07:19.309Z')

Atualização: Parece que minhas simulações de Date não estavam funcionando por causa de um bug em como o babel está transpilando no meu ambiente. Algo relacionado a como estamos usando @babel/runtime-corejs2

Solução final: jest-date-mock .

  • instalar

Em seu package.json sob a brincadeira, crie um array setupFiles e adicione jest-date-mock ao array.

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

Fornece API simples para controlar o carimbo de data / hora atual para seus casos de teste.

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

Eu penso: Todas as outras soluções não são sistemáticas ou temporárias.

parece que a transformação babel quebra as soluções alternativas anteriores.

Minha solução é adicionar um novo arquivo chamado 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)

Em jest.config.js na entrada setupFilesAfterEnv (ou setupFiles na versão de brincadeira antiga), adicione '<rootDir>/jest/setupMockDate.js' .

Agora, você é capaz de executar

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

Atrasado para a festa, mas acho que o jest tem todas as funcionalidades de que você precisa para isso.

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

Estou usando o momento vue e o gracejo, e descobri que a melhor maneira é fazer algo assim:

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

Se você estiver usando Date.now()

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

Para qualquer outra pessoa que tenha cometido erros com isso, tive alguns problemas porque o objeto global Date tem propriedades diferentes de construtor. Eu fiz o seguinte:

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;

Eu queria zombar de toda a classe Date e o método sugerido por @kristojorg parecia ideal.

Não tenho certeza se esta é a maneira apropriada de fazer isso, mas essa solução funciona bem no TypeScript corrigindo o problema de digitação mencionado por @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());
  });
});

É importante mencionar que isso só funciona quando você instancia um novo objeto Date e não funciona para Date.now() . Há um comentário sobre Date.now .

Dentro de um bloco de teste, estou fazendo algo como ...

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

Mas essa substituição não faz nada. Acho muito confuso.

Estou tendo o mesmo problema: testei um monte de exemplos de código encontrados neste problema e nenhum funcionou para mim: o mock parece ser ignorado.

Como você resolveu seu problema?

Também estamos usando o Babel, então isso também pode estar relacionado.

Dentro de um bloco de teste, estou fazendo algo como ...

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

Mas essa substituição não faz nada. Acho muito confuso.

Estou tendo o mesmo problema: testei um monte de exemplos de código encontrados neste problema e nenhum funcionou para mim: o mock parece ser ignorado.

Como você resolveu seu problema?

Também estamos usando o Babel, então isso também pode estar relacionado.

@warpdesign esta solução parece funcionar para mim com Jest no 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.
  });
});

A partir deste artigo sobre zombar da data atual em Jest .

Solução final: jest-date-mock .

  • instalar

Em seu package.json sob a brincadeira, crie um array setupFiles e adicione jest-date-mock ao array.

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

Fornece API simples para controlar o carimbo de data / hora atual para seus casos de teste.

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

Eu penso: Todas as outras soluções não são sistemáticas ou temporárias.

Obrigado funcionou !!

Segui o tutorial do Hugo e acabei fazendo:

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

Portanto, new Date() sempre retornará new Date('2019-06-19T00:07:19.309Z')

Que merda é esse homem. Você diz o tutorial do Hugo e o Hugo diz o seu ... por favor, não nos engane.

Jest 26 suporta simulação de Date usando timers falsos modernos: https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers

Se você está tentando simular o construtor Date no TS, tente o seguinte:

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 suporta simulação de Date usando timers falsos modernos: https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers

@SimenB Isso é ótimo e acabei de atualizar para a v26, mas não consigo descobrir como usamos o gracejo para simular a data. Os documentos engraçados falam apenas sobre como simular timers para que você possa testar setTimeOut, mas como fazer isso para simular "new Date ()"?

@gregveres Aqui está um exemplo de suíte de teste que define a hora do sistema (métodos Date ) para uma data fixa e controla o avanço dessa 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: Incluído afterEach() per @alexdanilowicz 's comentário below._

Atualização de novembro de 2020

_Bolding that ^ como este thread está envelhecendo e vinculado a um post stackoverflow popular_

@seansullivan Incrível! Para sua informação, corrija-me se eu estiver errado, mas acho que seria bom adicionar um afterEach (ou afterAll) às suas especificações para redefinir a data de volta à realidade. Apenas para estar seguro.

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 Perfect. Sim, esqueci de incluir a limpeza em meu exemplo. Vou atualizar com afterEach() para garantir que a sanidade seja mantida para qualquer pessoa que encontrar este tópico. Obrigado!

Esta página foi útil?
0 / 5 - 0 avaliações