We are working on a tutorial for the basics of offline first apps, and are using JSDOM with Tape to test our code.
In our code we update the DOM so that a text node changes from saying "online" to "offline" and vice versa by attaching an event listener to the window and listening for the "online"/"offline" events, and navigator.onLine
to initialise the text to online/offline. Like so:
// get the online status element from the DOM
var onlineStatusDom = document.querySelector('.online-status');
// navigator.onLine will be true when online and false when offline. We update the text in the online status element in the dom to reflect the online status from navigator.onLine
if (navigator.onLine) {
onlineStatusDom.innerText = 'online';
} else {
onlineStatusDom.innerText = 'offline';
}
// we use the 'online' and 'offline' events to update the online/offline notification to the user
// in IE8 the offline/online events exist on document.body rather than window, so make sure to reflect that in your code!
window.addEventListener('offline', function(e) {
onlineStatusDom.innerText = 'offline';
});
window.addEventListener('online', function(e) {
onlineStatusDom.innerText = 'online';
});
We want to use JSDOM to test that when offline the offline event fires and our text node updates to say "offline".
JSDOM has a window.navigator.onLine
property, but it is read only, and we can't find a way to change it (always true). It seems that it has the online/offline events as well, but I cannot see how to get them to fire.
How can we simulate going online/offline when testing with node?
There is no provision in JSDOM 11.0.0 (which is the current version as I write this answer) for changing navigator.onLine
or for generating the online
and offline
events.
However, it is possible to take over navigator.onLine
to control it and to generate the events yourself. Here is a proof of concept:
const { JSDOM } = require("jsdom");
const { window } = new JSDOM();
class OnlineController {
constructor(win) {
this.win = win;
this.onLine = win.navigator.onLine;
// Replace the default onLine implementation with our own.
Object.defineProperty(win.navigator.constructor.prototype,
"onLine",
{
get: () => {
return this.onLine;
},
});
}
goOnline() {
const was = this.onLine;
this.onLine = true;
// Fire only on transitions.
if (!was) {
this.fire("online");
}
}
goOffline() {
const was = this.onLine;
this.onLine = false;
// Fire only on transitions.
if (was) {
this.fire("offline");
}
}
fire(event) {
this.win.dispatchEvent(new this.win.Event(event));
}
}
window.addEventListener("offline", function () {
console.log("gone offline");
});
window.addEventListener("online", function () {
console.log("gone online");
});
const cont = new OnlineController(window);
console.log("online?", window.navigator.onLine);
cont.goOffline();
console.log("online?", window.navigator.onLine);
cont.goOnline();
console.log("online?", window.navigator.onLine);
If you run the file, you should get:
online? true
gone offline
online? false
gone online
online? true
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With