86 votes

Malsains globals dans Jest

Est-il possible pour Rire, à se moquer des objets globaux, tels que l' navigatorou Image*? J'ai à peu près renoncé à ce, et a laissé une série de mockable les méthodes de l'utilitaire. Par exemple:

// Utils.js
export isOnline() {
    return navigator.onLine;
}

Les tests de cette petite fonction est simple, mais crufty et non déterministe à tous. Je peux obtenir 75% du chemin, mais c'est à peu près 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 par l'intermédiaire de ces services publics:

// Foo.js
import { isOnline } from './Utils';

export default class Foo {
    doSomethingOnline() {
        if (!isOnline()) throw new Error('Not online');

        /* More implementation */            
    }
}

...et de façon déterministe test 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();
});

De toutes les infrastructures de test que j'ai utilisé, la Blague se sent comme la solution la plus complète, mais chaque fois que j'écris maladroit code juste pour rendre testable, je sens que mes outils de test sont de me laisser descendre.

Est-ce la seule solution ou dois-je besoin d'ajouter Rewire?

*Ne pas sourire en coin. Image est fantastique pour une requête ping à une ressource réseau à distance.

116voto

Andreas Köberle Points 16453

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 nom 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 });
 

21voto

smeltedcode Points 66

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, la seule solution consiste à utiliser les afterEach() ou afterAll() pour nettoyer vos affectations à global .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X