web-dev-qa-db-fra.com

Comment simuler une fonction nommée importée dans Jest lorsque le module est débloqué

J'essaie de tester le module suivant dans Jest:

// myModule.js

export function otherFn() {
  console.log('do something');
}

export function testFn() {
  otherFn();

  // do other things
}

Comme indiqué ci-dessus, il exporte certaines fonctions nommées et testFn utilise otherFn.

En plaisanterie quand j'écris mon test unitaire pour testFn, je veux me moquer de la fonction otherFn car je ne veux pas que les erreurs dans otherFn affectent mon test unitaire pour testFn. Mon problème est que je ne suis pas sûr de la meilleure façon de le faire:

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

import { testFn, otherFn } from 'myModule';

describe('test category', () => {
  it('tests something about testFn', () => {
    // I want to mock "otherFn" here but can't reassign
    // a.k.a. can't do otherFn = jest.fn()
  });
});

Toute aide/perspicacité est appréciée.

35
Jon Rubins
import m from '../myModule';

Ne fonctionne pas pour moi, j'ai utilisé:

import * as m from '../myModule';

m.otherFn = jest.fn();
19
bobu

Le code transpilé ne permettra pas à babel de récupérer la liaison à laquelle se réfère otherFn(). Si vous utilisez une expession de fonction, vous devriez pouvoir réaliser otherFn().

// myModule.js
exports.otherFn = () => {
  console.log('do something');
}

exports.testFn = () => {
  exports.otherFn();

  // do other things
}

// myModule.test.js
import m from '../myModule';

m.otherFn = jest.fn();

Mais comme @kentcdodds l'a mentionné dans le commentaire précédent, vous ne voudriez probablement pas vous moquer de otherFn(). Ecrivez plutôt une nouvelle spécification pour otherFn() et simulez tous les appels nécessaires.

Donc, par exemple, si otherFn() fait une requête http ...

// myModule.js
exports.otherFn = () => {
  http.get('http://some-api.com', (res) => {
    // handle stuff
  });
};

Ici, vous voudrez simuler http.get et mettre à jour vos assertions en fonction de vos implémentations simulées.

// myModule.test.js
jest.mock('http', () => ({
  get: jest.fn(() => {
    console.log('test');
  }),
}));
9
vutran

Utilisez jest.requireActual() dans __jest.mock()

jest.requireActual(moduleName)

Renvoie le module actuel au lieu d'un simulacre, en ignorant toutes les vérifications pour savoir si le module doit ou non recevoir une implémentation simulée.

Exemple

Je préfère cet usage concis où vous avez besoin et que vous répandez dans la return:

// myModule.test.js

jest.mock('./myModule.js', () => {
  return {
    ...(jest.requireActual('./myModule.js')),
    otherFn: () => {}
  }
})

describe(...)

Cette méthode est également référencée dans la documentation de Jest's Manual Mocks (vers la fin de Exemples ):

Pour vous assurer que la maquette manuelle et sa mise en œuvre réelle restent synchronisées, il peut être utile d'exiger que le module réel utilise jest.requireActual(moduleName) dans votre maquette manuelle et qu'il soit modifié avec des fonctions fictives avant de l'exporter.

7
gfullam

On dirait que je suis en retard à cette fête, mais oui, c'est possible.

testFn doit juste appeler otherFn en utilisant le module .

Si testFn utilise le module pour appeler otherFn, l'exportation du module pour otherFn peut être fausse et testFn appellera la fausse.


Voici un exemple de travail:

myModule.js

import * as myModule from './myModule';  // import myModule into itself

export function otherFn() {
  return 'original value';
}

export function testFn() {
  const result = myModule.otherFn();  // call otherFn using the module

  // do other things

  return result;
}

myModule.test.js

import * as myModule from './myModule';

describe('test category', () => {
  it('tests something about testFn', () => {
    const mock = jest.spyOn(myModule, 'otherFn');  // spy on otherFn
    mock.mockReturnValue('mocked value');  // mock the return value

    expect(myModule.testFn()).toBe('mocked value');  // SUCCESS

    mock.mockRestore();  // restore otherFn
  });
});
4

En plus de la première réponse, vous pouvez utiliser babel-plugin-rewire pour simuler une fonction nommée importée. Vous pouvez consulter la section superficiellement pour fonction nommée recâblage

L’un des avantages immédiats de votre situation est qu’il n’est pas nécessaire de modifier la façon dont vous appelez l’autre fonction de votre fonction.

0
schrodinger's code