UNPKG

spa

Version:

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

1,231 lines (1,097 loc) 67.1 kB
fs = require("fs") mock = require("mock-fs") yaml = require("js-yaml") path = require("path") expect = require("chai").expect spa = require("../lib") utils = require("./utils") crypto = require("crypto") beforeEach -> @old_cwd = process.cwd() process.chdir("/") afterEach -> mock.restore() process.chdir(@old_cwd) describe 'Testing detectives', -> beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: | define({ a: 1 }); b.js: | define(function(require) { return require("./a") }); c.js: | define(function(require, exports, module) { module.exports = require("./b"); }); d.js: | define(["./c"], function(c) { return c; }); e.js: | define("e", ["./d"], function(d) { return d; }); """)) detectiveCJS = require('detective') detectiveAMD = require('detective-amd') it 'should find dependency', -> expect(detectiveAMD(fs.readFileSync("/testimonial/a.js", encoding: "utf8"))).to.deep.equal([]) expect(detectiveAMD(fs.readFileSync("/testimonial/b.js", encoding: "utf8"))).to.deep.equal(['./a']) expect(detectiveAMD(fs.readFileSync("/testimonial/c.js", encoding: "utf8"))).to.deep.equal(['./b']) expect(detectiveAMD(fs.readFileSync("/testimonial/d.js", encoding: "utf8"))).to.deep.equal(['./c']) expect(detectiveAMD(fs.readFileSync("/testimonial/e.js", encoding: "utf8"))).to.deep.equal(['./d']) describe 'Building module with unknown dependency', -> base = -> it 'should report unresolved dependency', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") expect(builder.build.bind(builder)) .to.throw(spa.UnresolvedDependencyError) .that.deep.equals(new spa.UnresolvedDependencyError("./a.js", "/b")) describe 'in CommonJS format', -> base() beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: | var b = require("/b"); spa.yaml: | root: "./" """)) describe 'in AMD format', -> base() beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: | define(["/b"], function(b) {}); spa.yaml: | manifest: manifest.json root: "./" """)) describe 'Building module with external dependency', -> base = -> it 'should report dependency out of scope', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") expect(builder.build.bind(builder)) .to.throw(spa.ExternalDependencyError) .has.properties alias: -> @equals("/b") path: -> @equals("./a.js") describe 'in CommonJS format', -> base() beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: | var b = require("/b"); b.js: | // empty spa.yaml: | root: "./" excludes: - ./b.js """)) describe 'in AMD format', -> base() beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: | define(["/b"], function(b) {}); b.js: | // empty spa.yaml: | root: "./" excludes: - ./b.js """)) describe 'Building module with cyclic dependencies', -> base = -> it 'should report loop in dependencies', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") _loop = new spa.Loop() .prepend("./d.js", "/a") .prepend("./c.js", "/d") .prepend("./b.js", "/c") .prepend("./a.js", "/b") expect(builder.build.bind(builder)) .to.throw(spa.CyclicDependenciesError) .to.have.property("loop") .that.deep.equals(_loop) describe 'in CommonJS format', -> base() beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: | var b = require("/b"); b.js: | var c = require("/c"); c.js: | var d = require("/d"); d.js: | var a = require("/a"); spa.yaml: | root: "./" """)) describe 'in AMD format', -> base() beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: | define(["/b"], function(b) {}); b.js: | define(["/c"], function(c) {}); c.js: | define(["/d"], function(d) {}); d.js: | define(["/a"], function(a) {}); spa.yaml: | root: "./" """)) describe 'Building module with cyclic dependencies and something else', -> base = -> it 'should report only loop', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") _loop = new spa.Loop() .prepend("./e.js", "/c") .prepend("./d.js", "/e") .prepend("./c.js", "/d") expect(builder.build.bind(builder)) .to.throw(spa.CyclicDependenciesError) .to.have.property("loop") .that.deep.equals(_loop) describe 'in CommonJS format', -> base() beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: | // empty b.js: | var a = require("/a"); c.js: | var d = require("/d"); var b = require("/b"); d.js: | var e = require("/e"); var f = require("/f"); var b = require("/b"); e.js: | var c = require("/c"); var f = require("/f"); f.js: | var a = require("/a"); spa.yaml: | root: "./" """)) describe 'in AMD format', -> base() beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: | // empty b.js: | define(["/a"], function(a) {}); c.js: | define(["/d", "/b"], function(d, b) {}); d.js: | define(["/e", "/f", "/b"], function(e, f, b) {}); e.js: | define(["/c", "/f"], function(c, f) {}); f.js: | define(["/a"], function(a) {}); spa.yaml: | root: "./" """)) describe 'Building module with paths rewired', -> base = (type) -> it 'should successfully build', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/manifest.json")).to.be.true manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8")) expect(manifest).to.have.properties modules: -> @that.is.an("Array").with.length(4).and.properties 0: -> @that.has.properties id: -> @that.equals("c") deps: -> @that.deep.equals({}) type: -> @that.equals(type) url: -> @that.equals("http://127.0.0.1:8010/module1/a/c.js") 1: -> @that.has.properties id: -> @that.equals("b") deps: -> @that.deep.equals "./a/c": "c" type: -> @that.equals(type) url: -> @that.equals("http://127.0.0.1:8010/module1/b.js") 2: -> @that.has.properties id: -> @that.equals("d") deps: -> @that.deep.equals "a1/c": "c" type: -> @that.equals(type) url: -> @that.equals("http://127.0.0.1:8010/module2/d.js") 3: -> @that.has.properties id: -> @that.equals("e") deps: -> @that.deep.equals "a1/../b": "b" type: -> @that.equals(type) url: -> @that.equals("http://127.0.0.1:8010/module2/e.js") describe 'in CommonJS format', -> base("cjs") beforeEach -> mock(yaml.safeLoad(""" testimonial: module1: a: c.js: | // because loader is like builtin for browser code var loader = require("loader") b.js: | var ac = require("./a/c"); module2: e.js: | var a1 = require("a1/../b"); d.js: | var a1 = require("a1/c"); spa.yaml: | root: "/testimonial/" extensions: - .js paths: a1: "/module1/a" hosting: "./(**/*.js)": "http://127.0.0.1:8010/$1" manifest: "manifest.json" default_loader: raw """)) describe 'in AMD format', -> base("amd") beforeEach -> mock(yaml.safeLoad(""" testimonial: module1: a: c.js: | define([], function() {}); b.js: | define(["./a/c"], function(ac) {}); module2: e.js: | define(["a1/../b"], function(a1) {}); d.js: | define(["a1/c"], function(a1) {}); spa.yaml: | root: "/testimonial/" extensions: - .js paths: a1: "/module1/a" hosting: "./(**/*.js)": "http://127.0.0.1:8010/$1" manifest: "manifest.json" default_loader: raw """)) describe 'Building module without manifest', -> beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: // empty spa.yaml: | root: "/testimonial/" extensions: - .js """)) it 'should not produce manifest.json', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/manifest.json")).not.to.be.true describe 'Building config with BOM', -> beforeEach -> mock(yaml.safeLoad(""" testimonial: "a.js": // empty """)) content = new Buffer("""\xEF\xBB\xBF\nroot: "/testimonial/"\nmanifest: "manifest.json"\n""", "ascii") fs.writeFileSync("/testimonial/spa.yaml", content) it 'should not produce manifest.json', -> content = fs.readFileSync("/testimonial/spa.yaml") expect(content[0]).to.equals(0xEF) expect(content[1]).to.equals(0xBB) expect(content[2]).to.equals(0xBF) builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/manifest.json")).to.be.true manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8")) expect(manifest).to.have.properties modules: -> @that.is.an("Array").with.length(1).and.properties 0: -> @that.has.not.property("url") describe 'Building module with wierd name', -> beforeEach -> mock(yaml.safeLoad(""" testimonial: "[^]$().'{}'+!=#$.js": // empty spa.yaml: | root: "/testimonial/" manifest: "manifest.json" """)) it 'should not produce manifest.json', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() describe 'Building module with appcache and index', -> beforeEach -> system = yaml.safeLoad(""" testimonial: a.js: "//empty" b.js: "///empty" spa.yaml: | root: "/testimonial/" index: index.html hash_func: md5 appcache: main.appcache cached: - a.js - b.js hosting: "./(**/*.*)": "http://127.0.0.1:8010/$1" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) it 'should produce appcache and index files', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/index.html")).to.be.true expect(fs.readFileSync("/testimonial/index.html", "utf8")) .to.include.string('manifest.json') .to.include.string('<html manifest') expect(fs.existsSync("/testimonial/main.appcache")).to.be.true expect(fs.readFileSync("/testimonial/main.appcache", "utf8")) .to.include.string(crypto.createHash('md5').update("//empty").digest("hex")) .to.include.string('http://127.0.0.1:8010/a.js') .to.include.string(crypto.createHash('md5').update("///empty").digest("hex")) .to.include.string('http://127.0.0.1:8010/b.js') .to.include.string('http://127.0.0.1:8010/index.html') describe 'Building renamed manifest', -> beforeEach -> system = yaml.safeLoad(""" testimonial: a.js: // empty spa.yaml: | root: "/testimonial/" index: index.html manifest: "../spa-loader.json" cached: - a.js hosting: "./(**/*.*)": "http://127.0.0.1:8010/$1" "./../(*.json)": "/$1" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) it 'should produce index and manifest files', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/index.html")).to.be.true expect(fs.readFileSync("/testimonial/index.html", "utf8")) .to.include.string('spa-loader.json') expect(fs.existsSync("/spa-loader.json")).to.be.true manifest = JSON.parse(fs.readFileSync("/spa-loader.json", encoding: "utf8")) expect(manifest).to.have.properties version: -> @to.be.a("String") modules: -> @to.be.an("Array").with.length(1).and.properties 0: -> @that.has.properties id: -> @that.equals("a") deps: -> @that.deep.equals({}) type: -> @that.equals("cjs") hash: -> @that.equals("1007f6da5acf8cc2643274276079bc3e") url: -> @that.equals("http://127.0.0.1:8010/a.js") expect(manifest).not.to.have.property("decoder_func") expect(manifest.modules[0]).not.to.have.property("decoding") describe 'Building mixed-formats modules', -> beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: // empty b.js: | var a = require("/a"); c.js: | define(["/b"], function(b) {}); spa.yaml: | root: "/testimonial/" extensions: - .js manifest: "manifest.json" default_loader: junk """)) it 'should successfully build', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/manifest.json")).to.be.true manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8")) expect(manifest).to.have.properties modules: -> @that.is.an("Array").with.length(3).and.properties 0: -> @that.has.properties id: -> @that.equals("a") deps: -> @that.deep.equals({}) type: -> @that.equals("junk") 1: -> @that.has.properties id: -> @that.equals("b") deps: -> @that.deep.equals "/a": "a" type: -> @that.equals("cjs") 2: -> @that.has.properties id: -> @that.equals("c") deps: -> @that.deep.equals "/b": "b" type: -> @that.equals("amd") expect(manifest).to.have.properties modules: -> @that.has.properties 0: -> @that.has.not.property("url") 1: -> @that.has.not.property("url") 2: -> @that.has.not.property("url") describe 'Building module with different hash function', -> hashes = md5: "1007f6da5acf8cc2643274276079bc3e" ripemd160: "9eb50257b88aaf4f2dea2ab99108fb631845ed51" sha1: "da03efe4b6962871b780b3bfd5794325d11ab193" sha224: "48125fcd2addc22961b026524fea1c56cf4e06c2be12e98bf1c971c0" sha256: "ebe41801037df7a354b168593f4545e58fd4a15dc7c2252cf5c0e7f5a799c048" sha384: "70b68b5fc3774ec4e7d68d4db2f71d81548a486687e5e1c46314a8e9e79d104f6b6c52f19b6629df3b1d300a0ce7e713" sha512: "333cbe76073d26fdb480d005e01ba2de20ed781ca38d9c1e25adb12d5f0cb92c5b2bfeaeb63b3ae72683aa28a809732dab4055273781f5f4a3af25105128a228" sha3: "c37785c2a1ad86b547ec92f840f19a6ea19db65ed02b7307f45ceca8b1882540240c07e5defa72d931c149578f5e48b0cb7d211b69dca14184560a19afd46441" test = (hash_name, hash_value) -> it """should compute valid `#{hash_name}` hash""", -> mock(yaml.safeLoad(""" testimonial: a.js: // empty spa.yaml: | root: "/testimonial/" manifest: "manifest.json" hash_func: #{hash_name} hosting: "./(**/*.*)": "http://127.0.0.1:8010/$1" """)) builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/manifest.json")).to.be.true manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8")) expect(manifest).to.have.properties modules: -> @that.is.an("Array").with.length(1).and.has.properties 0: -> @that.has.properties id: -> @that.equals("a") hash: -> @that.equals(hash_value) for hash_name, hash_value of hashes test(hash_name, hash_value) describe 'Building with encoder', -> beforeEach -> system = yaml.safeLoad(""" build: placeholder.txt: empty testimonial: 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 b = require("./b.js"); module.exports = function() { return "a" + b(); }; spa.yaml: | pretty: true root: "/testimonial/" manifest: "manifest.json" hosting: "./../build/bundle.js": "http://127.0.0.1:8010/bundle.js" "./(**/*.*)": "http://127.0.0.1:8010/$1" bundle: "/build/bundle.js" coding_func: name: aes-gcm password: babuka iter: 1000 ks: 128 ts: 128 copying: "./(**/*.*)": "/build/$1" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) sandbox = ArrayBuffer: Object.freeze(ArrayBuffer) Buffer: Object.freeze(Buffer) Uint8Array: Object.freeze(Uint8Array) vm = require("vm") eval_file = (p) -> return vm.runInNewContext(fs.readFileSync(path.resolve(__dirname, p), "utf8"), sandbox) decoder = eval_file("../lib/assets/decode/aes-gcm.js") it 'should manifest and encrypted files', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/manifest.json")).to.be.true manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8")) expect(manifest) .to.have.property("decoder_func") .that.equals("aes-gcm") expect(fs.existsSync("/build/bundle.js")).to.be.true expect(fs.existsSync("/build/a.js")).to.be.true expect(fs.existsSync("/build/b.js")).to.be.true expect(fs.existsSync("/build/c.js")).to.be.true expect(fs.existsSync("/build/d.js")).to.be.true expect(manifest).to.have.properties bundle: -> @that.has.properties url: -> @that.is.a("String").and.equals("http://127.0.0.1:8010/bundle.js") modules: -> @that.is.an("Array").with.length(4).and.has.has.properties 0: -> @that.has.properties decoding: -> @that.has.properties cipher: -> @that.is.a("String").and.equals("aes") mode: -> @that.is.a("String").and.equals("gcm") iter: -> @that.is.a("Number").and.equals(1000) ks: -> @that.is.a("Number").and.equals(128) ts: -> @that.is.a("Number").and.equals(128) auth: -> @that.is.a("String") salt: -> @that.is.a("String").with.length(16) iv: -> @that.is.a("String").with.length(32) loader = options: password: "babuka" expect(decoder(fs.readFileSync("/build/d.js"), manifest.modules[0], loader)) .to.equal(fs.readFileSync("/testimonial/d.js", encoding: "utf8")) expect(decoder(fs.readFileSync("/build/c.js"), manifest.modules[1], loader)) .to.equal(fs.readFileSync("/testimonial/c.js", encoding: "utf8")) expect(decoder(fs.readFileSync("/build/b.js"), manifest.modules[2], loader)) .to.equal(fs.readFileSync("/testimonial/b.js", encoding: "utf8")) expect(decoder(fs.readFileSync("/build/a.js"), manifest.modules[3], loader)) .to.equal(fs.readFileSync("/testimonial/a.js", encoding: "utf8")) describe 'Building updates with encoding', -> beforeEach -> system = yaml.safeLoad(""" build: placeholder.txt: empty testimonial: a.js: module.exports = function() { return "a1"; }; spa.yaml: | pretty: true root: "/testimonial/" manifest: "manifest.json" hosting: "./(**/*.*)": "http://127.0.0.1:8010/$1" coding_func: name: aes-gcm password: babuka iter: 1000 ks: 128 ts: 128 copying: "./(**/*.*)": "/build/$1" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) it 'should manifest and encrypted files', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/manifest.json")).to.be.true manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8")) hash1 = manifest.modules[0].hash expect(manifest) .to.have.property("decoder_func") .that.equals("aes-gcm") expect(fs.existsSync("/build/a.js")).to.be.true builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8")) hash2 = manifest.modules[0].hash expect(hash1).to.equal(hash2) fs.writeFileSync("/testimonial/a.js", """module.exports = function() { return "a2"; };"""); builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8")) hash3 = manifest.modules[0].hash expect(hash3).not.to.equal(hash2) describe 'fix for #72: copier cannot create dirs', -> beforeEach -> system = yaml.safeLoad(""" testimonial: a.js: module.exports = function() { return "a1"; }; spa.yaml: | pretty: true root: "/testimonial/" manifest: "manifest.json" hosting: "./(**/*.*)": "http://127.0.0.1:8010/$1" coding_func: name: aes-gcm password: babuka iter: 1000 ks: 128 ts: 128 copying: "./(**/*.*)": "/build/encoded/$1" """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) it 'should manifest and encrypted files', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/manifest.json")).to.be.true manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8")) hash1 = manifest.modules[0].hash expect(manifest) .to.have.property("decoder_func") .that.equals("aes-gcm") expect(fs.existsSync("/build/encoded/a.js")).to.be.true describe 'fix for #71: copier path is not relative to build path', -> beforeEach -> system = yaml.safeLoad(""" testimonial: source: a.js: | var b = require("b"); module.exports = function() { return "a" + b; }; bad.yaml: | pretty: true grab: true root: "." manifest: "../build/manifest.json" hosting: "./(**/*.*)": "http://127.0.0.1:8010/$1" coding_func: name: aes-gcm password: babuka iter: 1000 ks: 128 ts: 128 copying: "./(**/*.*)": "../build/$1" good.yaml: | pretty: true grab: true root: "." manifest: "../build/manifest.json" hosting: "./(**/*.*)": "http://127.0.0.1:8010/$1" coding_func: name: aes-gcm password: babuka iter: 1000 ks: 128 ts: 128 copying: "./../node_modules/(**/*.*)": "../build/node_modules/$1" "./(**/*.*)": "../build/source/$1" node_modules: b: index.js: | module.exports = "b"; """) utils.mount(system, path.resolve(__dirname, "../lib/assets")) mock(system) it 'should not damage source files and generate output', -> hash_a_1 = crypto.createHash('md5').update(fs.readFileSync("/testimonial/source/a.js")).digest("hex") hash_b_1 = crypto.createHash('md5').update(fs.readFileSync("/testimonial/node_modules/b/index.js")).digest("hex") builder = spa.Builder.from_config("/testimonial/source/good.yaml") builder.build() expect(fs.existsSync("/testimonial/build/manifest.json")).to.be.true hash_a_2 = crypto.createHash('md5').update(fs.readFileSync("/testimonial/source/a.js")).digest("hex") hash_b_2 = crypto.createHash('md5').update(fs.readFileSync("/testimonial/node_modules/b/index.js")).digest("hex") expect(hash_a_1).to.be.equal(hash_a_2, "Source file `a` was damaged!") expect(hash_b_1).to.be.equal(hash_b_2, "Source file `b` was damaged!") expect(fs.existsSync("/testimonial/build/source/a.js")).to.be.true expect(fs.existsSync("/testimonial/build/node_modules/b/index.js")).to.be.true it 'should overwrite source files', -> hash_a_1 = crypto.createHash('md5').update(fs.readFileSync("/testimonial/source/a.js")).digest("hex") hash_b_1 = crypto.createHash('md5').update(fs.readFileSync("/testimonial/node_modules/b/index.js")).digest("hex") builder = spa.Builder.from_config("/testimonial/source/bad.yaml") builder.build() expect(fs.existsSync("/testimonial/build/manifest.json")).to.be.true hash_a_2 = crypto.createHash('md5').update(fs.readFileSync("/testimonial/source/a.js")).digest("hex") hash_b_2 = crypto.createHash('md5').update(fs.readFileSync("/testimonial/node_modules/b/index.js")).digest("hex") expect(hash_a_1).to.be.equal(hash_a_2, "Source file `a` was damaged!") expect(hash_b_1).not.to.be.equal(hash_b_2, "Source file `b` was not damaged!") expect(fs.existsSync("/testimonial/source/a.js")).to.be.true describe 'Building modules with syntax errors', -> beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: var 55; spa.yaml: | root: "/testimonial/" extensions: - .js manifest: "manifest.json" default_loader: junk """)) it 'should successfully build', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") expect(builder.build.bind(builder)) .to.throw(spa.ModuleTypeError) .that.has.property("path") .that.equals(path.resolve("/testimonial/a.js")) describe 'Building modules with dependency from node_modules', -> beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: var m1 = require("m1"); var m2 = require("m2"); console.log(m1() + m2()); node_modules: m1: node_modules: m11: other.js: //empty index.js: module.exports = function() { return "m2"; } lib: other.js: //empty main.js: var m11 = require("m11"); module.exports = function() { return "m1"; } package.json: | { "name": "m1", "main": "lib/main.js" } m2: lib: other.js: //empty main.js: module.exports = function() { return "m2"; } package.json: | { "name": "m2", "main": "lib/main.js" } spa.yaml: | pretty: true root: "/testimonial/" hosting: "./(**/*.*)": "http://127.0.0.1:8010/$1" extensions: - .js excludes: - "./node_modules/**" manifest: "manifest.json" grab: true default_loader: junk """)) it 'should successfully build', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/manifest.json")).to.be.true manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8")) expect(manifest).to.have.properties modules: -> @that.is.an("Array").with.length(4).and.has.properties 0: -> @that.has.properties id: -> @that.equals("lib_main") deps: -> @that.deep.equals({}) type: -> @that.equals("cjs") url: -> @that.equals("http://127.0.0.1:8010/node_modules/m2/lib/main.js") 1: -> @that.has.properties id: -> @that.equals("m11") deps: -> @that.deep.equals({}) type: -> @that.equals("cjs") url: -> @that.equals("http://127.0.0.1:8010/node_modules/m1/node_modules/m11/index.js") 2: -> @that.has.properties id: -> @that.equals("main") deps: -> @that.deep.equals "m11": "m11" type: -> @that.equals("cjs") url: -> @that.equals("http://127.0.0.1:8010/node_modules/m1/lib/main.js") 3: -> @that.has.properties id: -> @that.equals("a") deps: -> @that.deep.equals "m1": "main" "m2": "lib_main" type: -> @that.equals("cjs") url: -> @that.equals("http://127.0.0.1:8010/a.js") describe 'Building modules with inexistent dependency from node_modules', -> beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: var m1 = require("m1"); node_modules: m1: empty.txt: placeholder spa.yaml: | pretty: true root: "/testimonial/" hosting: "./(**/*.*)": "http://127.0.0.1:8010/$1" extensions: - .js excludes: - "./node_modules/**" manifest: "manifest.json" grab: true default_loader: junk """)) it 'should report unresolved dependency', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") expect(builder.build.bind(builder)) .to.throw(spa.UnresolvedDependencyError) .that.deep.equals(new spa.UnresolvedDependencyError("./a.js", "m1")) describe 'Building modules with dependency from node_modules (multifile module)', -> beforeEach -> mock(yaml.safeLoad(""" testimonial: lib: a.js: | var b = require("b"); node_modules: b: index.js: | var c = require("./c"); c.js: | module.exports = 1; spa.yaml: | pretty: true root: "/testimonial/" hosting: "./(**/*.*)": "http://127.0.0.1:8010/$1" extensions: - .js excludes: - "./node_modules/**" manifest: "manifest.json" grab: true default_loader: junk """)) it 'should successfully build', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/manifest.json")).to.be.true manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8")) expect(manifest).to.have.properties modules: -> @that.is.an("Array").with.length(3).and.has.properties 0: -> @that.has.properties id: -> @that.equals("c") deps: -> @that.deep.equals({}) type: -> @that.equals("cjs") url: -> @that.equals("http://127.0.0.1:8010/node_modules/b/c.js") 1: -> @that.has.properties id: -> @that.equals("b") deps: -> @that.deep.equals "./c": "c" type: -> @that.equals("cjs") url: -> @that.equals("http://127.0.0.1:8010/node_modules/b/index.js") 2: -> @that.has.properties id: -> @that.equals("a") deps: -> @that.deep.equals "b": "b" type: -> @that.equals("cjs") url: -> @that.equals("http://127.0.0.1:8010/lib/a.js") describe 'Building modules with dependency from node_modules (import from the deep)', -> beforeEach -> mock(yaml.safeLoad(""" testimonial: lib: a.js: | var b = require("b"); node_modules: b: index.js: | var c = require("c"); node_modules: c: index.js: | var d = require("d"); node_modules: d: index.js: | var e = require("e"); e: index.js: | module.exports = 1; spa.yaml: | pretty: true root: "/testimonial/" hosting: "./(**/*.*)": "http://127.0.0.1:8010/$1" extensions: - .js excludes: - "./node_modules/**" manifest: "manifest.json" grab: true default_loader: junk """)) it 'should successfully build', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/manifest.json")).to.be.true manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8")) expect(manifest).to.have.properties modules: -> @that.is.an("Array").with.length(5).and.has.properties 0: -> @that.has.properties id: -> @that.equals("e") deps: -> @that.deep.equals({}) type: -> @that.equals("cjs") url: -> @that.equals("http://127.0.0.1:8010/node_modules/e/index.js") 1: -> @that.has.properties id: -> @that.equals("d") deps: -> @that.deep.equals "e": "e" type: -> @that.equals("cjs") url: -> @that.equals("http://127.0.0.1:8010/node_modules/b/node_modules/c/node_modules/d/index.js") 2: -> @that.has.properties id: -> @that.equals("c") deps: -> @that.deep.equals "d": "d" type: -> @that.equals("cjs") url: -> @that.equals("http://127.0.0.1:8010/node_modules/b/node_modules/c/index.js") 3: -> @that.has.properties id: -> @that.equals("b") deps: -> @that.deep.equals "c": "c" type: -> @that.equals("cjs") url: -> @that.equals("http://127.0.0.1:8010/node_modules/b/index.js") 4: -> @that.has.properties id: -> @that.equals("a") deps: -> @that.deep.equals "b": "b" type: -> @that.equals("cjs") url: -> @that.equals("http://127.0.0.1:8010/lib/a.js") describe 'Remaping standart-like modules inside dependencies from node_modules', -> beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: var uuid = require("node-uuid"); console.log(uuid.v4()); node_modules: node-uuid: uuid.js: var crypto = require("crypto"); module.exports.v4 = function(data) { return "blah"; } package.json: | { "name": "node-uuid", "main": "./uuid.js" } crypto-replacement: index.js: // blah spa.yaml: | pretty: true root: "/testimonial/" hosting: "./(**/*.*)": "http://127.0.0.1:8010/$1" extensions: - .js excludes: - "./node_modules/**" manifest: "manifest.json" grab: true default_loader: junk paths: crypto: "crypto-replacement" """)) it 'should successfully build', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/manifest.json")).to.be.true manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8")) describe 'Hosting output', -> beforeEach -> mock(yaml.safeLoad(""" testimonial: a.js: var m1 = require("m1"); var m2 = require("m2"); console.log(m1() + m2()); node_modules: m1: node_modules: m11: other.js: //empty index.js: module.exports = function() { return "m2"; } lib: other.js: //empty main.js: var m11 = require("m11"); module.exports = function() { return "m1"; } package.json: | { "name": "m1", "main": "lib/main.js" } m2: lib: other.js: //empty main.js: module.exports = function() { return "m2"; } package.json: | { "name": "m2", "main": "lib/main.js" } spa.yaml: | pretty: true root: "/testimonial/" hosting: "./(**/*.*)": "$1" hosting_map: "hosting.json" extensions: - .js excludes: - "./node_modules/**" grab: true default_loader: junk """)) it 'should output hosting structure', -> builder = spa.Builder.from_config("/testimonial/spa.yaml") builder.build() expect(fs.existsSync("/testimonial/hosting.json")).to.be.true hosting = JSON.parse(fs.readFileSync("/testimonial/hosting.json", encoding: "utf8")) expect(hosting).to.have.properties version: -> @that.is.a("String") files: -> @that.deep.equals "node_modules/m2/lib/main.js": "./node_modules/m2/lib/main.js" "node_modules/m1/node_modules/m11/index.js": "./node_modules/m1/node_modules/m11/index.js" "node_modules/m1/lib/main.js": "./node_modules/m1/lib/main.js" "a.js": "./a.js" describe 'Hosting output with encoder', -> beforeEach -> system = yaml.safeLoad(""" build: placeholder.txt: empty testimonial: d.js: | module.exports = function() { retur