Jest: Como simular uma função de módulo específica?

Criado em 25 abr. 2016  ·  116Comentários  ·  Fonte: facebook/jest

Estou lutando com algo que acho que deveria ser fácil e óbvio, mas por alguma razão não consigo descobrir.

Eu tenho um módulo. Ele exporta várias funções. Aqui está myModule.js :

export function foo() {...}
export function bar() {...}
export function baz() {...}

Eu desbloqueio o módulo para teste.

jest.unmock('./myModule.js');

No entanto, preciso simular foo , porque ele faz chamadas ajax para meu back-end. Eu quero que todas as funções neste arquivo permaneçam desbloqueadas, espere foo , que eu quero zombar. E as funções bar e baz fazem chamadas internamente para foo , então, quando meu teste chamar bar() , o bar desmocked chamará o zombou de foo .

Ele aparece na documentação jest que as chamadas para unmock e mock operam em todo o módulo. Como posso simular uma função específica? Dividir arbitrariamente meu código em módulos separados para que eles possam ser testados corretamente é ridículo.

Comentários muito úteis

Você pode fazer:

jest.unmock('./myModule.js');

const myModule = require('myModule');
myModule.foo = jest.fn();

Consulte http://facebook.github.io/jest/docs/api.html#mock -functions

Todos 116 comentários

Após uma análise mais profunda, parece que o jest-mock gera um AST para todo o módulo e, em seguida, usa esse AST para criar um módulo simulado que está em conformidade com as exportações do original: https://github.com/facebook/jest/tree/master/packages / jest-mock

Outras estruturas de teste, como o mock do Python (https://docs.python.org/3/library/unittest.mock-examples.html), permitem que você simule funções específicas. Este é um conceito de teste fundamental.

Eu recomendo fortemente a capacidade de simular uma parte de um módulo. Acho que jest-mock deve ser alterado para ignorar condicionalmente as exportações de mocking e fazer referência à implementação original.

Você pode fazer:

jest.unmock('./myModule.js');

const myModule = require('myModule');
myModule.foo = jest.fn();

Consulte http://facebook.github.io/jest/docs/api.html#mock -functions

Acho que você tem um mal-entendido fundamental sobre como require funciona. Quando você chama require() , você não obtém uma instância do módulo. Você obtém um objeto com referências às funções do módulo. Se você sobrescrever um valor no módulo necessário, sua própria referência é sobrescrita, _mas a implementação mantém as referências originais_.

No seu exemplo, se você chamar myModule.foo() , sim, você chamará a versão simulada. Mas se você chamar myModule.bar() , que internamente chama foo() , a foo que faz referência _não é sua versão sobrescrita_. Se você não acredita em mim, você pode testá-lo.

Portanto, o exemplo que você descreveu é inadequado para o problema que tenho. Você sabe de algo que eu não?

@cpojer

Eu acredito que entendo isso muito bem. A forma como o babel compila os módulos não torna isso mais fácil de entender e eu entendo sua confusão. Não sei exatamente como isso se comportaria em um ambiente ES2015 real com módulos, principalmente porque esse ambiente não existe no momento (exceto talvez as versões mais recentes do Chrome Canary, que ainda não tentei). Para explicar o que acontece, temos que olhar para a saída compilada do seu código babel. Vai parecer algo assim:

var foo = function foo() {};
var bar = function bar() { foo(); };

exports.foo = foo;
exports.bar = bar;

Nesse caso, é realmente correto que você não pode simular foo e peço desculpas por não ter lido seu problema inicial corretamente, no entanto, ele não fez nenhuma suposição sobre como foo foi chamado, então presumi que era exports.foo() . Apoiar o acima simulando uma função após exigir um módulo é impossível em JavaScript - não há (quase) nenhuma maneira de recuperar a ligação a que foo se refere e modificá-la.

No entanto, se você alterar seu código para este:

var foo = function foo() {};
var bar = function bar() { exports.foo(); };

exports.foo = foo;
exports.bar = bar;

e então em seu arquivo de teste você faz:

var module = require('../module');
module.foo = jest.fn();
module.bar();

funcionará conforme o esperado. Isso é o que fazemos no Facebook, onde não usamos o ES2015.

Embora os módulos ES2015 possam ter ligações imutáveis ​​para o que exportam, o código compilado subjacente para o qual o babel compila agora não impõe tais restrições. Não vejo nenhuma maneira de oferecer suporte exatamente ao que você está pedindo em um ambiente de módulo ES2015 estrito com módulos com suporte nativo. A maneira jest-mock funciona é que ele executa o código do módulo isoladamente e, em seguida, recupera os metadados de um módulo e cria funções simuladas. Novamente, neste caso não haverá nenhuma maneira de modificar a ligação local de foo . Se você tiver idéias sobre como implementar isso de forma eficaz, contribua aqui ou com uma solicitação de pull. Gostaria de lembrar que temos um código de conduta para este projeto que você pode ler aqui: https://code.facebook.com/pages/876921332402685/open-source-code-of-conduct

A solução certa em seu exemplo não é simular foo, mas simular a API de nível superior que foo está chamando (como XMLHttpRequest ou a abstração que você usa).

@cpojer Obrigado por sua explicação detalhada. Sinto se ofendi você com minha linguagem, sou muito eficiente com minha redação de engenharia e quero transmitir meu ponto de vista o mais rápido possível. Para colocar as coisas em perspectiva, passei 5 horas tentando entender esse problema e escrevi 2 comentários detalhados, então você fechou com uma breve mensagem que perdeu completamente o objetivo de ambas as minhas declarações. É por isso que minha próxima mensagem disse que você teve um "mal-entendido fundamental", porque 1) você não entendeu o que eu estava defendendo ou 2) você não entendeu require() , que felizmente era a opção 1.

Vou refletir sobre uma possível solução para o meu problema, para contorná-lo, por enquanto, eu simulei uma API de nível inferior, mas definitivamente deve haver uma maneira de simular a função diretamente, pois isso seria bastante útil.

Eu concordo que seria útil ser capaz de fazer isso, mas não há uma boa maneira em JS de fazer isso sem (provavelmente lenta) uma análise estática inicial :(

@cpojer : Não tenho certeza se pular aqui 5 meses depois é o caminho a percorrer, mas não consegui encontrar nenhuma outra conversa sobre isso.

Pegando sua sugestão acima, fiz isso para simular uma função de outra no mesmo módulo:

jest.unmock('./someModule.js');
import someModule from './someModule.js';

it('function1 calls function 2', () => {
    someModule.function2 = jest.fn();

    someModule.function1(...);

    expect(someModule.function2).toHaveBeenCalledWith(...);
});

Isso funciona para o único teste, mas não encontrei uma maneira de fazer isso de forma isolada para apenas um bloco it(...); . Como escrito acima, isso afeta todos os testes, o que torna difícil testar o real function2 em outro teste. Alguma dica?

Você pode chamar .mockClear na função em beforeEach ou chamar jest.clearAllMocks() se estiver usando Jest 16.

Ei @cpojer! Estou usando o Jest 16. Nem jest.clearAllMocks() ou someModule.function2.mockClear() funcionam para mim. Eles só funcionam quando o mock é um módulo inteiro, não uma função de um módulo importado. No meu projeto, a função permanece simulada em testes subsequentes. Se isso não for esperado, verei se posso replicar em um pequeno projeto de amostra e criar um novo problema. Boa ideia?

@cpojer -

A solução certa em seu exemplo não é simular foo, mas simular a API de nível superior que foo está chamando (como XMLHttpRequest ou a abstração que você usa).

Sou novo no Jest e estou lutando com um problema semelhante. Estou usando axios , que por baixo do capô usa XMLHttpRequest , e não quero zombar de axios , mas sim de XMLHttpRequest reais. Parece que eu teria que implementar os seus métodos por mim, algo como este . É este o caminho certo?

Obrigado!

sim, algo assim deve colocá-lo no caminho certo! :) Use jest.fn como uma API melhor, embora: D

@cpojer sobre seu comentário aqui: https://github.com/facebook/jest/issues/936#issuecomment -214939935

Como você faria isso com o ES2015?

// myModyle.js
export foo = (string) => "foo-" + string
export bar = (string2) => foo(string2)

// myModule.test.js
var module = require('./myModule');

// how do I mock foo here so this test passes?
expect(bar("hello")).toEqual("test-hello")

Para quem se depara com isso em busca de uma solução, o seguinte parece estar funcionando para mim ao exportar muitas const / funções em um arquivo e importá-las em um arquivo que estou testando

`` javascript function mockFunctions() { const original = require.requireActual('../myModule'); return { ...original, //Pass down all the exported objects test: jest.fn(() => {console.log('I didnt call the original')}), someFnIWantToCurry: {console.log('I will curry the original') return jest.fn((...args) => original.someFnIWantToCurry(...args)}), } jest.mock('../myModule', () => mockFunctions()); const storage = require.requireMock('../myModule');

@ainesophaur , não tenho certeza do que estou fazendo de errado aqui. Mas parece que não funciona
Estou atualmente no jest 18.1 (e criar-reagir-app 0.9.4)

...<codes from comment above>..

// Let's say the original myModule has a function doSmth() that calls test()
storage.doSmth();
expect(storage.test).toHaveBeenCalled();

O teste falhará com:

expect(jest.fn()).toHaveBeenCalled()
Expected mock function to have been called.

@huyph, você teria que simular seu método doSmth e seu método de teste para que o jest testasse se ele foi chamado. Se você puder fornecer o snippet do seu código de simulação, posso verificar o que está errado

@ainesophaur ... uhm. Achei que seus códigos acima são para zombar do método test() ? esta parte: test: jest.fn(() => {console.log('I didnt call the original')}),

@ainesophaur Eu tentei seu código também. Mas não funcionou para mim. Ele nunca executa a função simulada. Portanto, a expectativa nunca é atendida.

Acho que isso é inerente à forma como o require funciona como afirmado acima ... Gostaria que houvesse uma solução para isso.

@cpojer Há algo novo em relação aos módulos de mocking parcial?

@rantonmattei & @huyph Eu teria que ver um trecho de suas definições de simulação e o teste que você está executando. Você deve definir seu mock antes que o arquivo de implementação real seja necessário / importado. Já faz um tempo que não trabalho com o JEST, mas me lembro de que finalmente consegui simular tudo o que precisava, seja uma biblioteca node_modules ou um arquivo em meu aplicativo. Estou com pouco tempo no caixa eletrônico, mas aqui estão alguns dos testes de um projeto em que trabalhei usando o Jest.

Zombar de um arquivo de uma dependência

A definição real da função neste exemplo é feita por react-native. Estou zombando do arquivo "react-nativos / Bibliotecas / Utilitários / despedirKeyboard.js"

Este é um arquivo simulado em __mocks__/react-native/Libraries/Utilities/dismissKeyboard.js

function storeMockFunctions() {
  return jest.fn().mockImplementation(() => true);
}
jest.mock('react-native/Libraries/Utilities/dismissKeyboard', () => storeMockFunctions(), { virtual: true });
const dismissKeyboard = require('react-native/Libraries/Utilities/dismissKeyboard');
exports = module.exports = storeMockFunctions;

Não consigo encontrar o arquivo de teste que usei para o acima, mas era algo como exigir o módulo, jest iria encontrá-lo em __mocks__ e então eu poderia fazer algo como

expect(dismissKeyboard.mock.calls).toHaveLength(1);

Zombar de um arquivo que você controla
Definição de função real

export const setMerchantStores = (stores) => storage.set('stores', stores);

Arquivo de teste com simulação

const { storeListEpic, offerListEpic } = require('../merchant');

function storeMockFunctions() {
  const original = require.requireActual('../../common/Storage');
  return {
    ...original,
    setMerchantStores: jest.fn((...args) => original.setMerchantStores(...args)),
    setMerchantOffers: jest.fn((...args) => original.setMerchantOffers(...args)),
  };
}
jest.mock('../../common/Storage', () => storeMockFunctions());
import * as storage from '../../common/Storage';

afterEach(() => {
  storage.setMerchantStores.mockClear();
});

it('handle storeListEpic type STORE_LIST_REQUEST -> STORE_LIST_SUCCESS', async () => {
  const scope = nock('http://url')
  .get('/api/merchant/me/stores')
  .reply(200, storeData);
  const result = await storeListEpic(ActionsObservable.of(listStores())).toPromise();
  expect(storage.setMerchantStores.mock.calls).toHaveLength(1);
  expect(await storage.getMerchantStores()).toEqual({ ids: storesApiData.result, list: storesApiData.entities.store});
});

obrigado por compartilhar @ainesophaur. Ainda não consigo fazer funcionar com o gracejo 18.1. Aqui estão meus códigos:

it('should save session correctly', () => {

  function mockFunctions() {
    const original = require.requireActual('./session');
    return {
      ...original,
      restartCheckExpiryDateTimeout: jest.fn((() => {
        console.log('I didn\'t call the original');
      })),
    }
  }

  jest.mock('./session', () => mockFunctions());
  const mockSession = require('./session');

  // NOTE: saveSession() will call the original restartCheckExpiryDateTimeout() instead of my
  // mock one. However, mockSession.restartCheckExpiryDateTimeout() does call the mock one
  mockSession.saveSession('', getTomorrowDate(), 'AUTH');

  // mockSession.restartCheckExpiryDateTimeout(); // does print out "I didn't call the original"

  expect(mockSession.restartCheckExpiryDateTimeout).toHaveBeenCalled();
});

Em session.js

export function saveSession(sessionId, sessionExpiryDate, authToken) {
  ....
  restartCheckExpiryDateTimeout(sessionExpiryDate);
  ...
}
....

export function restartCheckExpiryDateTimeout(...) {
....
}

Não consigo encontrar uma maneira de resolver esse problema. Posso reabrir isso, por favor? @cpojer

@huyph a maneira como você está fazendo a exportação saveSession vai chamar o restartCheckExpiryDateTimeout definido localmente em vez de passar pelo módulo e chamar module.restartCheckExpiryDateTimeout - portanto, seu simulado module.restartCheckExpiryDateTimeout não será detectado por saveSession porque saveSession está chamando a função real definida restartCheckExpiryDateTimeout .

Eu atribuiria saveSession a uma const e, em seguida, faria saveSession.restartCheckExpiryDateTimeout = () => {...logic} . .então de saveSession.saveSession , chame saveSession.restartCheckExpiryDateTimeout vez de apenas restartCheckExpiryDateTimeout . Exporte sua nova const em vez da função real saveSession que então define seus métodos. Então, quando você chamar seu someVar.saveSession() ele chamará internamente saveSession.restartCheckExpiryDateTimeout() que agora é ridicularizado.

Eu deveria ter adicionado que restartCheckExpiryDateTimeout() é uma função exportada. Não é uma função definida localmente em saveSession() ... (Atualizado meu comentário acima). Nesse caso, acho que module.saveSession() deve chamar o module.restartCheckExpiryDateTimeout() correto, que é ridicularizado.

Mas vou dar uma chance ao que você sugere acima. Movendo saveSession() e restartCheckExpiryDateTimeout() para outro const. Obrigado

Eu entendo que não está definido no escopo de saveSession. saveSession é
chamando o método irmão no escopo pai. Eu encontrei isso muitas vezes
e o que eu sugeri funcionou para isso

Em 8 de maio de 2017, às 20h38, "Huy Pham" [email protected] escreveu:

Eu deveria ter adicionado que restartCheckExpiryDateTimeout () é um exportado
função. Não é uma função definida localmente em saveSession () ...

Vou dar uma chance ao que você sugere acima. Obrigado

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/facebook/jest/issues/936#issuecomment-300029003 ou mudo
o segmento
https://github.com/notifications/unsubscribe-auth/AEeBdsmpOOmzvcUHB3D_-Z7MChIzt10Pks5r37WYgaJpZM4IPGAH
.

Acabei de tentar ... descobri que:

Isso NÃO funciona: (ou seja, o restartCheckExpiryDateTimeout () original ainda é chamado)

export session = {
   saveSession: () => {
      session.restartCheckExpiryDateTimeout();
   },
   restartCheckExpiryDateTimeout: () => {},
}

Isso funciona: (ou seja, o mock restartCheckExpiryDateTimeout () é chamado em seu lugar). A diferença é o uso de function() vez da forma de seta e o uso de this. vez de session.

export session = {
   saveSession: function() {
      this.restartCheckExpiryDateTimeout();
   },
   restartCheckExpiryDateTimeout: () => {},
}

Pode ser um problema transpilar esses códigos ....

Tente exportá-los como um objeto de classe em vez de pojo. Eu acredito no
o transpiler levanta as variáveis ​​de maneira diferente. Nós vamos começar a trabalhar
teste, eu prometo .. Já se passou cerca de meio ano desde que eu estava no projeto
isso costumava ser uma brincadeira, mas eu me lembro bem desse problema e me lembro eventualmente
encontrando uma solução.

Em 9 de maio de 2017, às 12h53, "Huy Pham" [email protected] escreveu:

Acabei de tentar ... descobri que:

Isso NÃO funciona: (ou seja, o restartCheckExpiryDateTimeout () original é
ainda é chamado)

sessão de exportação = {
saveSession: () => {
session.restartCheckExpiryDateTimeout ();
},
restartCheckExpiryDateTimeout: () => {},
}

Isso NÃO funciona: (ou seja, o restartCheckExpiryDateTimeout () original é
ainda é chamado)

sessão de exportação = {
saveSession: function () {
this.restartCheckExpiryDateTimeout ();
},
restartCheckExpiryDateTimeout: () => {},
}

Pode ser um problema transpilar esses códigos ....

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/facebook/jest/issues/936#issuecomment-300060975 ou mudo
o segmento
https://github.com/notifications/unsubscribe-auth/AEeBdrRQExycPYiGtvm7qYi5G87w6b6Oks5r3_FlgaJpZM4IPGAH
.

@sorahn mesmo problema. es6 + babel , Como zombar?
@cpojer Isso significa que es6 + babel , export const function xx() {} , exportar várias funções, Jest não tem como simular uma função em um módulo (arquivo) chamado por outra função no mesmo módulo (arquivo)? Eu testo, parece que estou certo. Apenas para o padrão commonjs , Jest pode simular a função com sucesso, como o seu exemplo.

@ainesophaur não está funcionando.

módulo:

export const getMessage = (num: number): string => {
  return `Her name is ${genName(num)}`;
};

export function genName(num: number): string {
  return 'novaline';
}

teste:

function mockFunctions() {
  const original = require.requireActual('../moduleA');
  return {
    ...original,
    genName: jest.fn(() => 'emilie')
  }
}
jest.mock('../moduleA', () => mockFunctions());
const moduleA = require('../moduleA');

describe('mock function', () => {

  it('t-0', () => {
    expect(jest.isMockFunction(moduleA.genName)).toBeTruthy();
  })

  it('t-1', () => {

    expect(moduleA.genName(1)).toBe('emilie');
    expect(moduleA.genName).toHaveBeenCalled();
    expect(moduleA.genName.mock.calls.length).toBe(1);
    expect(moduleA.getMessage(1)).toBe('Her name is emilie');
    expect(moduleA.genName.mock.calls.length).toBe(2);

  });

});

resultado do teste:

FAIL  jest-examples/__test__/mock-function-0.spec.ts
  ● mock function › t-1

    expect(received).toBe(expected)

    Expected value to be (using ===):
      "Her name is emilie"
    Received:
      "Her name is novaline"

      at Object.it (jest-examples/__test__/mock-function-0.spec.ts:22:35)
      at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)

  mock function
    ✓ t-0 (1ms)
    ✕ t-1 (22ms)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        0.215s, estimated 1s

Veja meus últimos comentários acima. Especificamente o último. Sua
métodos exportados estão chamando o método irmão com escopo local versus o
método exportado real (que é onde está o seu mock)

Em 31 de maio de 2017, às 2h, "novaline" [email protected] escreveu:

@ainesophaur https://github.com/ainesophaur não está funcionando.

módulo:

export const getMessage = (num: número): string => {
return Her name is ${genName(num)} ;
};
função de exportação genName (num: número): string {
return 'novaline';
}

teste:

function mockFunctions () {
const original = require.requireActual ('../ moduleA');
Retorna {
...original,
genName: jest.fn (() => 'emilie')
}
} jest.mock ('../ moduleA', () => mockFunctions ()); const moduleA = require ('../ moduleA');
descrever ('função simulada', () => {

it ('t-0', () => {
expect (jest.isMockFunction (moduleA.genName)). toBeTruthy ();
})

it ('t-1', () => {

expect(moduleA.genName(1)).toBe('emilie');
expect(moduleA.genName).toHaveBeenCalled();
expect(moduleA.genName.mock.calls.length).toBe(1);
expect(moduleA.getMessage(1)).toBe('Her name is emilie');
expect(moduleA.genName.mock.calls.length).toBe(2);

});

});

resultado do teste:

FAIL jest-examples / __ test __ / mock-function-0.spec.ts
● função simulada ›t-1

expect(received).toBe(expected)

Expected value to be (using ===):
  "Her name is emilie"
Received:
  "Her name is novaline"

  at Object.it (jest-examples/__test__/mock-function-0.spec.ts:22:35)
  at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)

função simulada
✓ t-0 (1ms)
✕ t-1 (22ms)

Suítes de teste: 1 falha, 1 total
Testes: 1 reprovado, 1 aprovado, 2 no total
Instantâneos: 0 no total
Tempo: 0,215 s, estimado 1 s

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/facebook/jest/issues/936#issuecomment-305091749 ou mudo
o segmento
https://github.com/notifications/unsubscribe-auth/AEeBdv6SafXlTtKo3DNeFWhbL6gV9l0Gks5r_QHjgaJpZM4IPGAH
.

@ainesophaur : Eu tentei export class Session { } . E não funciona para mim.

A única abordagem que funciona para mim está no meu comentário acima: onde a sintaxe function é usada em vez da seta () => . Aqui:

export const session = {
   saveSession: function() {
      this.restartCheckExpiryDateTimeout();
   },
   restartCheckExpiryDateTimeout: () => {},
}

Este é o Jest 20.0.3

O que faço é criar um invólucro const para as funções e, em seguida, exportar esse invólucro (como exportar const fns). Então, dentro do módulo, use fns.functionName e, então, posso jest.fn () a função fns.functionName

Quando escrevemos uma função simulada de um módulo definido pelo usuário que é escrito em texto digitado e quando chamamos a função simulada, a função original é coberta no relatório de cobertura porque estamos chamando a versão simulada da função.

Tenho 2 funções que foram importadas originalmente nos testes como
import { getCurrentDate, getStartEndDatesForTimeFrame } from ./../_helpers/date';
Como você pode ver, getStartEndDatesForTimeFrame depende de getCurrentDate . Com a configuração a seguir, o teste getCurrentDate funciona bem e usa a versão simulada. Por outro lado, por algum motivo, o teste getStartEndDatesForTimeFrame não usa o simulado getCurrentDate mas a implementação original, então meu teste falha. Eu tentei muitas configurações diferentes (como Date.now = jest.fn(() => "2017-11-16T20:33:09.071Z"); mas não consegui fazer funcionar. Alguma ideia?

export const getCurrentDate = () => new Date();
export const getStartEndDatesForTimeFrame = (timeFrame) => {
  ...
  const todayDate = getCurrentDate();
  ...
  switch (timeframe) {
    case TimeFrames.TODAY:
      console.log(todayDate); // this always prints the real value in tests instead of the mocked one
      start = new Date(todayDate.getFullYear(), todayDate.getMonth(), todayDate.getDate(), 0, 0, 0);
      end = new Date(
        todayDate.getFullYear(),
        todayDate.getMonth(),
        todayDate.getDate(), 23, 59, 59,
      );
      break;
  ...
  return { start: start.toISOString(), end: end.toISOString() }
};
function mockFunctions() {
  const original = require.requireActual('../../_helpers/date');
  return {
    ...original,
    getCurrentDate: jest.fn(() => '2017-11-16T20:33:09.071Z'),
  }
}
jest.mock('../../_helpers/date', () => mockFunctions());
const dateModule = require.requireMock('../../_helpers/date');

describe('getCurrentDate', () => {
  it('returns the mocked date', () => {
    expect(dateModule.getCurrentDate()).
      toBe('2017-11-16T20:33:09.071Z'); // this works well and returns the mocked value
  });
});

describe('getStartEndDatesForTimeFrame', () => {
  it('returns the start and end dates for today', () => {
    expect(dateModule.getStartEndDatesForTimeFrame('today')).toEqual(
      { 'start': '2017-11-15T23:00:00.000Z', 'end': '2017-11-16T22:59:59.000Z' }
    ); // this one uses the original getCurrentDate instead of the mocked one :(
  });
});

Portanto, o getStartEndDatesForTimeFrame falha porque usa a hora atual e não a hora simulada.

Consegui fazer funcionar seguindo uma sugestão de @ainesophaur - exportando todas as funções dentro de um objeto e chamando os métodos desses objetos exportados em vez de métodos irmãos com escopo local:

// imageModel.js
const model = {
  checkIfImageExists,
  getImageUrl,
  generateImagePreview
}
export default model

async function checkIfImageExists(...) {}
async function getImageUrl() {}
async function generateImagePreview() {
  // I am calling it as `model` object's method here, not as a locally scoped function
  return model.getImageUrl(...)
}

// imageModel.test.js
import imageModel from './imageModel'

test('should mock getImageUrl called within the same file', async () => {
  imageModel.getImageUrl = jest.fn().mockReturnValueOnce(Promise.resolve())

  await imageModel.generateImagePreview()

  expect(imageModel.getImageUrl).toBeCalled()
})

@miluoshi Essa foi a única maneira de fazer isso também. Existe alguma perda de desempenho ou algo parecido quando usamos este método? Parece "errado" alterar o código para que você possa testá-lo.

Eu realmente gostaria de uma maneira de escrever:
jest.mock('src/folder/file.func, () => {return 'whatever i want'})

peça-chave aqui sendo o .func

@miluoshi @Rdlenke se o seu código consistir em exportações nomeadas, você também pode import * as model e então sobrescrever model.generateImagePreview = jest.fn(() => Promise.resolve);

Como você testaria isso com o sinon? Como mencionado antes (consulte https://github.com/facebook/jest/issues/936#issuecomment-214939935), a maneira como o ESM funciona torna impossível zombar de func2 dentro de func1 , então Eu não o chamaria necessariamente de básico.

Talvez um mod babel pudesse ser escrito para ler qualquer função "testImport"
e reescreve o código para exportar as funções no módulo antes do
teste em execução?

Na segunda-feira, 18 de dezembro de 2017 às 17h, Jim Moody [email protected] escreveu:

Você está certo @SimenB https://github.com/simenb , eu tinha mudado algo
no meu teste entre a mudança para o Sinon, que pode parecer que passou.
Quando reverti isso, ainda não estava funcionando. Eu acho que não é um problema
que foi resolvido.

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/facebook/jest/issues/936#issuecomment-352488400 ou mudo
o segmento
https://github.com/notifications/unsubscribe-auth/AQRY9a5-s2_bjCWKNw5WiAJW-JeBf8W3ks5tBpoygaJpZM4IPGAH
.

-

Darren Cresswell
Desenvolvedor de contrato | Developer Limited
E-mail: [email protected]
Telefone:
Site: http://www.develer.co.uk

Por favor pense no meio ambiente antes de imprimir este e-mail
AVISO: Os vírus de computador podem ser transmitidos por e-mail. O destinatário
deve verificar este e-mail e quaisquer anexos quanto à presença de vírus.
Developer Limited não se responsabiliza por qualquer dano causado por qualquer vírus
transmitido por este e-mail. A transmissão de e-mail não pode ser garantida como
segura ou livre de erros, pois as informações podem ser interceptadas, corrompidas, perdidas,
destruídos, chegam atrasados ​​ou incompletos, ou contêm vírus. O remetente
portanto, não se responsabiliza por quaisquer erros ou omissões no
conteúdo desta mensagem, que surge como resultado da transmissão de e-mail.

AVISO: Embora a Developer Limited tenha tomado precauções razoáveis ​​para
garantir que nenhum vírus esteja presente neste e-mail, a empresa não pode aceitar
responsabilidade por qualquer perda ou dano decorrente do uso deste e-mail ou
anexos.

Developer Limited é uma empresa limitada registrada na Inglaterra e no País de Gales. |
Registo da empresa n.º 09817616 | Escritórios registrados: SUITE 1 SECOND
FLOOR EVERDENE HOUSE, DEANSLEIGH ROAD, BOURNEMOUTH, REINO UNIDO, BH7 7DU

obrigado @ainesophaur pela solução alternativa.

Caso alguém considere útil um exemplo de trabalho não assíncrono, aqui está o meu:

//reportError.js
const functions = {};

functions._reportToServer = (error, auxData) => {
  // do some stuff
};

functions.report = (error, auxData = {}) => {
  if (shouldReportToServer()) {
    functions._reportToServer(error, auxData);
  }
};
export default functions;

// reportError.jest.js
import reportError from 'app/common/redux/lib/reportError';
reportError._reportToServer = jest.fn();

describe('test reportError', () => {
  it('reports ERROR to server as as error', () => {
   reportError.report(new Error('fml'), {});
    expect(reportError._reportToServer).toHaveBeenCalledTimes(1);
  });
});

@ jim-moody Se entendi o problema corretamente, isso deve funcionar para o seu exemplo:

const spyOnExampleFunc2 = jest.spyOn(example, 'func2');
example.func1();
expect(spyOnExampleFunc2).toBeCalled();

(isso _somente_ funciona se as funções forem exportadas como const, como no seu exemplo)

@dinvlad meu herói!

Seguindo a resposta de @dinvlad , acho que adicionar, mostrar por exemplo ou vincular os seguintes documentos simulados relacionados na página do objeto jest à funções Mock pode ser uma melhoria para os documentos jest sobre simulação:

  • jest.isMockFunction (fn)
  • jest.genMockFromModule (moduleName)
  • jest.mock (moduleName, factory, options)
  • jest.unmock (moduleName)
  • jest.doMock (moduleName, factory, options)
  • jest.dontMock (moduleName)

Meu caso de uso é que, como um novo usuário de jest, estou migrando alguns códigos mocha + sinon.js para jest. Eu já tinha espiões e expectativas, então achei que seria fácil. Mas depois de ler este tópico e ler a documentação do jest sobre as funções Mock, fiquei com a impressão de que usar o jest dessa forma pode precisar de uma reescrita de meus testes ou compreensão detalhada de ESM ou Babel ... ou outra confusão.

Obrigado por Jest - está tornando meus testes mais fáceis de escrever / entender e mais rápidos de executar. :)

O PR esclarecendo a documentação é muito bem-vindo! 🙂

Para simular apenas módulos específicos com a sintaxe do módulo ES, você pode usar require.requireActual para restaurar os módulos originais e sobrescrever aquele que deseja simular:

import { foo } from './example';

jest.mock('./example', () => (
  ...require.requireActual('./example'),
  foo: jest.fn()
));

test('foo should be a mock function', () => {
  expect(foo('mocked!')).toHaveBeenCalledWith('mocked!');
});

Parece invertido, mas é a maneira mais simples que encontrei. Gorjeta de chapéu para @joshjg.

Estou perdido em algum lugar na longa discussão, só tenho uma pergunta, há como testar se a implementação real da função é chamada?

Pelo que entendi, se eu precisar usar jest.fn() isso substituirá a função original, mas se eu não usar, o console me dará um erro dizendo que deve ser jest.fn() function or a spy

Estou tentando testar um middleware onde a solicitação será passada adiante, então se eu simular, toda a lógica será perdida e os dados não serão passados ​​para o próximo middleware. Se eu não simular, ao importá-lo, há alguma maneira de testar se essa função foi chamada?

Você pode usar jest.spyOn , talvez? Por padrão, ele chama a função subjacente

Obrigado pela ajuda, tentei, mas o teste sugere que nunca foi chamado, embora tenha sido chamado porque coloquei o console.log e ele imprimiu

arquivo de teste

import errorHandler from '../../controller/errorHandler'

describe('auth test', () => {
  describe('test error: ', () => {
    const test1 = jest.spyOn(errorHandler, 'handleClientError')
    test('should return 400', (done) => {
      request(app)
      .post('/auth/error')
      .then((res) => {
        expect(res.statusCode).toBe(400)
        expect(test1).toBeCalled()
        done()
      })
    })

errorHandler

module.exports = {
  handleClientError () {
    console.log('err')
  }
}

console

console.log src/controller/errorHandler.js:10
      err

  ● auth test › test error:  ›  should return 400

    expect(jest.fn()).toBeCalled()

    Expected mock function to have been called.

      18 |         expect(res.statusCode).toBe(400)
    > 19 |         expect(test1).toBeCalled()
      20 |         done()
      21 |       })
      22 |     })

A função é chamada handleClientError ou logError ?

@WangHansen Pelo seu exemplo, seu código deve ser expect(errorHandler.handleClientError).toBeCalled() // > true

@WangHansen você poderia adicionar .mockImplementation() ao seu jest.spyOn() ? Como alguém vindo de Jasmine, achei esta dica crucial para alcançar a mesma funcionalidade que os espiões de Jasmine. Por exemplo

const mockModuleFunction = jest
  .spyOn(module, 'function')
  .mockImplementation(() => 'hello');
...
expect(mockModuleFunction.mock).toBeCalled();

Se você _não_ usar mockImplementation() , então jest.spyOn() produz um objeto que _não_ é uma simulação (afaiu) e, na verdade, difere para a implementação nativa. Se você tem que manter a implementação nativa, talvez valha a pena usar

const moduleFunction = module.function;
jest.spyOn(module, 'function').mockImplementation(moduleFunction);
...

Não tenho certeza se isso é necessário, mas tenho quase certeza de que _deve_ funcionar.

Voltando para a solicitação original ...

Você não poderia simplesmente envolver um proxy em torno de uma importação *? por exemplo

importar * como teste de './myfile.js';

const handler = {
/ ** Intercepta: obtendo propriedades * /
get (target, propKey, receiver) {
console.log ( GET ${propKey} );
return 123;
},

/** Intercepts: checking whether properties exist */
has(target, propKey) {
    console.log(`HAS ${propKey}`);
    return true;
}};

const p = novo Proxy (teste);

Na terça-feira, 30 de janeiro de 2018 às 16h24, Denis Loginov [email protected]
escreveu:

@WangHansen https://github.com/wanghansen você poderia adicionar
.mockImplementation () para seu jest.spyOn ()? Como alguém vindo de
Jasmine, achei esta dica crucial para obter a mesma funcionalidade que
Os espiões de Jasmine. Por exemplo

const mockModuleFunction = jest
.spyOn (módulo, 'função')
.mockImplementation (() => 'hello'); ... expect (mockModuleFunction.mock) .toBeCalled ();

Se você não usar mockImplementation (), então jest.spyOn () produz um
objeto que não é um mock (afaiu) e na verdade é transferido para o nativo
implementação. Se você tiver que manter a implementação nativa, talvez seja
vale a pena usar

const moduleFunction = module.function; jest.spyOn (módulo, 'função'). mockImplementation (moduleFunction); ...

Não tenho certeza se isso é necessário, mas tenho quase certeza de que deve funcionar.

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/facebook/jest/issues/936#issuecomment-361648414 ou mudo
o segmento
https://github.com/notifications/unsubscribe-auth/AQRY9VXyHNYatwOOY6EV637WGQH9k5Plks5tP0I9gaJpZM4IPGAH
.

-

Darren Cresswell
Desenvolvedor de contrato | Developer Limited
E-mail: [email protected]
Telefone:
Site: http://www.develer.co.uk

Por favor pense no meio ambiente antes de imprimir este e-mail
AVISO: Os vírus de computador podem ser transmitidos por e-mail. O destinatário
deve verificar este e-mail e quaisquer anexos quanto à presença de vírus.
Developer Limited não se responsabiliza por qualquer dano causado por qualquer vírus
transmitido por este e-mail. A transmissão de e-mail não pode ser garantida como
segura ou livre de erros, pois as informações podem ser interceptadas, corrompidas, perdidas,
destruídos, chegam atrasados ​​ou incompletos, ou contêm vírus. O remetente
portanto, não se responsabiliza por quaisquer erros ou omissões no
conteúdo desta mensagem, que surge como resultado da transmissão de e-mail.

AVISO: Embora a Developer Limited tenha tomado precauções razoáveis ​​para
garantir que nenhum vírus esteja presente neste e-mail, a empresa não pode aceitar
responsabilidade por qualquer perda ou dano decorrente do uso deste e-mail ou
anexos.

Developer Limited é uma empresa limitada registrada na Inglaterra e no País de Gales. |
Registo da empresa n.º 09817616 | Escritórios registrados: SUITE 1 SECOND
FLOOR EVERDENE HOUSE, DEANSLEIGH ROAD, BOURNEMOUTH, REINO UNIDO, BH7 7DU

@dinvlad @iampeterbanjo @SimenB Obrigado novamente por toda a sua ajuda, mas, infelizmente, nenhuma das maneiras que você sugeriu funcionou. Eu me pergunto se é porque a função é chamada na forma de next(err) . A lógica é, quando uma solicitação falhar, ela será passada para errorHandler chamando return next(err) . Com certeza a função está sendo chamada porque quando adicionei console.log , ela está imprimindo. Mas os testes sugerem que nunca é chamado

@dinvlad Tentei seu método, não funcionou, mas obrigado pela ajuda de qualquer maneira. Eu estava me perguntando por que você precisa chamar mockImplementation , de acordo com o documento oficial em jest.spyOn , você só o chama quando deseja substituir a função original.

@WangHansen sim, você está certo ao dizer que só é necessário quando se deseja substituir o método original. Eu estava apenas jogando uma ideia para essas situações.

Uma razão pela qual pode ter falhado para você é a assincronicidade. Se o seu método estiver usando retornos de chamada e / ou promessas (ou async / await), você precisa se certificar de que suas expectativas sejam realmente executadas antes que o método de teste termine. Existe um método especial expect.assertions(N) para afirmar isso. Além disso, certifique-se de que sua expectativa seja executada somente após o código dentro de callbacks / promises ter sido chamado. Tenho certeza de que você olhou para isso, mas apenas para a referência, https://facebook.github.io/jest/docs/en/asynchronous.html

É uma pena que simular fns usados ​​internamente como @seibelj descreve não seja possível sem alterar o módulo impl.

Na minha opinião, os testes não devem orientar como a lógica de negócios é implementada 😕 (pelo menos não neste grau)

Existem planos para implementar tal comportamento em tom de brincadeira?

Oi,
Meio tarde para toda a discussão, mas lendo toda a discussão - ainda não consegui fazer isso.
A solução promissora do @greypants não funcionou bem para mim, pois ainda chama a função original.
Alguma coisa mudou desde o início desta discussão? Estou esquecendo de algo?

Adaptei um pouco a solução do

import Module from './module'
import { getJSON } from './helpers'

jest.mock('./helpers', () =>
  Object.assign(require.requireActual('./helpers'), {
    getJSON: jest.fn()
  })
)

test('should use the mock', async () => {
  getJSON.mockResolvedValue('foo')
  await expect(module().someAsyncThingThatUsesGetJSON()).resolves.toEqual('foo')
})

test('should use the actual module', () => {
  expect(module().someFunctionThatUsesAHelper()).toBe(true)
})

Isso ainda parece meio maluco e os documentos não foram tão úteis. Sou grato por Jest e pela equipe por trás disso, mas parece um caso de uso comum que deveria ter pelo menos uma solução "oficial".

@sarahdayan , e quem quer que seja do seu interesse -
Acabei usando o babel-plugin-rewire.
Levei um tempo para encontrar esse plugin, mas era uma solução coerente o suficiente para não parecer hacky.

Na maioria dos casos, queremos nem um simulado ou mais funções de um módulo. Se você usar o sistema de zombaria global jest, poderá consegui-lo usando genMockFromModule e requireActual . Aqui está o exemplo:

//  __mocks__/myModule.js
const moduleMock = jest.genMockFromModule('./../myModule');

// in most cases we don't want to mock `someFunction`
moduleMock.someFunction = jest.fn(
  (...args) => require.requireActual('./../myModule').someFunction(...args)
)

module.exports = moduleMock;

Esta solução permite usar simulações para outras funções do módulo, usando someFunction implementação original quando todo o módulo é simulado e também permite simular a função someFunction com mockImplementationOnce ou mockImplementation API.

Eu li todas as conversas acima, mas nenhuma solução funciona para mim.
Se você ainda está procurando por uma solução para este caso de teste, a resposta é babel-plugin-rewire , este plugin é para resolver o caso que discutimos.
Por favor, dê uma olhada nessa lib, você vai me agradecer de volta mais tarde.

Então, para resumir todo o tópico acima:

  1. Suponha que você tenha um módulo m com funções f , g e h onde g e h chamar f . Gostaríamos de simular f para que g e h chamassem o simulado em vez do f real. Infelizmente, isso não é f seja sempre chamado por meio de exports conforme descrito pelo cpojer . Isso é impossível se o seu módulo usa sintaxe de importação / exportação ES6 no TypeScript (e estou supondo que o mesmo seja verdadeiro no Babel).
  2. No entanto, suponha que movamos f para outro módulo m2 . Então m terá uma declaração como import {f} from 'm2' e quando g e h chamarem f , eles na verdade estão chamando m2.f onde m2 = require('./m2') (é assim que a tradução Babel / TypeScript ficará). Isso torna possível simular f confiavelmente conforme descrito por greypants . Em outras palavras, você pode simular chamadas de maneira confiável apenas se elas cruzarem o limite de um módulo . Observação: a solução de greypants agora produz esta mensagem de erro: "O módulo de fábrica de jest.mock() não tem permissão para fazer referência a nenhuma variável fora do escopo - Acesso inválido à variável: __assign". Suspeito que seja um bug no Jest; como uma solução alternativa, use Object.assign conforme mostrado abaixo.
  3. Mas se, em vez de simular uma ou duas funções, você quiser simular tudo, exceto uma ou duas funções, use código como o de darkowic .

Exemplo de (2):

~~~ js
// módulo m.js
importar {f} de './m2'
função de exportação g () {return 'f return' + f (); };

// módulo m2.js
função de exportação f () {return 'the real f'; }

// test.js
importar * como m de './m'

jest.mock ('./ m2', () => Object.assign (
require.requireActual ('./ m2'), {
f: jest.fn (). mockReturnValue ('MOCK')
}));

teste ('simulado', () => {
esperar (mg ()). toEqual ('f retornou MOCK');
});
~~~

Ao testar isso, encontrei # 2649: chamar jest.mock dentro de um teste não tem efeito e, se você chamá-lo no escopo global, não poderá unmock antes de outros testes. Muito irritante.

Obrigado!! @sarahdayan
Estou procurando por isso há um tempo

Se os documentos estiverem faltando, os RPs são sempre bem-vindos para esclarecê-los 🙂

Olá a todos!

Brinquei um pouco e tive a seguinte ideia para resolver esse problema:

  • simule um módulo, mas o módulo simulado tem o módulo original na cadeia de protótipo.
  • fornecer um método para adicionar propriedades ao módulo simulado (que substituirá as propriedades do protótipo)
  • também fornece um método para remover as propriedades do módulo simulado (para usar o do protótipo novamente).
// m1.js
export const f = () => "original f"

// __mocks__/m1.js
const originalM1 = require.requireActual("../m1");
// set the original as a prototype
let mockModule: any = Object.create(originalM1);
const __setMock = (name, value) => {
  mockModule[name] = value;
};
const __removeMock = (name) => {
  Reflect.deleteProperty(mockModule, name);
};
// enhance the mocked module to allow overriding original exports
module.exports = Object.assign(mockModule, { __setMock, __removeMock });


// m1.test.js
import { f } from "./m1";

jest.mock("./m1");

test("mocking stuff", () => {
  // here nothing is mocked - the original module is used
  expect(f()).toBe("original f");

  // override the export f of the module
  require("./m1").__setMock("f", () => "mocked f");
  expect(f()).toBe("mocked f");

  // set it back to the original
  require("./m1").__removeMock("f");
  expect(f()).toBe("original f");

  //override with another value
  require("./m1").__setMock("f", () => "another mocked f");
  expect(f()).toBe("another mocked f");
});

Meus 2 centavos:

Testei muitas soluções (senão todas) e a única que funcionou para mim é esta (jest 23):

// importedModule.js
export const funcB = () => {
  return "not mocked";
};
export const funcA = () => {
  return mockProxy.funcB(); // this works but it's soooo hacky
};

export const mockProxy = {
  funcB
};

// moduleToTest.js
import { funcA } from "./moduleImported.js";

export default function() {
  return funcA();
}

// test
let moduleImported = require("./moduleImported.js");
moduleImported.mockProxy.funcB = jest.fn(() => "mocked");
const funcToTest = require("./moduleToTest.js").default; // or import

it("should return mocked", function() {
  expect(funcToTest()).toBe("mocked");
});

Cheguei à conclusão de que não é uma boa ideia tentar fazer isso porque:

  • test.js sabe muito sobre os detalhes de implementação de importedModule.js
  • a solução é frágil e ninguém vai entender o propósito de mockProxy olhando para importedModule.js

Alguém encontrou uma solução para isso que funcione?

Estou a usar:

"jest": "^21.2.1",
"jest-cli": "^21.2.1",

@jamesone , você leu este https://github.com/facebook/jest/issues/936#issuecomment -410080252?

Isso funcionou para mim, com base na resposta de @thomaskempel :

No meu caso, eu queria simular uma dependência em node_modules, vamos chamá-lo de 'componentes compartilhados'. Ele exporta vários componentes nomeados. Eu queria zombar apenas de algumas dessas exportações nomeadas e deixar o resto como a coisa real.

Então, em __mocks__/shared-components.js eu tenho:

const original = require.requireActual('shared-components');

module.exports = {
...original,
moduleNameToOverride: jest.fn().mockImplementation(() => {
      return 'whatever';
    }),
}

No meu caso, eu estava removendo as implementações. Espero que isso ajude alguém no futuro.

Eu enfrentei o mesmo problema recentemente, a conversa neste tópico me ajudou a entender melhor e resumi minhas descobertas aqui https://medium.com/@DavideRama/mock -spy-export-functions-within-a-single- module-in-jest-cdf2b61af642

Inspirado pela solução de @qwertie

mockGet = jest.fn()
jest.mock('my-module', () => ({
  ...jest.requireActual('my-module'),
  get: mockGet
}))

@MajorBreakfasts que funciona com React.lazy ?

const mockLazy = jest.fn();

jest.mock('React', () => ({
    ...jest.requireActual('React'),
    lazy: mockLazy
}));

Eu ainda ganho ReferenceError: React is not defined .

Para simular um módulo de função de exportação independente:
Exporte todas as funções individuais que fazem parte da exportação padrão do arquivo.

Exemplo:
dataDao.js

função getData ()
function setData ()
função deleteData ()
exportar {getData, setData, deleteData}

Agora você pode importar todas as funções do arquivo para o seu teste de brincadeira por nomenclatura padrão;

dataDao.spec.js

import * as dataDao from '../dataDao';
// Espiar os módulos que fazem referência ao nome padrão atribuído na importação
jest.spyOn (dataDao, 'getData')
jest.spyOn (dataDao, 'setData')
jest.spyOn (dataDao, 'deleteData')

@vchinthakunta , isso pode funcionar, mas parece uma violação de um dos principais objetivos da sintaxe de exportação / importação: outros módulos não serão mais capazes de importar métodos específicos ou campos de dados via

import { justThisThing } from 'someModule';

Estou perdendo alguma coisa aí?

@MajorBreakfasts que funciona com React.lazy ?

const mockLazy = jest.fn();

jest.mock('React', () => ({
    ...jest.requireActual('React'),
    lazy: mockLazy
}));

Eu ainda ganho ReferenceError: React is not defined .

Acho que 'React' deve estar em minúsculas aqui, pois está se referindo à importação?

jest.mock('react'...)

Meu código está funcionando usando o seguinte, que é mais simples do que outras soluções que vi aqui. Não requer que você use require ou configure default exportações.

helpers / navigation.js

export const initHeader = () => {
    // initialise header
    ...
}

...

export const anotherHelperFunction = () => {
    // do stuff
    ...
}

componente que usa navigation.js

import { initHeader } from '../helpers/navigation';

jest.mock('../helpers/navigation');

...

describe('Test component', () => {

    it('should reinitialise header', () => {
        const mockHeaderInit = jest.fn();
        initHeader.mockImplementation(mockHeaderInit);

        const component = mountComponent(mockProps);
        component.simulate('click');

        expect(mockHeaderInit).toBeCalled();
    }
}
mockGet = jest.fn()
jest.mock('my-module', () => ({
  ...jest.requireActual('my-module'),
  get: mockGet
}))
ReferenceError: mockGet is not defined

       4 | const mockGet = jest.fn();
       5 | jest.mock('./browserStorage', () => ({
       6 |   ...jest.requireActual('./browserStorage'),
    >  7 |   get: mockGet,
         |        ^
       8 | }));

jest.mock é içado, use doMock ou

jest.mock('./browserStorage', () => ({
  ...jest.requireActual('./browserStorage'),
  get: jest.fn(),
}));

const {get: mockGet} = require('./browserStorage');

Este parece ser um problema bastante comum. Há algo sobre isso nos documentos de brincadeira?

Então, há uma solução para simular uma função dentro do mesmo módulo ?

O método a seguir funcionou para mim, o truque é redefinir a função simulada de volta no final do teste.
Este exemplo simula a função de verificação do módulo jsonwebtoken.

  test('perform my test', async () => {
    // save the real jwt.verify function
    const verify = jwt.verify
    // mock it.
    jwt.verify = jest.fn().mockReturnValue({ sub: 0 })
    // do the test
    ...
    // set the real function back.
    jwt.verify = verify
  })

O método a seguir funcionou para mim, o truque é redefinir a função simulada de volta no final do teste.
Este exemplo simula a função de verificação do módulo jsonwebtoken.

  test('perform my test', async () => {
    // save the real jwt.verify function
    const verify = jwt.verify
    // mock it.
    jwt.verify = jest.fn().mockReturnValue({ sub: 0 })
    // do the test
    ...
    // set the real function back.
    jwt.verify = verify
  })

onde você está usando const verify ? de qualquer forma, isso só funcionará se sua função simulada não for uma função const exportada

Então, há uma solução para simular uma função _dentro do mesmo módulo_?

Depois de muita pesquisa, a solução para esse problema é armazenar suas exportações em um único objeto ao qual sua função e simulações possam fazer referência. Todos os artigos abaixo chegaram ao mesmo consenso.

https://github.com/facebook/jest/issues/936#issuecomment -438975674
https://medium.com/@qjli/how -to-mock-specific-module-function-in-jest-715e39a391f4
https://luetkemj.github.io/170421/mocking-modules-in-jest

É surpreendente para mim que ninguém tenha mencionado uma solução diferente que, se for viável para o seu código, elimina completamente todos esses problemas e torna o teste do código desejado muito, muito simples:

_Mova a única função que você deseja simular em seu próprio módulo._

Seriamente. Se seu módulo for escrito de forma que você precise testar partes internas dele separadamente de outras partes internas, então quase certamente sua classe está violando o Princípio de Responsabilidade Única (sim, não é uma classe real, mas o módulo está funcionando como uma classe, módulos sendo um contêiner de unidade de código). Divida esse otário e bum, você pode zombar do que é necessário.

Se a função simulada depende de vários estados privados, ainda não é uma boa razão para não dividir seu módulo de alguma forma. O próprio fato de que depende de um monte de estados internos implica, para mim, que as preocupações do módulo não são claramente pensadas. Talvez haja até um terceiro módulo para dividir, que representa algum tipo de classe de dados ou DTO, que pode ser passado como um argumento.

Além disso, você está exportando funções apenas para teste que, de outra forma, seriam privadas? Por que o código externo chamaria a função simulada diretamente, mas também chamaria as outras funções de que precisam para chamá-la? Aposto que há algum tipo de desconexão acontecendo aqui. Talvez a função simulada precise ficar, mas todas as funções precisam ser divididas ao meio com a metade removida indo para outro módulo. Você entendeu a ideia.

Quando o teste fica muito difícil, quase sempre é um sinal de que a refatoração está sendo necessária ...

Nenhum teste de tolice necessário:

const tomfoolery = require('tomfoolery'); // no longer required

Depois de ler este tópico e testar as soluções propostas, ainda não consigo fazer isso funcionar. Pelo que li, algumas pessoas fizeram isso funcionar, mas não consigo descobrir como.

Alguém poderia me dizer o código que preciso adicionar ao exemplo a seguir para fazer os testes passarem?

// a.js
export const foo = () => 'foo-' + bar()
export const bar = () => 'bar'
// a.test.js
import {
  foo,
  bar
} from './a'

describe('foo', () => {
  it('should return foo-MOCKED_BAR', () => {
    expect(foo()).toBe('foo-MOCKED_BAR')
  })

  it('should have the mocked implementation of bar', () => {
    expect(bar()).toBe('MOCKED_BAR')
  })
})

describe('bar', () => {
  it('should have the original implementation of bar', () => {
    expect(bar()).toBe('bar')
  })
})

describe('foo and bar together', () => {
  it('should have the original implementation of both', () => {
    expect(foo()).toBe('foo-bar')
  })
})

Obrigado!

Eu queria apenas zombar de um único método lodash como lodash.random e fui capaz de fazer isso facilmente com:

module.js

const lodash = require('lodash');

module.exports = function() {
  return lodash.random();
}

test.js

const lodash = require('lodash');
const module = require('./module.js);

it('mocks lodash', () => {
    jest.spyOn(lodash, 'random').mockImplementationOnce(() => {
      return 2;
    });

    expect(module()).toEqual(2)
});

Espero que ajude :)

Algo que funcionou para nossa equipe de trabalho com texto digitado foi criar um const que exportamos em vez de exportar a função diretamente.
Não está funcionando:
export function doSomething(a, b) {}
Trabalhando:
export const doSomething = function (a, b) {}

Mudei a exportação como

@dgrcode Você já encontrou uma solução para o seu exemplo? Pelo que eu posso dizer, o que você está tentando fazer não é suportado por zombarias via Jest. Especificamente, acho que simular é basicamente reconectar as importações para que as visualizações externas do módulo vejam os métodos simulados. No entanto, no seu exemplo, foo e bar são no mesmo módulo e assim por foo view 's de bar não pode ser ridicularizado fora.

Eu acredito que suas opções são:
1) Reorganize seu código para que foo importe um módulo que inclua bar
2) Use babel-plugin-rewire

Por favor, corrija-me se eu estiver entendendo mal!

Eu tinha um requisito ligeiramente diferente: queria simular um módulo inteiro _exceto_ para uma função. Usando a solução de @MajorBreakfasts como ponto de partida, eu vim com o seguinte:

jest.mock('my-module', () => ({
  ...jest.genMockFromModule('my-module'),
  myFunction: jest.requireActual('my-module').myFunction
}))

@dgrcode Você já encontrou uma solução para o seu exemplo? Pelo que eu posso dizer, o que você está tentando fazer não é suportado por zombarias via Jest. Especificamente, eu _penso_ que simular é basicamente reconectar as importações para que as visualizações externas do módulo vejam os métodos simulados. No entanto, no seu exemplo, foo e bar são no mesmo módulo e assim por foo view 's de bar não pode ser ridicularizado fora.

Eu acredito que suas opções são:

  1. Reorganize seu código para que foo importe um módulo que inclua bar
  2. Use babel-plugin-rewire

Por favor, corrija-me se eu estiver entendendo mal!

Esse foi realmente o meu caso
Meu entendimento de como os módulos podem ser simulados foi confuso 🤦‍♂

Basicamente
Se 2 funções estiverem no mesmo módulo e chamando uma à outra

Se foo está chamando bar

function bar() {
  return 'some-result'
}

function foo(){
  return bar()  // <-- the function I want to mock 
}

Coloque bar em um novo arquivo (para ser simulado)

Mudei o método bar em um novo arquivo e agora poderia usar muitos dos exemplos acima
Muito obrigado a @ yoni-abtech por me fazer entender isso 🤣

Do jeito que eu vejo depois de ler todo este tópico e testar várias vezes, há 3 opções ....

Opção 1 - declarar todas as funções usando const

Isso requer que você determine o uso de expressões de declarações . Felizmente, a regra func-style eslint está do seu lado.

Usar export const permite que você spyOn funções que são usadas por outras funções de dentro do módulo _same_ .

// hello.js
export const message = () => {
  return 'Hello world';
}

export const foo = () => {
  return message();
}
// hello.test.js
import * as testModule from './hello.js';

describe('test spyon with function expressions', function () {
  afterAll(() => {
    jest.restoreAllMocks();
  });
  it('should NOT mock message in foo', function () {
    const actual = testModule.foo();

    expect(actual).toBe('Hello world');
  });

  it('should mock message in foo', function () {
    jest.spyOn(testModule, 'message').mockReturnValue('my message');

    const actual = testModule.foo();

    expect(actual).toBe('my message');
    expect(testModule.message).toHaveBeenCalledTimes(1);
  });
});

Opção 2 - Use o plugin rewire babel

Se você não quiser obrigar o uso de expressões de função (ou seja, usando const ), esta pode ser uma boa abordagem.

Isso permite que você _rewire_ (também conhecido como mock) funções do mesmo módulo. Eu poderia imaginar que o código seria algo assim abaixo, mas não testei. Também a partir de seus documentos , parece que você pode religar funções no mesmo módulo que nem mesmo são exportadas do módulo 👍, imagine o exemplo abaixo sem exportar a função message .

Exemplo:

// hello.js
export function message() {
  return 'Hello world';
}

export function foo() {
  return message();
}
// hello.test.js
import * as testModule from './hello.js';

describe('test rewire api', function() {
  it('should NOT mock message in foo', function () {
    const actual = testModule.foo();

    expect(actual).toBe('Hello world');
  });

  it('should mock message in foo', function () {
    testModule.__RewireAPI__.__Rewire__('message', jest.fn().mockReturnValue('my message'));

    const actual = testModule.foo();

    expect(actual).toBe('my message');
    expect(testModule.message).toHaveBeenCalledTimes(1);
    testModule.__RewireAPI__.__ResetDependency__('message');
  });
});

Veja a documentação para exemplos.

Nota: Requer transpilação de babel

Opção 3 - Separe todas as funções em módulos / arquivos separados

Esta opção é a menos favorável, mas obviamente funcionaria bem com a funcionalidade típica mock .


PS: Embora este trecho tenha sido muito esclarecedor e muitas vezes divertido, espero que esta sinopse mitigue a necessidade de outras pessoas lerem o tópico inteiro. ✌️

Obrigado @nickofthyme , você acabou de terminar alguns dias batendo minha cabeça contra isso.

@nickofthyme seu option 1 falha em meu aplicativo e create react app :

 FAIL  src/hello.test.js
  test spyon with function expressions
    ✓ should NOT mock message in foo (3ms)
    ✕ should mock message in foo (6ms)

  ● test spyon with function expressions › should mock message in foo

    expect(received).toBe(expected) // Object.is equality

    Expected: "my message"
    Received: "Hello world"

      17 |     const actual = testModule.foo();
      18 |
    > 19 |     expect(actual).toBe("my message");
         |                    ^
      20 |     expect(testModule.message).toHaveBeenCalledTimes(1);
      21 |   });
      22 | });

      at Object.toBe (src/hello.test.js:19:20)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        1.848s
Ran all test suites related to changed files.

@danielhusar Você parece estar correto. Desculpe, eu deveria ter testado isso com o CRA.

Eu tenho a simulação descrita na opção 1 para funcionar aqui . Teste-o usando o script yarn test:hello .

Resultado

> yarn test:hello
yarn run v1.16.0
$ jest --config=jest.config.js -t=hello --verbose
 PASS  src/hello/hello.test.ts
  test hello
    ✓ should NOT mock message in foo (3ms)
    ✓ should mock message in foo (1ms)

Test Suites: 1 skipped, 1 passed, 1 of 2 total
Tests:       1 skipped, 2 passed, 3 total
Snapshots:   0 total
Time:        1.392s
Ran all test suites with tests matching "hello".
✨  Done in 2.36s.

Requer o uso de um arquivo jest.config.js usando ts-jest e chamando jest --config=./jest.config.js diretamente, não por meio de react-scripts . Não tenho certeza de como o jest está configurado no react-scripts mas acho que pode haver uma maneira de atualizar a configuração de alguma forma.

Esta correção remove as transformações para *.css e *.svg arquivos, então ignore os erros App.tsx .

Há algo específico que precisa ser feito para que funcione?
Eu diria que tenho uma configuração bastante padrão (sem ts) e não funciona fora da caixa.

Vou olhar um pouco mais esta noite e ver se isso é possível.

@danielhusar Eu olhei ontem à noite e não consegui uma solução transformer que o CRA permite que você substitua em package.json#jest . Os arquivos js e ts são transpilados usando babel-jest mas react-scripts impede que você use um arquivo de configuração .babelrc e defina o test env que eles definiram em react-scripts test aqui .

Eu gostaria de poder cavar mais fundo, mas não tenho tempo agora.

Hmm, ainda estou lutando para fazer funcionar (na minha configuração personalizada, não no cra).
(versão mais recente de jest e babel-jest)

Esta é a minha configuração de brincadeira:

module.exports = {
  name: 'my-app',
  testURL: 'http://localhost/',
  setupFiles: ['<rootDir>/setup-jest.js'],
  setupFilesAfterEnv: ['<rootDir>/setup-test.js'],
  testMatch: ['**/__tests__/**/*.test.js?(x)', '**/?(*.)+(spec|test).js?(x)'],
  testEnvironment: 'jest-environment-jsdom-fifteen',
  snapshotSerializers: ['enzyme-to-json/serializer'],
  globals: {
    ENV: 'test',
  },
  transform: {
    '^.+\\.[t|j]sx?$': 'babel-jest',
  },
};

E minha babelrc:

{
  "presets": [
    "@babel/react",
    ["@babel/env", {
      "corejs": "3",
      "useBuiltIns": "entry",
      "loose": true,
      "exclude": [
        "es.string.split"
      ]
    }],
    "@babel/flow"
  ],
  "plugins": [
    "array-includes",
    "lodash",
    "@babel/plugin-syntax-dynamic-import",
    "@babel/plugin-syntax-class-properties",
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-proposal-object-rest-spread",
    "@babel/plugin-proposal-optional-chaining"
  ],
  "env": {
    "test": {
      "plugins": ["dynamic-import-node"]
    }
  }
}

Para qualquer um que esteja lutando com a opção 1 , é importante usar a função () => { return expression } vez da função () => (expression) .

Eu consegui a opção 1 para funcionar, modificando-a para:

import * as test from './test';

export const message = () => {
    return 'Hello world';
  }

  export const foo = () => {
    return test.message();
  }

Não é bonito, mas deve funcionar.

@nickofthyme , a Opção 1 está correta como você a tem. Mas se você alterar o código para:

const foo = () => {}
export { foo }

Então ele quebra. Presumivelmente porque você cria um novo literal de objeto e o exporta.

Observação interessante. Obrigado @maletor

Jest tem um exemplo muito simples e claro em sua documentação de como simular parcialmente um módulo. Isso funciona com as instruções ES import e Node require.
https://jestjs.io/docs/en/jest-object#jestrequireactualmodulename

@johncmunson Esse é um bom ponto. No entanto, este exemplo que você mostrou de simulação de um módulo só funciona se você só precisar executar jest.mock _uma vez_ e nenhum dos métodos simulados usar outra exportação desse módulo.

Pegue o exemplo acima ... Eu adicionei bar para mostrar como quero simular o módulo de forma diferente entre foo e bar .

export const message = (): string => {
  return 'Hello world';
}

export const foo = (): string => {
  return message();
}

export const bar = (): (() => string) => {
  return foo;
}

Usando jest.mock com jest.requireActual , acho que seria algo assim.

import * as mockTestModule from './hello';

jest.mock('./hello');
const actualTestModule = jest.requireActual('./hello');

describe('test hello', function () {
  afterAll(() => {
    jest.restoreAllMocks();
  });

  // first test doesn't depend on any other method of the module so no mocks
  it('should NOT mock message in foo', function () {
    const actual = actualTestModule.foo();

    expect(actual).toBe('Hello world');
  });

  // the second I want to mock message in foo
  it('should mock message in foo', function () {
    jest.spyOn(mockTestModule, 'message').mockReturnValue('my message');
    const actual = actualTestModule.foo();

    expect(actual).toBe('my message'); // fails
    expect(mockTestModule.message).toHaveBeenCalledTimes(1); // never called
  });

  it('should mock foo in bar', function () {
    jest.spyOn(mockTestModule, 'foo').mockReturnValue('my message');
    const actual = actualTestModule.bar();

    expect(actual()).toBe('my message'); // fails
    expect(mockTestModule.message).toHaveBeenCalledTimes(1); // never called
  });
});

Eu até tentei zombar deles separadamente com jest.doMock e ainda obtive o mesmo resultado.


Clique para ver o código

`` `ts
import * como testModule de './hello';

descrever ('testar olá', função () {
afterAll (() => {
jest.restoreAllMocks ();
});

it('should NOT mock message in foo', function () {
  const actual = testModule.foo();

  expect(actual).toBe('Hello world');
});

it('should mock message in foo', function () {
  jest.doMock('./hello', () => {
    // Require the original module to not be mocked...
    const originalModule = jest.requireActual('./hello');

    return {
      ...originalModule,
      message: jest.fn().mockReturnValue('my message'),
    };
  });
  const actual = testModule.foo();

  expect(actual).toBe('my message'); // fails
  expect(testModule.message).toHaveBeenCalledTimes(1); // never called
});

it('should mock foo in bar', function () {
  jest.doMock('./hello', () => {
    // Require the original module to not be mocked...
    const originalModule = jest.requireActual('./hello');

    return {
      ...originalModule,
      foo: jest.fn().mockReturnValue('my message'),
    };
  });
  const actual = testModule.bar()();

  expect(actual).toBe('my message'); // fails
  expect(testModule.foo).toHaveBeenCalledTimes(1); // never called
});

});
`` `

O problema com essa abordagem é que exigir o módulo real, digamos, chamar foo , ainda chama a função message real e não a simulação.

Eu gostaria que fosse tão simples, mas pelo que vejo, isso não ajuda para os exemplos deste tópico. Se eu estiver faltando alguma coisa aqui, por favor me avise. Terei prazer em admitir a culpa.

Para quem se depara com isso em busca de uma solução, o seguinte parece estar funcionando para mim ao exportar muitas const / funções em um arquivo e importá-las em um arquivo que estou testando

function mockFunctions() {
  const original = require.requireActual('../myModule');
  return {
    ...original, //Pass down all the exported objects
    test: jest.fn(() => {console.log('I didnt call the original')}),
    someFnIWantToCurry: {console.log('I will curry the original') return jest.fn((...args) => original.someFnIWantToCurry(...args)}),
  }
jest.mock('../myModule', () => mockFunctions());
const storage = require.requireMock('../myModule');
`

O seguinte funciona e é um pouco mais curto:

const module = require('./module');
jest.spyOn(module, 'myFn').mockImplementation(() => 'val');

No texto datilografado, apenas import vez de require :

import * as module from './module';

Isso tem a vantagem de tornar a vida mais fácil para restaurar as funções originais e fazer simulações claras.

Para quem se depara com isso em busca de uma solução, o seguinte parece estar funcionando para mim ao exportar muitas const / funções em um arquivo e importá-las em um arquivo que estou testando

function mockFunctions() {
  const original = require.requireActual('../myModule');
  return {
    ...original, //Pass down all the exported objects
    test: jest.fn(() => {console.log('I didnt call the original')}),
    someFnIWantToCurry: {console.log('I will curry the original') return jest.fn((...args) => original.someFnIWantToCurry(...args)}),
  }
jest.mock('../myModule', () => mockFunctions());
const storage = require.requireMock('../myModule');
`

O seguinte funciona e é um pouco mais curto:

const module = require('./module');
jest.spyOn(module, 'myFn').mockImplementation(() => 'val');

No texto datilografado, apenas import vez de require :

import * as module from './module';

Isso tem a vantagem de tornar a vida mais fácil para restaurar as funções originais e fazer simulações claras.

Oh, sim, também este método não está funcionando se seu objeto tiver apenas getter definido. A mensagem de erro pode ser assim:

Test suite failed to run

    TypeError: Cannot set property useContent of #<Object> which has only a getter

Provavelmente será necessário usar jest.mock(..) para este caso. : bowing_man:

Minhas simulações estão funcionando usando o seguinte:

import { unsubscribe } from "../lib/my-lib"
import { MyComponent } from "./index"

test("unsubscribe gets called", () => {
    const module = require("../lib/my-lib")
    jest.spyOn(
        module,
        "unsubscribe"
    ).mockImplementation(() => jest.fn())

    const { getByTestId } = render(() => <MyComponent  />)

    let button = getByTestId("trigger.some.action.button")

    fireEvent.press(button)

    expect(unsubscribe).toHaveBeenCalled()
})

Não parece tão elegante e não escala tão facilmente, mas funciona muito bem e se adapta aos meus casos por enquanto ... mas se alguém puder sugerir qualquer outra sintaxe, isso seria ótimo! Esta é a única sintaxe que parece estar funcionando.

código do módulo es6:

export const funcA = () => {};
export const funcB = () => {
  funcA();
};

Depois de transpilado para CommonJS:

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.funcB = exports.funcA = void 0;

var funcA = function funcA() {};

exports.funcA = funcA; // You can mock or add a spy  on this `funcA`

var funcB = function funcB() {
  funcA();  // This is still original `funcA`
};

exports.funcB = funcB;

Existem muitas maneiras de resolver esta situação.

  1. Você precisa alterar o código assim, para que possa usar o método simulado / espiado funcA
function funcA() {}
exports.funcA = funcA;

function funcB() {
  exports.funcA(); // Now, this `exports.funcA` is added a spy or mocked. Keep the same reference to `funcA`
}
exports.funcB = funcB;

Ou,

export let funcA = () => {};
export const funcB = () => {
  exports.funcA();
};

resultados do teste de unidade:

 PASS  myModule.test.ts (9.225s)
  funcB
    ✓ should call funcA (3ms)

-------------|---------|----------|---------|---------|-------------------
File         | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------|---------|----------|---------|---------|-------------------
All files    |     100 |      100 |     100 |     100 |                   
 myModule.ts |     100 |      100 |     100 |     100 |                   
-------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        10.967s
  1. use o pacote rewire para simular funcA
    ...

Além disso, você precisa dar uma olhada nestes documentos: https://nodejs.org/api/modules.html#modules_exports_shortcut , para ver o que exatamente require faz

A solução neste post stackoverflow funcionou para mim
https://stackoverflow.com/a/53402206/1217998

Basicamente, primeiro você converte todas as funções que deseja converter em jest.fn

jest.mock('../../utils', () => {
  const actualUtils = jest.requireActual('../../utils');
  const originalImplementation = actualUtils.someFun;

  return {
    ...actualUtils,
    someFun: jest.fn()
      .mockImplementation(originalImplementation),
  };
});
const utils = require('../../utils');

Então você pode usá-lo normalmente se quiser ou simular assim

jest.spyOn(utils, 'someFun').mockReturnValueOnce(true);

Você pode usar isso para obter a implementação original

beforeEach(() => {
    jest.clearAllMocks();
  });

A solução neste post stackoverflow funcionou para mim
https://stackoverflow.com/a/53402206/1217998

Basicamente, primeiro você converte todas as funções que deseja converter em jest.fn

jest.mock('../../utils', () => {
  const actualUtils = jest.requireActual('../../utils');
  const originalImplementation = actualUtils.someFun;

  return {
    ...actualUtils,
    someFun: jest.fn()
      .mockImplementation(originalImplementation),
  };
});
const utils = require('../../utils');

Então você pode usá-lo normalmente se quiser ou simular assim

jest.spyOn(utils, 'someFun').mockReturnValueOnce(true);

Você pode usar isso para obter a implementação original

beforeEach(() => {
    jest.clearAllMocks();
  });

Obrigado!

Jest tem um exemplo muito simples e claro em sua documentação de como simular parcialmente um módulo. Isso funciona com as instruções ES import e Node require.
https://jestjs.io/docs/en/jest-object#jestrequireactualmodulename

Não funciona quando a função simulada é chamada de dentro do módulo.

Além disso, descobri que às vezes pode ser útil simular a função da maneira que você não altera a função original, mas chama a função com algumas variáveis ​​personalizadas (adicionais):

jest.mock('./someModule', () => {
  const moduleMock = require.requireActual('./someModule');
  return {
    ...moduleMock,
    // will mock this function 
    someFunction: (args) =>
      moduleMock.someFunction({
        ...args,
        customArgument,
      }),
  };
});

No meu caso, eu precisava passar a configuração do vir para funcionar, sem a qual ele usaria o padrão.

Esta é a única maneira que encontrei de fazer isso, então se você tiver algumas ideias melhores ou mais fáceis, ficarei feliz em saber :)

FWIW reuni várias abordagens com exemplos executáveis ​​em https://github.com/magicmark/jest-how-do-i-mock-x/blob/master/src/function-in-same-module/README. md

Isso não responde à pergunta / problema dos OPs, mas é uma solução com alguma refatoração envolvida. Descobri que separar minhas funções em arquivos diferentes e, em seguida, zombar dessas importações é a coisa mais fácil de fazer.

// package.json
...
"scripts": {
    "test": "jest",

...
"devDependencies": {
    "@babel/preset-env": "^7.11.5",
    "jest": "^24.9.0",
...

`` `js
// babel.config.js

module.exports = {
predefinições: [
[
'@ babel / preset-env',
{
alvos: {
nó: 'atual',
},
},
],
],
};

```js
// module-utils.js

export const isBabaYaga = () => {
  return false
}

// module.js

import { isBabaYaga } from './module-utils'

export const isJohnWickBabaYaga = () => {
  return isBabaYaga()
}
// modules.test.js

import { isJohnWickBabaYaga } from './module';

jest.mock('./module-utils', () => ({
    isBabaYaga: jest.fn(() => true)
}))

test('John Wick is the Baba Yaga', () => {

    // when
    const isBabaYaga = isJohnWickBabaYaga()

    // then
    expect(isBabaYaga).toBeTruthy()
});
PASS  src/module.test.js
✓ John Wick is the Baba Yaga (4ms)

Recentemente, encontrei esse problema. Nenhuma das soluções propostas funciona para mim porque não consigo alterar o código. O babel-plugin-rewire também não funciona para mim. Existe alguma outra solução para testar se uma função foi chamada por outra função dentro do mesmo módulo? Isso honestamente parece que deveria funcionar ou que deveria haver um plugin do babel por aí que faz isso. Qualquer ajuda seria muito apreciada!

Recentemente, encontrei esse problema. Nenhuma das soluções propostas funciona para mim porque não consigo alterar o código. O babel-plugin-rewire também não funciona para mim. Existe alguma outra solução para testar se uma função foi chamada por outra função dentro do mesmo módulo? Isso honestamente parece que deveria funcionar ou que deveria haver um plugin do babel por aí que faz isso. Qualquer ajuda seria muito apreciada!

Você já consultou https://github.com/facebook/jest/issues/936#issuecomment -659597840? Há uma reprodução mínima lá que simula chamadas de funções no mesmo arquivo.

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