2016-11-06 109 views
18

在Jest中是否有任何方法來模擬全局對象,如navigatorImage *?我幾乎放棄了這一點,並將其留給了一系列可嘲弄的效用方法。例如:在Jest中嘲笑全局

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

測試這個微小的函數很簡單,但是很笨拙而且不確定。我可以得到的方式出現75%,但是這是關於據我可以走:

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

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

在另一方面,如果我還好這個間接的,我現在就可以通過這些工具訪問navigator

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

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

     /* More implementation */    
    } 
} 

...和確定性測試這樣的...

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

出我用過的所有測試框架,玩笑感覺最完整的解決方案,但任何時候我寫awkwar d代碼只是爲了使其可測試,我覺得我的測試工具讓我失望。

這是唯一的解決方案還是我需要添加Rewire?

*請勿假笑。 Image對於ping遠程網絡資源非常棒。

回答

34

由於每個測試運行自己的環境,您可以通過覆蓋它們來模擬全局變量。所有全局變量可通過global名稱空間訪問。

global.navigator = { 
    onLine: true 
} 

覆蓋只對當前測試有影響,不會影響其他人。這也給處理Math.randomDate.now

注意的好辦法,通過在jsdom一些變化可能是可能的,你必須嘲笑這樣的全局:

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

將'global'是一樣的'窗口在瀏覽器中? – Andrew

+1

是的,你可以在那裏設置東西。但也許並不是所有'window'中的東西都存在於'global'中。這就是爲什麼我不使用'global.navigator.onLine'因爲我不確定''global'中是否有'navigator'對象。 –

+1

請注意,作爲一種普遍的做法,並不是所有的全球房產都可以在當下覆蓋。有些具有可寫的錯誤,並會忽略更改值的嘗試。 –