diff --git a/injected.html b/injected.html index 59b7695..3c43c2e 100644 --- a/injected.html +++ b/injected.html @@ -5,16 +5,16 @@ (function() { function refreshCSS() { var sheets = [].slice.call(document.getElementsByTagName("link")); - var head = document.getElementsByTagName("head")[0]; for (var i = 0; i < sheets.length; ++i) { var elem = sheets[i]; - head.removeChild(elem); + var parent = elem.parentNode; var rel = elem.rel; + parent.removeChild(elem); if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") { var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, ''); elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf()); } - head.appendChild(elem); + parent.appendChild(elem); } } var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://'; diff --git a/package.json b/package.json index bf39ce3..21b33d6 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ }, "devDependencies": { "eslint": "^5.9.0", + "jsdom": "^16.6.0", "jshint": "^2.9.6", "mocha": "^5.2.0", "supertest": "^3.3.0" diff --git a/test/css.js b/test/css.js new file mode 100644 index 0000000..a9e0e65 --- /dev/null +++ b/test/css.js @@ -0,0 +1,85 @@ +var assert = require('assert'); +var fs = require('fs'); +var jsdom = require('jsdom'); +var path = require('path'); +var request = require('supertest'); +var liveServerRoot = path.join(__dirname, 'data'); +var liveServer = require('..').start({ + root: liveServerRoot, + port: 0, + open: false +}); +var JSDOM = jsdom.JSDOM; +var readFile = fs.readFileSync; +var updateFile = fs.writeFileSync; +var loadDOM = function(res){ + return new JSDOM(res, { + // Enable subresource (, , ...) loading. + resources: 'usable', + // Allow executing the injected script. + runScripts: 'dangerously' + });; +}; + +describe('css refreshing', function(){ + var cssFilepath = path.join(liveServerRoot, 'style.css'); + var originalStyles = readFile(cssFilepath); + + afterEach(function(){ + updateFile(cssFilepath, originalStyles); + }); + + it('should refresh css contained within the element', function(done){ + request(liveServer) + .get('/css-refreshing-body.html') + .expect(200) + .then(function(res) { + /** + * For some reason, the following won't work: + * + * var dom = loadDOM(res.text); + * var querySelectorStyles = function(dom, selector){ + * var window = dom.window; + * var document = window.document; + * var element = document.querySelector(selector); + * var styles = window.getComputedStyle(element); + * + * return styles; + * }; + * + * updateFile(cssFilepath, 'h1 { color: blue; }'); + * assert(querySelectorStyles(dom, 'h1').color, 'blue'); + * + * Not even using a timeout of 5s before the assertion + * (after updating this.timeout(10e3), of course). + * + * It seems that the WebSocket's event is emitted once this + * test finishes because the "CSS change detected" message + * is logged afterwards. + * + * Anyway... the following hack makes the WebSocket's + * "onmessage" listener available on NodeJS to emulate + * the event emitted by LiveServer, + * and creates a property on the updated element + * to detect that the injected script was called on that element. + * + * @TODO Test properly. + */ + var domString = res.text + .replace(/(socket\.onmessage)/, 'window.sendWebSocketMessage = $1') + .replace(/(\.appendChild\(elem\);)/, '$1 elem.refreshed = true;'); + var dom = loadDOM(domString); + var window = dom.window; + var document = window.document; + + updateFile(cssFilepath, 'h1 { color: blue; }'); + window.sendWebSocketMessage({ + data: 'refreshcss' + }); + + assert(document.querySelector('link').refreshed, true); + }) + .then(done) + .catch(done); + }); +}); diff --git a/test/data/css-refreshing-body.html b/test/data/css-refreshing-body.html new file mode 100644 index 0000000..cbed442 --- /dev/null +++ b/test/data/css-refreshing-body.html @@ -0,0 +1,12 @@ + + + + + Live-server Test Page + + + + CSS refreshing + CSS within the body tag is refreshed too. + +
CSS within the body tag is refreshed too.