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 import
s par require
s 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.
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".
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);
});
});
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.
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.
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
});
});
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();
})