From 73ed9195ce02240da9a4ec342cd266ec07375f4f Mon Sep 17 00:00:00 2001 From: Dat Vong Date: Thu, 28 Jan 2021 16:14:50 -0800 Subject: [PATCH] more tests for xarc-subapp (#1801) --- .../xarc-subapp/test/fixtures/assets.json | 3 + packages/xarc-subapp/test/fixtures/stats.json | 400 ++++++++++++++++++ .../test/spec/node/init-context.spec.ts | 55 +++ .../test/spec/node/init-v2.spec.ts | 209 +++++++++ .../xarc-subapp/test/spec/node/utils.spec.ts | 216 +++++----- 5 files changed, 782 insertions(+), 101 deletions(-) create mode 100644 packages/xarc-subapp/test/fixtures/assets.json create mode 100644 packages/xarc-subapp/test/fixtures/stats.json create mode 100644 packages/xarc-subapp/test/spec/node/init-context.spec.ts create mode 100644 packages/xarc-subapp/test/spec/node/init-v2.spec.ts diff --git a/packages/xarc-subapp/test/fixtures/assets.json b/packages/xarc-subapp/test/fixtures/assets.json new file mode 100644 index 0000000000..b7b98fb635 --- /dev/null +++ b/packages/xarc-subapp/test/fixtures/assets.json @@ -0,0 +1,3 @@ +{ + "poc1.subapp-home.style.5faa52f5a3012ca195e2.css": "AE1234.css" +} diff --git a/packages/xarc-subapp/test/fixtures/stats.json b/packages/xarc-subapp/test/fixtures/stats.json new file mode 100644 index 0000000000..bbba3062ed --- /dev/null +++ b/packages/xarc-subapp/test/fixtures/stats.json @@ -0,0 +1,400 @@ +{ + "assetsByChunkName": { + "subapp-demo1": [ + "poc1.subapp-demo1.bundle.ad4e057b192750300507.js", + "../map/poc1.subapp-demo1.bundle.ad4e057b192750300507.js.map" + ], + "vendors~subapp-home~subapp-static": [ + "poc1.vendors~subapp-home~subapp-static.bundle.6e127ca81fd5be4d605b.js", + "../map/poc1.vendors~subapp-home~subapp-static.bundle.6e127ca81fd5be4d605b.js.map" + ], + "main": [ + "poc1.main.bundle.2ce93434dd0e0b9f6d2e.js", + "../map/poc1.main.bundle.2ce93434dd0e0b9f6d2e.js.map" + ], + "subapp-demo3": [ + "poc1.subapp-demo3.bundle.abec5b8087976c84f1f7.js", + "../map/poc1.subapp-demo3.bundle.abec5b8087976c84f1f7.js.map" + ], + "subapp-demo4": [ + "poc1.subapp-demo4.bundle.6a5771dedb5432de0bc9.js", + "../map/poc1.subapp-demo4.bundle.6a5771dedb5432de0bc9.js.map" + ], + "subapp-home": [ + "poc1.subapp-home.style.5faa52f5a3012ca195e2.css", + "poc1.subapp-home.bundle.1eb7ac0b24ebcd8281bc.js", + "../map/poc1.subapp-home.bundle.1eb7ac0b24ebcd8281bc.js.map" + ], + "subapp-static": [ + "poc1.subapp-static.style.5faa52f5a3012ca195e2.css", + "poc1.subapp-static.bundle.2d5a97f8cc7cb8bcc28c.js", + "../map/poc1.subapp-static.bundle.2d5a97f8cc7cb8bcc28c.js.map" + ], + "vendors~subapp-demo4": [ + "poc1.vendors~subapp-demo4.bundle.c27ec4a0bdc64599254c.js", + "../map/poc1.vendors~subapp-demo4.bundle.c27ec4a0bdc64599254c.js.map" + ] + }, + "assets": [ + { + "name": "../map/poc1.main.bundle.2ce93434dd0e0b9f6d2e.js.map", + "size": 428263, + "chunks": [ + 2 + ], + "chunkNames": [ + "main" + ], + "info": { + "development": true + }, + "emitted": false + }, + { + "name": "../map/poc1.subapp-demo1.bundle.ad4e057b192750300507.js.map", + "size": 1441, + "chunks": [ + 0 + ], + "chunkNames": [ + "subapp-demo1" + ], + "info": { + "development": true + }, + "emitted": false + }, + { + "name": "../map/poc1.subapp-demo3.bundle.abec5b8087976c84f1f7.js.map", + "size": 1978, + "chunks": [ + 3 + ], + "chunkNames": [ + "subapp-demo3" + ], + "info": { + "development": true + }, + "emitted": false + }, + { + "name": "../map/poc1.subapp-demo4.bundle.6a5771dedb5432de0bc9.js.map", + "size": 2688, + "chunks": [ + 4 + ], + "chunkNames": [ + "subapp-demo4" + ], + "info": { + "development": true + }, + "emitted": false + }, + { + "name": "../map/poc1.subapp-home.bundle.1eb7ac0b24ebcd8281bc.js.map", + "size": 7923, + "chunks": [ + 5 + ], + "chunkNames": [ + "subapp-home" + ], + "info": { + "development": true + }, + "emitted": false + }, + { + "name": "../map/poc1.subapp-static.bundle.2d5a97f8cc7cb8bcc28c.js.map", + "size": 9811, + "chunks": [ + 6, + 5 + ], + "chunkNames": [ + "subapp-static" + ], + "info": { + "development": true + }, + "emitted": false + }, + { + "name": "../map/poc1.vendors~subapp-demo4.bundle.c27ec4a0bdc64599254c.js.map", + "size": 137012, + "chunks": [ + 7 + ], + "chunkNames": [ + "vendors~subapp-demo4" + ], + "info": { + "development": true + }, + "emitted": false + }, + { + "name": "../map/poc1.vendors~subapp-home~subapp-static.bundle.6e127ca81fd5be4d605b.js.map", + "size": 242935, + "chunks": [ + 1 + ], + "chunkNames": [ + "vendors~subapp-home~subapp-static" + ], + "info": { + "development": true + }, + "emitted": false + }, + { + "name": "../subapps.json", + "size": 650, + "chunks": [], + "chunkNames": [], + "info": {}, + "emitted": false + }, + { + "name": "2b7ac2d4ff91cca5b9c8e742eda58b24.png", + "size": 5402, + "chunks": [], + "chunkNames": [], + "info": {}, + "emitted": false + }, + { + "name": "poc1.main.bundle.2ce93434dd0e0b9f6d2e.js", + "size": 167898, + "chunks": [ + 2 + ], + "chunkNames": [ + "main" + ], + "info": { + "immutable": true + }, + "emitted": false + }, + { + "name": "poc1.subapp-demo1.bundle.ad4e057b192750300507.js", + "size": 772, + "chunks": [ + 0 + ], + "chunkNames": [ + "subapp-demo1" + ], + "info": { + "immutable": true + }, + "emitted": false + }, + { + "name": "poc1.subapp-demo3.bundle.abec5b8087976c84f1f7.js", + "size": 976, + "chunks": [ + 3 + ], + "chunkNames": [ + "subapp-demo3" + ], + "info": { + "immutable": true + }, + "emitted": false + }, + { + "name": "poc1.subapp-demo4.bundle.6a5771dedb5432de0bc9.js", + "size": 1416, + "chunks": [ + 4 + ], + "chunkNames": [ + "subapp-demo4" + ], + "info": { + "immutable": true + }, + "emitted": false + }, + { + "name": "poc1.subapp-home.bundle.1eb7ac0b24ebcd8281bc.js", + "size": 3494, + "chunks": [ + 5 + ], + "chunkNames": [ + "subapp-home" + ], + "info": { + "immutable": true + }, + "emitted": false + }, + { + "name": "poc1.subapp-home.style.5faa52f5a3012ca195e2.css", + "size": 956, + "chunks": [ + 5 + ], + "chunkNames": [ + "subapp-home" + ], + "info": { + "immutable": true + }, + "emitted": false + }, + { + "name": "poc1.subapp-static.bundle.2d5a97f8cc7cb8bcc28c.js", + "size": 4280, + "chunks": [ + 6, + 5 + ], + "chunkNames": [ + "subapp-static" + ], + "info": { + "immutable": true + }, + "emitted": false + }, + { + "name": "poc1.subapp-static.style.5faa52f5a3012ca195e2.css", + "size": 956, + "chunks": [ + 6, + 5 + ], + "chunkNames": [ + "subapp-static" + ], + "info": { + "immutable": true + }, + "emitted": false + }, + { + "name": "poc1.vendors~subapp-demo4.bundle.c27ec4a0bdc64599254c.js", + "size": 39460, + "chunks": [ + 7 + ], + "chunkNames": [ + "vendors~subapp-demo4" + ], + "info": { + "immutable": true + }, + "emitted": false + }, + { + "name": "poc1.vendors~subapp-home~subapp-static.bundle.6e127ca81fd5be4d605b.js", + "size": 41012, + "chunks": [ + 1 + ], + "chunkNames": [ + "vendors~subapp-home~subapp-static" + ], + "info": { + "immutable": true + }, + "emitted": false + } + ], + "entrypoints": { + "main": [ + 2 + ] + }, + "chunks": [ + { + "id": 0, + "hash": "cd4a79e97a70427a951f", + "names": [ + "subapp-demo1" + ], + "entry": false, + "initial": false, + "rendered": true + }, + { + "id": 1, + "hash": "a8fcca25d04ca3bc26ab", + "names": [ + "vendors~subapp-home~subapp-static" + ], + "entry": false, + "initial": false, + "rendered": true, + "reason": "split chunk (cache group: vendors) (name: vendors~subapp-home~subapp-static)" + }, + { + "id": 2, + "hash": "52f5bd6e802cf8cad4b4", + "names": [ + "main" + ], + "entry": true, + "initial": true, + "rendered": true + }, + { + "id": 3, + "hash": "d71b2f786849b4e35ac0", + "names": [ + "subapp-demo3" + ], + "entry": false, + "initial": false, + "rendered": true + }, + { + "id": 4, + "hash": "24466bb6939de709516c", + "names": [ + "subapp-demo4" + ], + "entry": false, + "initial": false, + "rendered": true + }, + { + "id": 5, + "hash": "e77aab2255ae11e1d76e", + "names": [ + "subapp-home" + ], + "entry": false, + "initial": false, + "rendered": true + }, + { + "id": 6, + "hash": "988f82b1a7c69c12acf2", + "names": [ + "subapp-static" + ], + "entry": false, + "initial": false, + "rendered": true + }, + { + "id": 7, + "hash": "34e10030430024ec3ab1", + "names": [ + "vendors~subapp-demo4" + ], + "entry": false, + "initial": false, + "rendered": true, + "reason": "split chunk (cache group: vendors) (name: vendors~subapp-demo4)" + } + ] +} \ No newline at end of file diff --git a/packages/xarc-subapp/test/spec/node/init-context.spec.ts b/packages/xarc-subapp/test/spec/node/init-context.spec.ts new file mode 100644 index 0000000000..346f187773 --- /dev/null +++ b/packages/xarc-subapp/test/spec/node/init-context.spec.ts @@ -0,0 +1,55 @@ +import { initContext } from "../../../src/node/init-context"; +import { expect } from "chai"; + +describe("Test init-context", () => { + it("test process context", () => { + const tokens = { + props: {} + }; + const initializer = initContext(null, tokens); + + const context: any = { + options: { + request: { bingo: true } + } + }; + initializer.process(context); + + expect(context.user.request).deep.eq(context.options.request); + expect(context.user.scriptNonce).have.property("tokens"); + expect(context.user.scriptNonceAttr).contains("nonce"); + expect(context.user.styleNonce).have.property("tokens"); + expect(context.user.styleNonceAttr).contains("nonce"); + expect(context.user.cspHeader).match( + /^script-src-elem 'strict-dynamic' 'nonce-[A-Za-z0-9+=\/]{22}'; style-src-elem 'strict-dynamic' 'nonce-[A-Za-z0-9+=\/]{22}';$/ + ); + }); + + it("test process context without header", () => { + const tokens = { + props: { + nonce: { + script: false, + style: false, + tokens: {} + } + } + }; + const initializer = initContext(null, tokens); + + const context: any = { + user: {}, + options: { + request: { bingo: true } + } + }; + initializer.process(context); + + expect(context.user.request).deep.eq(context.options.request); + expect(context.user.scriptNonce).eq(undefined); + expect(context.user.scriptNonceAttr).eq(""); + expect(context.user.styleNonce).eq(undefined); + expect(context.user.styleNonceAttr).eq(""); + expect(context.user).not.have.property("cspHeader"); + }); +}); diff --git a/packages/xarc-subapp/test/spec/node/init-v2.spec.ts b/packages/xarc-subapp/test/spec/node/init-v2.spec.ts new file mode 100644 index 0000000000..3a6f465f86 --- /dev/null +++ b/packages/xarc-subapp/test/spec/node/init-v2.spec.ts @@ -0,0 +1,209 @@ +import { initSubApp } from "../../../src/node/init-v2"; +import sinon from "sinon"; +import { expect } from "chai"; +import Fs from "fs"; +import Path from "path"; + +const statContent = Fs.readFileSync(Path.join(__dirname, "../../fixtures/stats.json")); + +describe("Test init-v2", () => { + let sandbox; + let prevNodeEnv; + let prevWebpack; + + beforeEach(() => { + prevNodeEnv = process.env.NODE_ENV; + prevWebpack = process.env.WEBPACK_DEV; + sandbox = sinon.createSandbox(); + const fsStub = sandbox.stub(Fs, "readFileSync"); + fsStub.withArgs(sinon.match(/^.*stats.json$/)).returns(statContent); + fsStub.callThrough(); + }); + + afterEach(() => { + sandbox.restore(); + process.env.NODE_ENV = prevNodeEnv; + process.env.WEBPACK_DEV = prevWebpack; + }); + + it("test initSubApp prod", () => { + process.env.WEBPACK_DEV = ""; + process.env.NODE_ENV = "production"; + const tokens = { + props: { + prodAssetData: { + pathMap: { base: "/prod-js" }, + cdnMap: { "poc1.subapp-home.style.5faa52f5a3012ca195e2.css": "ABC.css" } + } + } + }; + const initializer = initSubApp(null, tokens); + + const context: any = { + user: { + request: {}, + scriptNonceAttr: " cowabunga", + styleNonceAttr: " mincer-shredder" + }, + options: { + request: { bingo: true } + } + }; + const result = initializer.process(context); + expect(result).contains(` { + const tokens = { + props: {} + }; + const initializer = initSubApp(null, tokens); + + const context: any = { + user: { + request: {}, + scriptNonceAttr: " cowabunga", + styleNonceAttr: " mincer-shredder" + }, + options: { + request: { bingo: true } + } + }; + const result = initializer.process(context); + expect(result).contains(` { + const tokens = { + props: { + prodAssetData: { + cdnMap: { "base.js": "ABC.js" } + } + } + }; + const initializer = initSubApp(null, tokens); + + const context: any = { + user: { + request: {} + }, + options: { + request: { bingo: true } + } + }; + const result = initializer.process(context); + expect(result).contains(` { + const tokens = { + props: { + prodAssetData: {} + } + }; + const initializer = initSubApp(null, tokens); + + const context: any = { + user: { + request: {} + }, + options: { + request: { bingo: true } + } + }; + const result = initializer.process(context); + expect(result).not.contains(`cdn-map-`); + }); + + it("test initSubApp with CDN Map from file", () => { + process.env.WEBPACK_DEV = ""; + const tokens = { + props: { + prodAssetData: { + cdnMap: Path.join(__dirname, "../../fixtures/assets.json") + } + } + }; + const initializer = initSubApp(null, tokens); + + const context: any = { + user: { + request: {}, + styleNonceAttr: " from-file" + }, + options: { + request: { bingo: true } + } + }; + const result = initializer.process(context); + expect(result).contains( + ` { + process.env.WEBPACK_DEV = "true"; + process.env.NODE_ENV = "development"; + const tokens = { + props: { + devAssetData: { + pathMap: { base: "/dev-js" }, + cdnMap: { "home.js": "DEF.js" } + } + } + }; + const initializer = initSubApp(null, tokens); + + const context: any = { + user: { + request: {}, + scriptNonceAttr: " dev-cowabunga", + styleNonceAttr: " dev-mincer-shredder" + }, + options: { + request: { bingo: true } + } + }; + const result = initializer.process(context); + expect(result).contains(` { + process.env.WEBPACK_DEV = "true"; + process.env.NODE_ENV = "development"; + const tokens = { + props: {} + }; + const initializer = initSubApp(null, tokens); + + const context: any = { + user: { + request: {}, + scriptNonceAttr: " dev-cowabunga", + styleNonceAttr: " dev-mincer-shredder" + }, + options: { + request: { bingo: true } + } + }; + const result = initializer.process(context); + expect(result).contains(` { - let sandbox; + let sandbox; - beforeEach(() => { - sandbox = sinon.createSandbox(); - }); + beforeEach(() => { + sandbox = sinon.createSandbox(); + }); - afterEach(() => { - sandbox.restore(); - }); + afterEach(() => { + sandbox.restore(); + }); - it("load cdn map with relative path", () => { - const fakeFs = sandbox.stub(fs, "readFileSync"); - fakeFs.returns(`{"cow":"bunga"}`); - const cdnMapPath = "test-cdn-map.js"; - const result = util.loadCdnMap(cdnMapPath); - expect(fakeFs.getCall(0).args[0]).eq(path.resolve(process.cwd(), cdnMapPath)); - expect(result).deep.eq({cow: "bunga"}); - }); + it("load cdn map with relative path", () => { + const fakeFs = sandbox.stub(fs, "readFileSync"); + fakeFs.returns(`{"cow":"bunga"}`); + const cdnMapPath = "test-cdn-map.js"; + const result = util.loadCdnMap(cdnMapPath); + expect(fakeFs.getCall(0).args[0]).eq(path.resolve(process.cwd(), cdnMapPath)); + expect(result).deep.eq({ cow: "bunga" }); + }); - it("load cdn map with absolute path", () => { - const fakeFs = sandbox.stub(fs, "readFileSync"); - fakeFs.returns(`{"cow":"dung"}`); - const cdnMapPath = "/home/user/test-cdn-map.js"; - const result = util.loadCdnMap(cdnMapPath); - expect(fakeFs.getCall(0).args[0]).eq(cdnMapPath); - expect(result).deep.eq({cow: "dung"}); - }); + it("load cdn map with absolute path", () => { + const fakeFs = sandbox.stub(fs, "readFileSync"); + fakeFs.returns(`{"cow":"dung"}`); + const cdnMapPath = "/home/user/test-cdn-map.js"; + const result = util.loadCdnMap(cdnMapPath); + expect(fakeFs.getCall(0).args[0]).eq(cdnMapPath); + expect(result).deep.eq({ cow: "dung" }); + }); - it("load cdn map with invalid json", () => { - const fakeFs = sandbox.stub(fs, "readFileSync"); - fakeFs.returns(`}`); - const cdnMapPath = "test-cdn-map.js"; - const result = util.loadCdnMap(cdnMapPath); - expect(fakeFs.getCall(0).args[0]).eq(path.resolve(process.cwd(), cdnMapPath)); - expect(result).eq(undefined); - }); + it("load cdn map with invalid json", () => { + const fakeFs = sandbox.stub(fs, "readFileSync"); + fakeFs.returns(`}`); + const cdnMapPath = "test-cdn-map.js"; + const result = util.loadCdnMap(cdnMapPath); + expect(fakeFs.getCall(0).args[0]).eq(path.resolve(process.cwd(), cdnMapPath)); + expect(result).eq(undefined); + }); - it("map cdn returns mapping or false", () => { - const fileOne = "file.one"; - const fileTwo = "file.two"; - const mapping = { - [fileOne]: "bingo", - }; - expect(util.mapCdn(fileOne, mapping)).eq("bingo"); - expect(util.mapCdn(fileTwo, mapping)).eq(false); - expect(util.mapCdn(fileTwo, undefined)).eq(false); - }); + it("map cdn returns mapping or false", () => { + const fileOne = "file.one"; + const fileTwo = "file.two"; + const mapping = { + [fileOne]: "bingo" + }; + expect(util.mapCdn(fileOne, mapping)).eq("bingo"); + expect(util.mapCdn(fileTwo, mapping)).eq(false); + expect(util.mapCdn(fileTwo, undefined)).eq(false); + }); - it("test wrapStringFragment", () => { - expect(util.wrapStringFragment("fragment")).eq("fragment"); - expect(util.wrapStringFragment("fragment", "pre")).eq("prefragment"); - expect(util.wrapStringFragment("fragment", "post", "ly")).eq("postfragmently"); - expect(util.wrapStringFragment("", "post", "ly")).eq(""); - }); + it("test wrapStringFragment", () => { + expect(util.wrapStringFragment("fragment")).eq("fragment"); + expect(util.wrapStringFragment("fragment", "pre")).eq("prefragment"); + expect(util.wrapStringFragment("fragment", "post", "ly")).eq("postfragmently"); + expect(util.wrapStringFragment("", "post", "ly")).eq(""); + }); - it("test nonceGenerator", () => { - const nonce = util.nonceGenerator(); - expect(nonce).match(/[A-Za-z0-9+\/]{22}/); - }); + it("test nonceGenerator", () => { + const nonce = util.nonceGenerator(); + expect(nonce).match(/[A-Za-z0-9+\/]{22}/); + }); - it("test generateNonce", () => { - expect(util.generateNonce({props: { nonce: false }})).deep.eq({attr: ""}); - const generated = util.generateNonce({props: {}}); - expect(generated.attr).match(/ nonce="[A-Za-z0-9+\/]{22}"/); - expect(generated.nonce.tokens.all).match(/[A-Za-z0-9+\/]{22}/); - expect(generated.nonce.tokens[""]).match(/[A-Za-z0-9+\/]{22}/); - }); + it("test generateNonce", () => { + expect(util.generateNonce({ props: { nonce: false } })).deep.eq({ attr: "" }); + const generated = util.generateNonce({ props: {} }); + expect(generated.attr).match(/ nonce="[A-Za-z0-9+\/]{22}"/); + expect(generated.nonce.tokens.all).match(/[A-Za-z0-9+\/]{22}/); + expect(generated.nonce.tokens[""]).match(/[A-Za-z0-9+\/]{22}/); + }); - it("test generateNonce with generator", () => { - const nonceInfo = { - generator: () => "ABCDEF9876", - tokens: {} - }; - const generated = util.generateNonce({props: { nonce: nonceInfo }}, null, "script"); - expect(generated.attr).eq(` nonce="ABCDEF9876"`); - expect(generated.nonce).deep.eq(nonceInfo); - }); + it("test generateNonce with generator", () => { + const nonceInfo = { + generator: () => "ABCDEF9876", + tokens: {} + }; + const generated = util.generateNonce({ props: { nonce: nonceInfo } }, null, "script"); + expect(generated.attr).eq(` nonce="ABCDEF9876"`); + expect(generated.nonce).deep.eq(nonceInfo); + }); - it("test generateNonce with false tag", () => { - const nonceInfo = { - script: false, - tokens: {} - }; - const generated = util.generateNonce({props: { nonce: nonceInfo }}, null, "script"); - expect(generated).deep.eq({ attr: ""}); - }); + it("test generateNonce with false tag", () => { + const nonceInfo = { + script: false, + tokens: {} + }; + const generated = util.generateNonce({ props: { nonce: nonceInfo } }, null, "script"); + expect(generated).deep.eq({ attr: "" }); + }); - it("test generateNonce specify nonce and tag", () => { - const nonceInfo = { - tokens: { - all: "ABCDEF12345" - } - }; - const generated = util.generateNonce({props: { nonce: nonceInfo}}, null, "bingo"); - expect(generated.attr).eq(` nonce="ABCDEF12345"`); - expect(generated.nonce).deep.eq(nonceInfo); - }); + it("test generateNonce specify nonce and tag", () => { + const nonceInfo = { + tokens: { + all: "ABCDEF12345" + } + }; + const generated = util.generateNonce({ props: { nonce: nonceInfo } }, null, "bingo"); + expect(generated.attr).eq(` nonce="ABCDEF12345"`); + expect(generated.nonce).deep.eq(nonceInfo); + }); - it("test urLJoin", () => { - expect(util.urlJoin("http://www.google.com")).eq("http://www.google.com/"); - expect(util.urlJoin("http://www.google.com", "cow", "bunga")).eq("http://www.google.com/cow/bunga"); - expect(util.urlJoin("http://www.google.com", "cow", "?bunga=true")).eq("http://www.google.com/cow?bunga=true"); - expect(util.urlJoin("http://www.google.com", "cow", "&bunga=true")).eq("http://www.google.com/cow?bunga=true"); - expect(util.urlJoin("http://www.google.com", "cow", "&bunga=true", "mango")).eq("http://www.google.com/cow?bunga=true&mango"); - expect(util.urlJoin("http://www.google.com", "cow", "&bunga=true", "mango=1")).eq("http://www.google.com/cow?bunga=true&mango=1"); - expect(util.urlJoin("http://www.google.com/hockey")).eq("http://www.google.com/hockey"); - expect(util.urlJoin("http://www.google.com/hockey", "mango")).eq("http://www.google.com/hockey/mango"); - expect(util.urlJoin("http://www.google.com?fishing=true", "cow", "?bunga=true")).eq("http://www.google.com/cow?fishing=true&bunga=true"); - }); + it("test urLJoin", () => { + expect(util.urlJoin("http://www.google.com")).eq("http://www.google.com/"); + expect(util.urlJoin("http://www.google.com", "cow", "bunga")).eq( + "http://www.google.com/cow/bunga" + ); + expect(util.urlJoin("http://www.google.com", "cow", "?bunga=true")).eq( + "http://www.google.com/cow?bunga=true" + ); + expect(util.urlJoin("http://www.google.com", "cow", "&bunga=true")).eq( + "http://www.google.com/cow?bunga=true" + ); + expect(util.urlJoin("http://www.google.com", "cow", "&bunga=true", "mango")).eq( + "http://www.google.com/cow?bunga=true&mango" + ); + expect(util.urlJoin("http://www.google.com", "cow", "&bunga=true", "mango=1")).eq( + "http://www.google.com/cow?bunga=true&mango=1" + ); + expect(util.urlJoin("http://www.google.com/hockey")).eq("http://www.google.com/hockey"); + expect(util.urlJoin("http://www.google.com/hockey", "mango")).eq( + "http://www.google.com/hockey/mango" + ); + expect(util.urlJoin("http://www.google.com?fishing=true", "cow", "?bunga=true")).eq( + "http://www.google.com/cow?fishing=true&bunga=true" + ); + }); - it("test safeStringifyJson", () => { - expect(util.safeStringifyJson({french: ""})).eq(`{"french":"</script>"}`); - // missing " })).eq(`{"french":"</script>"}`); + // missing