web-dev-qa-db-fra.com

Comment puis-je simuler une importation de module ES6 à l'aide de Jest?

Je commence à penser que ce n'est pas possible, mais je veux quand même poser la question.

Je veux tester qu'un de mes modules ES6 appelle un autre module ES6 d'une manière particulière. C'est super facile avec Jasmine -

Le code de l'application:

// myModule.js
import dependency from './dependency';

export default (x) => {
  dependency.doSomething(x * 2);
}

Et le code de test:

//myModule-test.js
import myModule from '../myModule';
import dependency from '../dependency';

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    spyOn(dependency, 'doSomething');

    myModule(2);

    expect(dependency.doSomething).toHaveBeenCalledWith(4);
  });
});

Quel est l'équivalent avec Jest? Je pense que c'est une chose si simple à vouloir faire, mais je me suis arraché les cheveux pour essayer de le comprendre.

Le plus proche que je sois venu est de remplacer les imports par requires et de les déplacer dans les tests/fonctions. Aucune de ces choses que je veux faire.

// myModule.js
export default (x) => {
  const dependency = require('./dependency'); // yuck
  dependency.doSomething(x * 2);
}

//myModule-test.js
describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    jest.mock('../dependency');

    myModule(2);

    const dependency = require('../dependency'); // also yuck
    expect(dependency.doSomething).toBeCalledWith(4);
  });
});

Pour les points bonus, j'aimerais que tout fonctionne correctement lorsque la fonction dans dependency.js est une exportation par défaut. Cependant, je sais que l'espionnage sur les exportations par défaut ne fonctionne pas dans Jasmine (ou du moins je ne pourrais jamais le faire fonctionner), donc je ne laisse pas espérer que ce soit possible dans Jest non plus.

203
Cam Jackson

J'ai pu résoudre ce problème en utilisant un hack impliquant import *. Cela fonctionne même pour les exportations nommées et par défaut!

Pour une exportation nommée:

// dependency.js
export const doSomething = (y) => console.log(y)

// myModule.js
import { doSomething } from './dependency';

export default (x) => {
  doSomething(x * 2);
}

// myModule-test.js
import myModule from '../myModule';
import * as dependency from '../dependency';

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    dependency.doSomething = jest.fn(); // Mutate the named export

    myModule(2);

    expect(dependency.doSomething).toBeCalledWith(4);
  });
});

Ou pour une exportation par défaut:

// dependency.js
export default (y) => console.log(y)

// myModule.js
import dependency from './dependency'; // Note lack of curlies

export default (x) => {
  dependency(x * 2);
}

// myModule-test.js
import myModule from '../myModule';
import * as dependency from '../dependency';

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    dependency.default = jest.fn(); // Mutate the default export

    myModule(2);

    expect(dependency.default).toBeCalledWith(4); // Assert against the default
  });
});

Comme Mihai Damian l'a fait remarquer à juste titre ci-dessous, ceci modifie l'objet module de dependency, ce qui entraînera une "fuite" vers d'autres tests. Donc, si vous utilisez cette approche, vous devez stocker la valeur d'origine, puis la rétablir après chaque test. Pour faire cela facilement avec Jest, utilisez la méthode spyOn () à la place de jest.fn(), car elle permet de restaurer facilement sa valeur d'origine, évitant par conséquent les "fuites".

177
Cam Jackson

Vous devez vous moquer du module et paramétrer l'espion par vous-même:

import myModule from '../myModule';
import dependency from '../dependency';
jest.mock('../dependency', () => ({
  doSomething: jest.fn()
}))

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    myModule(2);
    expect(dependency.doSomething).toBeCalledWith(4);
  });
});
131
Andreas Köberle

Ajouter plus à la réponse d'Andreas. J'ai eu le même problème avec le code ES6, mais je ne voulais pas muter les importations. Cela avait l'air hacky. Alors j'ai fait ça

import myModule from '../myModule';
import dependency from '../dependency';
jest.mock('../dependency');

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    myModule(2);
  });
});

Et ajouté dependency.js dans le dossier "__ mocks __" parallèlement à dependency.js. Cela a fonctionné pour moi. En outre, cela m'a donné la possibilité de renvoyer des données appropriées de l'implémentation factice. Assurez-vous de donner le bon chemin au module que vous voulez simuler.

38
mdsAyubi

Pour simuler une exportation par défaut du module de dépendance ES6 à l'aide de jest:

import myModule from '../myModule';
import dependency from '../dependency';

jest.mock('../dependency');

// If necessary, you can place a mock implementation like this:
dependency.mockImplementation(() => 42);

describe('myModule', () => {
  it('calls the dependency once with double the input', () => {
    myModule(2);

    expect(dependency).toHaveBeenCalledTimes(1);
    expect(dependency).toHaveBeenCalledWith(4);
  });
});

Les autres options ne fonctionnaient pas pour mon cas.

37
falsarella

La question est déjà résolue mais vous pouvez la résoudre comme ceci:

dependency.js

module.exports.doSomething = (x) => x

myModule.js:

const { doSomething } = require('./dependency')
module.exports = (x) => doSomething(x * 2)

myModule.spec.js:

jest.mock('../dependency')
const { doSomething } = require('../dependency')
const myModule = require('../myModule')
describe('myModule', () => {
    it('calls the dependency with double the input', () => {
      doSomething.mockImplementation((x) => x * 10)

      myModule(2);

      expect(doSomething).toHaveBeenCalledWith(4);
      console.log(myModule(2)) // 40
    });
  });
0
Slim

J'ai résolu ce problème d'une autre manière. Disons que vous avez votre dependency.js

export const myFunction = () => { }

Je crée un fichier depdency.mock.js avec le contenu suivant:

export const mockFunction = jest.fn();

jest.mock('dependency.js', () => ({ myFunction: mockFunction }));

et dans le test, avant d’importer le fichier qui a la dépendance que j’utilise:

import { mockFunction } from 'dependency.mock'
import functionThatCallsDep from './tested-code'

it('my test', () => {
    mockFunction.returnValue(false);

    functionThatCallsDep();

    expect(mockFunction).toHaveBeenCalled();

})
0
Felipe Leusin