2016-11-06 12 views
18

Czy istnieje sposób, aby kpić z obiektów globalnych, takich jak navigator lub Image *? Zupełnie się z tego zrezygnowalem i pozostawiłem to serii możliwych do zastosowania metod użytkowych. Na przykład:Szydercze globale w Jest

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

Testowanie tej niewielkiej funkcji jest proste, ale w najlepszym przypadku nie jest deterministyczne. Mogę dostać 75% drogi tam, ale jest to o ile mogę iść:

// Utils.test.js 
it('knows if it is online',() => { 
    const { isOnline } = require('path/to/Utils'); 

    expect(() => isOnline()).not.toThrow(); 
    expect(typeof isOnline()).toBe('boolean'); 
}); 

Z drugiej strony, jeśli jestem w porządku z tym zadnie, mogę teraz przejść navigator za pośrednictwem tych narzędzi:

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

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

     /* More implementation */    
    } 
} 

... i deterministycznie przetestować jak to ...

// 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(); 
}); 

Spośród wszystkich ram testowania użyłem, żartem czuje się jak najbardziej kompletne rozwiązanie, ale za każdym razem piszę awkwar d kod tylko po to, aby można było go przetestować, mam wrażenie, że moje narzędzia testowe mnie zawodzą.

Czy to jedyne rozwiązanie, czy muszę dodać Rewire?

* Nie smuć się. Image jest fantastyczny do pingowania zdalnego zasobu sieciowego.

Odpowiedz

34

Ponieważ każdy test uruchamia własne środowisko, możesz udawać globale, po prostu je nadpisując. Dostęp do wszystkich globalnych zmiennych można uzyskać za pomocą przestrzeni nazw global.

global.navigator = { 
    onLine: true 
} 

Zastąpienie ma tylko efekty w bieżącym teście i nie wpłynie na inne. To także dobry sposób obsłużyć Math.random lub Date.now

uwaga, że ​​przez kilka zmian w jsdom to mogło być możliwe, że trzeba kpić globalnych jak to:

Object.defineProperty(globalObject, key, { value, writable: true }); 
+0

Will 'global' być taka sama, jak' okno "w przeglądarce? – Andrew

+1

Tak w tym sensie, że możesz tam ustawić rzeczy. Ale może nie wszystkie rzeczy obecne w 'oknie' są również obecne w' global'. To dlatego nie używam 'global.navigator.onLine', ponieważ nie jestem pewien, czy istnieje obiekt' navigator' w 'global'. –

+1

Należy pamiętać, że z ogólnej praktyki nie wszystkie dzisiejsze globalne właściwości są nadpisywane. Niektóre mają zapisywalne fałsz i ignorują próby zmiany wartości. –