UNPKG

spa

Version:

Single-page applications builder with continuous integration, granular updates and loader.

1,211 lines (1,141 loc) 66.8 kB
selenium = require('selenium-standalone') wd = require('wd') chai = require('chai') chaiAsPromised = require("chai-as-promised") chai.use(chaiAsPromised); chai.should() expect = chai.expect assert = chai.assert chaiAsPromised.transferPromiseness = wd.transferPromiseness http = require('http') connect = require("connect") morgan = require('morgan') serveStatic = require('serve-static') mock = require("mock-fs") fs = require("fs") path = require("path") yaml = require("js-yaml") spa = require("../lib") utils = require("./utils") class UrlsLog constructor: -> @_items = [] add: (item) -> @_items.push(item) return clear: -> @_items = [] return get: -> return @_items.slice() describe "WD.js", -> @timeout(20000) DELAY = 200 MALFUNCTION_DELAY = 3000 before -> @urls_log = urls_log = new UrlsLog() @server = selenium() @app = connect() .use morgan("dev") .use (req, res, next) -> if req.url == "/favicon.ico" res.statusCode = 404 res.end() else next() .use (req, res, next) -> urls_log.add(req.url) next() .use serveStatic "/", redirect: true etag: false http.createServer(@app).listen(3332) @browser = wd.promiseChainRemote() .init browserName: 'firefox' #browserName: 'chrome' after (done) -> @browser .quit() .then => @server.kill() @app.removeAllListeners() done() beforeEach -> @old_cwd = process.cwd() process.chdir("/") afterEach -> mock.restore() process.chdir(@old_cwd) it 'should update single file only after manifest regenerated', (done) -> return @browser .then -> system = yaml.safeLoad(""" index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: a.js: | var loader = require("loader"); loader.onApplicationReady = function() { document.title = "version_1"; loader.checkUpdate(); }; loader.onUpdateCompleted = function(event) { setTimeout(location.reload.bind(location), 0) return true }; spa.yaml: | root: "./" manifest: "./manifest.json" index: "./index.html" hosting: "./a.js": "/app/a.js" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .get('http://127.0.0.1:3332/app/') .sleep(3 * DELAY) .title().should.eventually.become("version_1") .refresh() .sleep(2 * DELAY) .title().should.eventually.become("version_1") .then -> content = """ var loader = require("loader"); loader.onApplicationReady = function() { document.title = "version_2"; }; """ fs.writeFileSync("/app/a.js", content) .refresh() .sleep(2 * DELAY) .title().should.eventually.become("version_1") .then -> spa.Builder.from_config("/app/spa.yaml").build() .refresh() .sleep(3 * DELAY) .title().should.eventually.become("version_2") .safeExecute("localforage.clear()") .nodeify(done) it 'should not remove not owning keys from localstorage', (done) -> return @browser .then -> system = yaml.safeLoad(""" index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: a.js: | var loader = require("loader"); loader.onApplicationReady = function() { document.title = "version_1"; }; spa.yaml: | root: "./" manifest: "./manifest.json" index: "./index.html" hosting: "./a.js": "/app/a.js" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .setLocalStorageKey("test_item", "should_not be removed") .get('http://127.0.0.1:3332/app/') .sleep(DELAY) .title().should.eventually.become("version_1") .getLocalStorageKey("test_item").should.become("should_not be removed") .safeExecute("localforage.clear()") .nodeify(done) it 'multiple files loading and updating', (done) -> return @browser .then -> system = yaml.safeLoad(""" index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: d.js: | module.exports = function() { return "d"; }; c.js: | var d = require("./d.js"); module.exports = function() { return "c" + d(); }; b.js: | var c = require("./c.js"); module.exports = function() { return "b" + c(); }; a.js: | var loader = require("loader"); var b = require("./b.js"); loader.onApplicationReady = function() { document.title = "a" + b(); loader.checkUpdate(); }; loader.onUpdateCompleted = function(event) { setTimeout(location.reload.bind(location), 0) return true }; spa.yaml: | root: "./" manifest: "./manifest.json" index: "./index.html" randomize_urls: false hosting: "./(*.js)": "/app/$1" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) utils.mount(system, path.resolve(__dirname, "../tests")) mock(system) spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .then => @urls_log.clear() .get('http://127.0.0.1:3332/app/') .sleep(3 * DELAY) .title().should.eventually.become("abcd") .then => urls = @urls_log.get() expect(urls).to.be.an("Array").with.length(8) expect(urls[0]).to.equal("/app/") expect(urls[1]).to.equal("/app/manifest.json") expect(urls.slice(2, 6)).to.consist([ "/app/a.js", "/app/b.js", "/app/c.js", "/app/d.js", ]) expect(urls[6]).to.equal("/app/") expect(urls[7]).to.equal("/app/manifest.json") .safeExecute("localforage.keys( function(err, keys) { window.forage_keys = keys; } )") .sleep(DELAY) .safeEval("window.forage_keys") .then (keys) => expect(keys.map((key) => key.split(":")[2])).to.consist([ "/app/a.js", "/app/b.js", "/app/c.js", "/app/d.js", ]) .then -> content = """ var d = require("./d.js"); module.exports = function() { return "B" + d(); }; """ fs.writeFileSync("/app/b.js", content) fs.unlinkSync("/app/c.js") spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .then => @urls_log.clear() .get('http://127.0.0.1:3332/app/') .sleep(3 * DELAY) .title().should.eventually.become("aBd") .then => urls = @urls_log.get() expect(urls[0]).to.equal("/app/") expect(urls[1]).to.equal("/app/manifest.json") expect(urls[2]).to.equal("/app/b.js") expect(urls[3]).to.equal("/app/") expect(urls[4]).to.equal("/app/manifest.json") .safeExecute("localforage.keys( function(err, keys) { window.forage_keys = keys; } )") .sleep(DELAY) .safeEval("window.forage_keys") .then (keys) => expect(keys.map((key) => key.split(":")[2])).to.consist([ "/app/a.js", "/app/b.js", "/app/d.js", ]) .safeExecute("localforage.clear()") .nodeify(done) it 'multiple files loading and updating with bundle', (done) -> return @browser .then -> system = yaml.safeLoad(""" index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: d.js: | module.exports = function() { return "d"; }; c.js: | var d = require("./d.js"); module.exports = function() { return "c" + d(); }; b.js: | var c = require("./c.js"); module.exports = function() { return "b" + c(); }; a.js: | var loader = require("loader"); var b = require("./b.js"); loader.onApplicationReady = function() { document.title = "a" + b(); loader.checkUpdate(); }; loader.onUpdateCompleted = function(event) { setTimeout(location.reload.bind(location), 0) return true }; spa.yaml: | root: "./" manifest: "./manifest.json" index: "./index.html" bundle: "./bundle.js" randomize_urls: false excludes: - "./bundle.js" hosting: "./(*.js)": "/app/$1" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) utils.mount(system, path.resolve(__dirname, "../tests")) mock(system) spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .then => @urls_log.clear() .get('http://127.0.0.1:3332/app/') .sleep(3 * DELAY) .title().should.eventually.become("abcd") .then => urls = @urls_log.get() expect(urls).to.be.an("Array").with.length(5) expect(urls[0]).to.equal("/app/") expect(urls[1]).to.equal("/app/manifest.json") expect(urls[2]).to.equal("/app/bundle.js") expect(urls[3]).to.equal("/app/") expect(urls[4]).to.equal("/app/manifest.json") .safeExecute("localforage.keys( function(err, keys) { window.forage_keys = keys; } )") .sleep(DELAY) .safeEval("window.forage_keys") .then (keys) => expect(keys.map((key) => key.split(":")[2])).to.consist([ "/app/a.js", "/app/b.js", "/app/c.js", "/app/d.js", ]) .then -> content = """ var d = require("./d.js"); module.exports = function() { return "B" + d(); }; """ fs.writeFileSync("/app/b.js", content) fs.unlinkSync("/app/c.js") spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .then => @urls_log.clear() .get('http://127.0.0.1:3332/app/') .sleep(3 * DELAY) .title().should.eventually.become("aBd") .then => urls = @urls_log.get() expect(urls[0]).to.equal("/app/") expect(urls[1]).to.equal("/app/manifest.json") expect(urls[2]).to.equal("/app/b.js") expect(urls[3]).to.equal("/app/") expect(urls[4]).to.equal("/app/manifest.json") .safeExecute("localforage.keys( function(err, keys) { window.forage_keys = keys; } )") .sleep(DELAY) .safeEval("window.forage_keys") .then (keys) => expect(keys.map((key) => key.split(":")[2])).to.consist([ "/app/a.js", "/app/b.js", "/app/d.js", ]) .safeExecute("localforage.clear()") .nodeify(done) it 'no manifest file', (done) -> return @browser .then -> system = yaml.safeLoad(""" index.tmpl: | <!DOCTYPE html> <html> <head> <script type="text/javascript"> (function() { var hash_func = <%- inline("./hash/" + hash_name + ".js") %> <%- inline("./localforage.js") %> <%- inline("./loader.js") %> var loader = new Loader({ "version": "<%- version %>", "manifest_location": "<%- manifest_location %>", "prefix": "spa", "hash_name": "<%- hash_name %>", "hash_func": hash_func, }); loader.onUpdateCompleted = function() { document.title = "UpdateCompleted"; }; loader.onNoManifest = function() { document.title = "NoManifest"; loader.checkUpdate(); }; loader.onApplicationReady = function() { document.title = "ApplicationReady"; }; loader.onUpdateFailed = function() { document.title = "UpdateFailed"; }; loader.onUpToDate = function() { document.title = "UpToDate"; }; loader.onEvaluationError = function() { document.title = "EvaluationError"; }; window.onload = function() { loader.load(); } })(); </script> </head> <body> </body> </html> index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: a.js: | var loader = require("loader"); loader.onApplicationReady = function() { document.title = "ClientApplicationReady"; }; spa.yaml: | root: "./" index: "./index.html" manifest: "./manifest.json" assets: index_template: /index.tmpl hosting: "./a.js": "/app/a.js" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) spa.Builder.from_config("/app/spa.yaml").build() fs.unlinkSync("/app/manifest.json") .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .get('http://127.0.0.1:3332/app/') .sleep(3*DELAY) .title().should.eventually.become("UpdateFailed") .safeExecute("localforage.clear()") .nodeify(done) it 'renamed manifest file', (done) -> return @browser .then -> system = yaml.safeLoad(""" index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: a.js: | var loader = require("loader"); loader.onApplicationReady = function() { document.title = "version_4"; }; spa.yaml: | root: "./" index: "./index.html" manifest: "../spa-loader.json" hosting: "./a.js": "/app/a.js" "./../(*.json)": "/$1" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .get('http://127.0.0.1:3332/app/') .sleep(3*DELAY) .title().should.eventually.become("version_4") .safeExecute("localforage.clear()") .nodeify(done) it 'manifest with alternated hash function', (done) -> return @browser .then -> system = yaml.safeLoad(""" index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: a.js: | var loader = require("loader"); loader.onApplicationReady = function() { document.title = "version_5"; }; spa.yaml: | root: "./" index: "./index.html" manifest: "./manifest.json" hash_func: sha256 hosting: "./a.js": "/app/a.js" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .get('http://127.0.0.1:3332/app/') .sleep(3*DELAY) .title().should.eventually.become("version_5") .safeExecute("localforage.clear()") .nodeify(done) it 'building files with BOM', (done) -> return @browser .then -> system = yaml.safeLoad(""" index.tmpl: | <!DOCTYPE html> <html> <head> <script type="text/javascript"> (function() { var hash_func = <%- inline("./hash/" + hash_name + ".js") %> var decoder_func = <%- inline("./decode/" + decoder_name + ".js") %> <%- inline("./localforage.js") %> <%- inline("./loader.js") %> var loader = new Loader({ "version": "<%- version %>", "manifest_location": "<%- manifest_location %>", "prefix": "spa", "hash_name": "<%- hash_name %>", "hash_func": hash_func, "decoder_func": decoder_func, }); loader.onUpdateCompleted = function() { document.title = "UpdateCompleted"; return true; }; loader.onNoManifest = function() { document.title = "NoManifest"; loader.checkUpdate(); }; loader.onApplicationReady = function() { document.title = "ApplicationReady"; }; loader.onUpdateFailed = function() { document.title = "UpdateFailed"; }; loader.onUpToDate = function() { document.title = "UpToDate"; }; loader.onEvaluationError = function() { document.title = "EvaluationError"; }; loader.onModuleDownloadFailed = function(module, event) { document.title = "ModuleDownloadFailed"; }; window.onload = function() { loader.load(); } })(); </script> </head> <body> </body> </html> index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: spa.yaml: | root: "./" index: "./index.html" manifest: "./manifest.json" assets: index_template: /index.tmpl hosting: "./a.js": "/app/a.js" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) content = new Buffer("""\xEF\xBB\xBF// empty""", "ascii") fs.writeFileSync("/app/a.js", content) spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .get('http://127.0.0.1:3332/app/') .sleep(5*DELAY) .title().should.eventually.become("UpdateCompleted") .refresh() .sleep(DELAY) .title().should.eventually.become("ApplicationReady") .safeExecute("localforage.clear()") .nodeify(done) it 'should be same manifest version and loader version', (done) -> return @browser .then => system = yaml.safeLoad(""" index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: a.js: | var loader = require("loader"); loader.onApplicationReady = function() { document.title = "VERSION-" + loader.version; }; spa.yaml: | root: "./" index: "./index.html" manifest: "./manifest.json" hosting: "./a.js": "/app/a.js" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) spa.Builder.from_config("/app/spa.yaml").build() manifest_content = fs.readFileSync("/app/manifest.json", encoding: "utf8") @manifest = JSON.parse(manifest_content) expect(@manifest).to.have.property("version") expect(@manifest.version).to.be.a("String") .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .get('http://127.0.0.1:3332/app/') .sleep(3*DELAY) .title() .then (title) => expect(title).to.equal("VERSION-" + @manifest.version) .safeExecute("localforage.clear()") .nodeify(done) it 'should load a lot of files', (done) -> return @browser .then => system = yaml.safeLoad(""" index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: spa.yaml: | root: "./" index: "./index.html" manifest: "./manifest.json" hosting: "./(*.js)": "/app/$1" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) NUM = 100 for i in [1..NUM] fs.writeFileSync("/app/module_#{i}.js", """ var next = require("./module_#{i+1}"); module.exports = function() { return next() + #{i}; }; """) fs.writeFileSync("/app/module_#{NUM}.js", """ module.exports = function() { return #{NUM}; }; """) fs.writeFileSync("/app/module_0.js", """ var loader = require("loader"); var next = require("./module_1"); loader.onApplicationReady = function() { document.title = next(); }; """) spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .get('http://127.0.0.1:3332/app/') .sleep(30*DELAY) .title().should.eventually.become("5050") .safeExecute("localforage.clear()") .sleep(10 * DELAY) .nodeify(done) it 'should load big files', (done) -> return @browser .then => system = yaml.safeLoad(""" index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: spa.yaml: | root: "./" index: "./index.html" manifest: "./manifest.json" hosting: "./(*.js)": "/app/$1" hash_func: sha256 """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) c = "7" for i in [1..5] c = "(#{c} + #{c})" q = c for i in [1..11] q = "(#{q} + #{q})" NUM = 10 for i in [1..10] fs.writeFileSync("/app/module_#{i}.js", """ var next = require("./module_#{i+1}"); module.exports = function() { return next() + #{c} + "#{q}".length; }; """) fs.writeFileSync("/app/module_#{NUM}.js", """ module.exports = function() { return #{c} + "#{q}".length; }; """) fs.writeFileSync("/app/module_0.js", """ var loader = require("loader"); var next = require("./module_1"); loader.onApplicationReady = function() { document.title = next(); }; """) spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .get('http://127.0.0.1:3332/app/') .sleep(40 * DELAY) .title().should.eventually.become("3934350") .safeExecute("localforage.clear()") .sleep(10 * DELAY) .nodeify(done) it 'building files with wierd names', (done) -> return @browser .then -> system = yaml.safeLoad(""" index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: "[^](). '{}'+!=#$.js": | var loader = require("loader"); loader.onApplicationReady = function() { document.title = "version_6"; }; spa.yaml: | root: "./" manifest: "./manifest.json" index: "./index.html" hosting: "./(*.js)": "/app/$1" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .get('http://127.0.0.1:3332/app/') .sleep(3*DELAY) .title().should.eventually.become("version_6") .safeExecute("localforage.clear()") .nodeify(done) it 'could not break loader', (done) -> return @browser .then -> system = yaml.safeLoad(""" index.tmpl: | <!DOCTYPE html> <html> <head> <script type="text/javascript"> (function() { var hash_func = <%- inline("./hash/" + hash_name + ".js") %> var decoder_func = <%- inline("./decode/" + decoder_name + ".js") %> <%- inline("./localforage.js") %> <%- inline("./loader.js") %> var loader = new Loader({ "version": "<%- version %>", "manifest_location": "<%- manifest_location %>", "prefix": "spa", "hash_name": "<%- hash_name %>", "hash_func": hash_func, "decoder_func": decoder_func, }); loader.onNoManifest = function() { loader.checkUpdate(); }; loader.onUpdateCompleted = function() { setTimeout(location.reload.bind(location), 0) return true; } loader.onModuleBeginDownload = function() { throw Error("HAHA1!"); }; loader.onModuleDownloadProgress = function() { throw Error("HAHA2!"); }; loader.onTotalDownloadProgress = function() { throw Error("HAHA3!"); }; loader.onTotalDownloadProgress = function() { throw Error("HAHA4!"); }; loader.onModuleDownloaded = function() { throw Error("HAHA5!"); }; loader.onEvaluationStarted = function() { throw Error("HAHA6!"); }; loader.onModuleEvaluated = function() { throw Error("HAHA7!"); }; window.onload = function() { loader.load(); } })(); </script> </head> <body> </body> </html> index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: c.js: | module.exports = 1 b.js: | module.exports = require("./c"); a.js: | var b = require("./b"); var loader = require("loader"); loader.onApplicationReady = function() { document.title = "version_7"; }; spa.yaml: | root: "./" index: "./index.html" manifest: "./manifest.json" assets: index_template: /index.tmpl hosting: "./(*.js)": "/app/$1" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .get('http://127.0.0.1:3332/app/') .sleep(3*DELAY) .title().should.eventually.become("version_7") .safeExecute("localforage.clear()") .nodeify(done) it 'malfunction while updating', (done) -> return @browser .then -> system = yaml.safeLoad(""" index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: d.js: | module.exports = function() { return "d"; }; c.js: | var d = require("./d.js"); module.exports = function() { return "c" + d(); }; b.js: | var c = require("./c.js"); module.exports = function() { return "b" + c(); }; a.js: | var loader = require("loader"); var b = require("./b.js"); loader.onApplicationReady = function() { document.title = "a" + b(); loader.checkUpdate(); }; loader.onUpdateCompleted = function(event) { setTimeout(location.reload.bind(location), 0) return true }; spa.yaml: | root: "./" manifest: "./manifest.json" index: "./index.html" randomize_urls: false hosting: "./(*.js)": "/app/$1" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .then -> content = """ var c = require("./c.js"); module.exports = function() { return "bb" + c(); }; """ fs.writeFileSync("/app/b.js", content) content = """var d = require("./d.js"); module.exports = function() { return "cc" + d(); };""" fs.writeFileSync("/app/c.js", content) spa.Builder.from_config("/app/spa.yaml").build() fs.unlinkSync("/app/c.js") .get('http://127.0.0.1:3332/') .sleep(DELAY) .then => @urls_log.clear() .get('http://127.0.0.1:3332/app/') .sleep(3 * DELAY) .then => urls = @urls_log.get() expect(urls).to.be.an("Array").with.length(6) expect(urls[0]).to.equal("/app/") expect(urls[1]).to.equal("/app/manifest.json") expect(urls.slice(2, 6)).to.consist([ "/app/a.js", "/app/b.js", "/app/c.js", "/app/d.js", ]) .elementById("btn-retry").isDisplayed().should.become(false) .sleep(MALFUNCTION_DELAY + 2 * DELAY) .elementById("btn-retry").isDisplayed().should.become(true) .elementById("btn-retry").click() .sleep(MALFUNCTION_DELAY + 2 * DELAY) .elementById("btn-retry").isDisplayed().should.become(true) .then -> content = """var d = require("./d.js"); module.exports = function() { return "cc" + d(); };""" fs.writeFileSync("/app/c.js", content) .then => @urls_log.clear() .elementById("btn-retry").click() .sleep(3 * DELAY) .then => urls = @urls_log.get() expect(urls).to.be.an("Array").with.length(5) expect(urls[0]).to.equal("/app/") expect(urls[1]).to.equal("/app/manifest.json") expect(urls[2]).to.equal("/app/c.js") expect(urls[3]).to.equal("/app/") expect(urls[4]).to.equal("/app/manifest.json") .title().should.eventually.become("abbccd") .safeExecute("localforage.clear()") .nodeify(done) it 'malfunction while evaluating', (done) -> return @browser .then -> system = yaml.safeLoad(""" index.html: | <html> <head> <title></title> </head> <body> <h1>Testing</h1> </body> </html> app: d.js: | module.exports = function() { return "d"; }; c.js: | var d = require("./d.js"); module.exports = function() { return "c" + d(); }; b.js: | var c = require("./c.js"); module.exports = function() { return "b" + c(); }; a.js: | var loader = require("loader"); var b = require("./b.js"); loader.onApplicationReady = function() { document.title = "a" + b(); loader.checkUpdate(); }; loader.onUpdateCompleted = function(event) { setTimeout(location.reload.bind(location), 0) return true }; spa.yaml: | root: "./" manifest: "./manifest.json" index: "./index.html" randomize_urls: false hosting: "./(*.js)": "/app/$1" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) spa.Builder.from_config("/app/spa.yaml").build() .get('http://127.0.0.1:3332/') .sleep(DELAY) .clearLocalStorage() .then => @urls_log.clear() .get('http://127.0.0.1:3332/app/') .sle