2016-11-06 49 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

请注意,作为一种普遍的做法,并不是所有的全球房产都可以在当下覆盖。有些具有可写的错误,并会忽略更改值的尝试。 –