如何伪造Jasmine离线?

时间:2016-12-14 19:18:30

标签: javascript unit-testing jasmine karma-jasmine

我有一个javascript函数,它应该在脱机时的行为与在线作为安全措施不同。我想进行Jasmine单元测试,测试离线和在线模式下的功能 - 例如,

// offline
describe('When there is no connection to the internet', function() {
  beforeEach(function(){
    spyOn(navigator, 'onLine').and.returnValue(false);
  });

  it('offline behavior happens', function() {
    myFunction();

    expect(something).not.toHaveBeenCalled();
  });
});

// online
describe('When there is a connection to the internet', function() {
  beforeEach(function(){
    spyOn(navigator, 'onLine').and.returnValue(true);
  });

  it('online behavior happens', function() {
    myFunction();

    expect(something).toHaveBeenCalled();
  });
});

但是,我无法伪造navigator.onLine的值。在我的before中,我也尝试过:

navigator = {
  'onLine': false
}

这也不起作用。为了彻底,我尝试使用window.navigator.onLine上面的相同技术,但也没有用。

有没有人知道如何模拟离线进行Jasmine测试?

3 个答案:

答案 0 :(得分:2)

您没有机会覆盖某些内置属性。虽然使用Object.defineProperty(),但您可以重新配置内置属性。

Jasmine 2.6及更新版

由于Jasmine 2.6(release notes)有spyOnProperty()

这就是间谍Car

的方法
// Horn with generic default
function Horn(sound) {
    this.sound = sound !== undefined ? sound : "Düdelüüüü!";
    this.level = '123dB';
}

Horn.prototype.doTutut = function() {
  return this.sound;
};

// Car using a single generic horn across all Car instances
function Car() {
}
Car.prototype.honk = function() {
    return this.horn.doTutut();
};
Car.prototype.horn = new Horn();

// Mercedes with its own special horn
function Mercedes() {
    Car.call(this);
}
Mercedes.prototype = Object.create(Car.prototype);
Mercedes.prototype.constructor = Mercedes;
Mercedes.prototype.horn = new Horn("Mercedes Honk!");

// Audi with its own special horn
function Audi() {
    Car.call(this);
}
Audi.prototype = Object.create(Car.prototype);
Audi.prototype.constructor = Audi;
Audi.prototype.horn = new Horn("Audi Honk!");

// Usage
var c = new Car();
console.log(c.honk());
var m = new Mercedes();
console.log(m.honk());
var a = new Audi();
console.log(a.honk());

请注意,引用了原型对象navigator.onLine,而不是它的实例beforeEach(function(){ spyOnProperty(Navigator.prototype, 'onLine').and.returnValue(false); });

Jasmine pre 2.6

为浏览器对象构建外观

使用pre Jasmine 2.6,您无法直接监视属性(或属性)。

我建议使用getter方法为这样的浏览器内置创建一个外观。然后,您可以在测试中模拟这些方法以返回您喜欢的内容。

Navigator

在您的代码中:

window.navigator

在你的测试中:

const Browser = (function() {
    return {
        isOnline: function() {
            return navigator.onLine;
        }
    };
})();

执行if (Browser.isOnline()) { // ... } 自己做的事情

如果由于某种原因无法从2.6之前的版本升级,您甚至可以使用Object.defineProperty()Object.getOwnPropertyDescriptor()手动监视。

beforeEach(function(){
    spyOn(Browser, 'isOnline').and.returnValue(false);
});

如果你绝望的话,你甚至可以实现自己的spyOnProperty()反向移动(虽然这超出了这个答案)。

答案 1 :(得分:0)

我有一个类似的问题,但是另外尝试检测浏览器从 offline 状态变为 online 状态时的情况,以便尝试重新连接一个EventSource。

我要测试的代码是:

private startOfflineWatcher(): void {
    const that = this;
    window.addEventListener('offline', () => {
        window.addEventListener('online', () => {
            that.reconnectTimeout();
        });
    });
}

在我的情况下,无法使用spyOnProperty(Navigator.prototype, 'onLine').and.returnValue(false);,因为我必须模拟状态变化。但是,我能够通过简单地将两个新事件调度到window来实现此目的。我现在进行的茉莉花测试如下:

it('should start reconnect when getting online after being offline', () => {
        spyOn<any>(service, 'reconnectTimeout');
        const offlineEvent = new Event('offline');
        const onlineEvent = new Event('online');

        (service as any).startOfflineWatcher();

        window.dispatchEvent(offlineEvent);
        window.dispatchEvent(onlineEvent);

        expect((service as any).reconnectTimeout).toHaveBeenCalled();
    });

取决于用例,这可能比模拟导航器更合适。

答案 2 :(得分:0)

这对我有用

window.navigator['__defineGetter__']('onLine', () => false); // false = OFFLINE

window.navigator['__defineGetter__']('onLine', () => true); // true = ONLINE