Est-il possible dans Jest de se moquer d'objets globaux, tels que navigator
ou Image
*? J'ai à peu près abandonné cela et laissé le soin à une série de méthodes utilitaires moquables. Par exemple:
// Utils.js
export isOnline() {
return navigator.onLine;
}
Tester cette fonction minuscule est simple, mais cruel et pas du tout déterministe. Je peux obtenir 75% du chemin, mais c'est aussi loin que je peux aller:
// Utils.test.js
it('knows if it is online', () => {
const { isOnline } = require('path/to/Utils');
expect(() => isOnline()).not.toThrow();
expect(typeof isOnline()).toBe('boolean');
});
D'autre part, si je suis d'accord avec cette indirection, je peux maintenant accéder à navigator
via ces utilitaires:
// Foo.js
import { isOnline } from './Utils';
export default class Foo {
doSomethingOnline() {
if (!isOnline()) throw new Error('Not online');
/* More implementation */
}
}
... et tester de manière déterministe comme ça ...
// Foo.test.js
it('throws when offline', () => {
const Utils = require('../services/Utils');
Utils.isOnline = jest.fn(() => isOnline);
const Foo = require('../path/to/Foo').default;
let foo = new Foo();
// User is offline -- should fail
let isOnline = false;
expect(() => foo.doSomethingOnline()).toThrow();
// User is online -- should be okay
isOnline = true;
expect(() => foo.doSomethingOnline()).not.toThrow();
});
Parmi tous les frameworks de test que j'ai utilisés, Jest semble être la solution la plus complète, mais chaque fois que j'écris un code compliqué juste pour le rendre testable, j'ai l'impression que mes outils de test me laissent tomber.
Est-ce la seule solution ou dois-je ajouter Rewire?
* Ne souriez pas. Image
est fantastique pour envoyer une requête ping à une ressource réseau distante.
Comme chaque test exécute son propre environnement, vous pouvez vous moquer des globaux en les écrasant. Tous les vars globaux sont accessibles via l’espace de noms global
.
global.navigator = {
onLine: true
}
L'écrasement n'a que des effets sur votre test actuel et n'affectera pas les autres. C'est aussi un bon moyen de gérer Math.random
ou Date.now
Notez que grâce à certains changements dans jsdom, il est possible que vous deviez vous moquer de globals comme ceci:
Object.defineProperty(globalObject, key, { value, writable: true });
Jest peut avoir changé depuis que la réponse acceptée a été écrite, mais Jest ne semble pas réinitialiser votre réponse globale après le test. Veuillez consulter les tests ci-joints.
https://repl.it/repls/DecentPlushDeals
Autant que je sache, le seul moyen de contourner ce problème consiste à utiliser afterEach()
ou afterAll()
pour nettoyer vos affectations dans global
.
Si quelqu'un a besoin de se moquer de global avec propriétés statiques, alors mon exemple pourrait aider:
beforeAll(() => {
global.EventSource = jest.fn().mockImplementation(() => ({
readyState: 0,
close: jest.fn()
}))
global.EventSource.CONNECTING = 0
global.EventSource.OPEN = 1
global.EventSource.CLOSED = 2
})