2016-11-06 16 views
18

Có cách nào trong Jest để giả lập các đối tượng toàn cầu, chẳng hạn như navigator, hoặc Image *? Tôi đã từ bỏ rất nhiều về điều này, và để lại nó lên đến một loạt các phương pháp tiện ích mockable. Ví dụ:Mocking globals trong Jest

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

Thử nghiệm chức năng nhỏ này thật đơn giản, nhưng không có tính xác thực. Tôi có thể lấy 75% số đường có, nhưng đây là khoảng như xa như tôi có thể đ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'); 
}); 

Mặt khác, nếu tôi không sao với gián tiếp này, bây giờ tôi có thể truy cập navigator qua những tiện ích này:

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

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

     /* More implementation */    
    } 
} 

... và tất định kiểm tra như thế này ...

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

trong số tất cả các khuôn khổ thử nghiệm tôi đã sử dụng, jest cảm thấy như là giải pháp hoàn thiện nhất, nhưng bất cứ lúc nào tôi viết awkwar d mã chỉ để làm cho nó có thể kiểm tra, tôi cảm thấy như các công cụ thử nghiệm của tôi đang cho phép tôi xuống.

Đây có phải là giải pháp duy nhất hoặc tôi có cần thêm phần thưởng không?

* Đừng cười. Image là tuyệt vời cho ping một nguồn tài nguyên mạng từ xa.

Trả lời

34

Khi mọi thử nghiệm chạy môi trường riêng của mình, bạn có thể thử hình cầu bằng cách chỉ ghi đè lên chúng. Tất cả các vars toàn cầu có thể được truy cập theo không gian tên global.

global.navigator = { 
    onLine: true 
} 

Ghi đè chỉ có tác dụng trong thử nghiệm hiện tại của bạn và sẽ không ảnh hưởng đến người khác. Đây cũng là một cách tốt để xử lý Math.random hoặc Date.now

Lưu ý, mà thông qua một số thay đổi trong jsdom nó có khả năng là bạn phải thử globals như thế này:

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

sẽ 'global' là giống như ' cửa sổ' trong trình duyệt? – Andrew

+1

Có nghĩa là bạn có thể đặt nội dung ở đó. Nhưng có lẽ không phải tất cả những thứ có trong 'cửa sổ' cũng có mặt trong' global'. Đó là lý do tại sao tôi không sử dụng 'global.navigator.onLine' vì tôi không chắc rằng có một đối tượng' navigator' trong 'global'. –

+1

Hãy nhận biết rằng như một thực tế chung không phải tất cả các tài sản toàn cầu có thể ghi đè ngày nay. Một số có thể ghi sai và sẽ bỏ qua các thay đổi giá trị. –