问题
I have a javascript function which is supposed to behave differently when offline than online as a safeguard. I would like to have a Jasmine unit test which tests the function in both offline and online modes - e.g.,
// 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();
});
});
However, I am unable to fake the value of navigator.onLine
. In my before
, I also tried:
navigator = {
'onLine': false
}
This didn't work either. To be thorough, I tried the same techniques above with window.navigator.onLine
and that also didn't work.
Does anyone know how to mock being offline for a Jasmine test?
回答1:
You have no chance to overwrite some built in properties. Though with Object.defineProperty() you can reconfigure builtin properties.
Jasmine 2.6 and newer
Since Jasmine 2.6 (release notes) there is spyOnProperty().
This is how you would spy navigator.onLine
:
beforeEach(function(){
spyOnProperty(Navigator.prototype, 'onLine').and.returnValue(false);
});
Note that the prototype object Navigator
is referenced, not it's instance window.navigator
.
Jasmine pre 2.6
Build a facade for browser objects
With pre Jasmine 2.6 you can't spy attributes (or properties) directly.
I'd suggest to create a facade for such browser builtins using getter methods. Then you can mock those methods in your tests to return what you like.
const Browser = (function() {
return {
isOnline: function() {
return navigator.onLine;
}
};
})();
In your code:
if (Browser.isOnline()) {
// ...
}
In your test:
beforeEach(function(){
spyOn(Browser, 'isOnline').and.returnValue(false);
});
Do what spyOnProperty()
does on your own
If you cannot upgrade from a pre 2.6 version for some reason, you could even spy manually by utilizing Object.defineProperty() and Object.getOwnPropertyDescriptor().
var onlineState,
origOnLineProp;
beforeEach(function() {
// Remember original config
origOnLineProp = Object.getOwnPropertyDescriptor(Navigator.prototype, "onLine");
onlineState = true;
// New behavior
Object.defineProperty(Navigator.prototype, "onLine", {
enumerable: origOnLineProp.enumerable,
configurable: origOnLineProp.configurable,
get: function() { return onlineState }
});
});
it("...", function() {
onlineState = false;
expect("code").toBe("correctly functioning in offline mode");
});
afterEach(function() {
// Restore original behavior
Object.defineProperty(Navigator.prototype, "onLine", {
enumerable: origOnLineProp.enumerable,
configurable: origOnLineProp.configurable,
get: origOnLineProp.get
});
});
You could even implement your own spyOnProperty()
backport if you're desperate (that's beyond this answer though).
来源:https://stackoverflow.com/questions/41150475/how-to-fake-being-offline-in-jasmine