inlineresources
Version:
Inlines style sheets, images, fonts and scripts in HTML documents. Works in the browser.
324 lines (253 loc) • 10.2 kB
JavaScript
;
var inlineScript = require("../../src/inlineScript"),
util = require("../../src/util"),
testHelper = require("../testHelper");
describe("JS inline", function () {
var doc,
joinUrlSpy,
ajaxSpy,
internalScript,
ajaxUrlMocks = {};
var setupAjaxMock = function () {
return spyOn(util, "ajax").and.callFake(function (url) {
if (ajaxUrlMocks[url] !== undefined) {
return Promise.resolve(ajaxUrlMocks[url]);
} else {
return Promise.reject({
url: "THEURL" + url,
});
}
});
};
var mockAjaxUrl = function (url, content) {
ajaxUrlMocks[url] = content;
};
var anExternalScriptWith = function (content, url) {
var externalScript = window.document.createElement("script");
url = url || "some/url.js";
externalScript.src = url;
mockAjaxUrl(url, content);
return externalScript;
};
var anExternalScript = function () {
return anExternalScriptWith("var b = 1;", "url/some.js");
};
var anotherExternalScript = function () {
var script = anExternalScriptWith(
"function something() {}",
"url/someOther.js"
);
script.type = "text/javascript";
script.id = "myScript";
return script;
};
beforeEach(function () {
doc = document.implementation.createHTMLDocument("");
joinUrlSpy = spyOn(util, "joinUrl");
ajaxSpy = setupAjaxMock();
internalScript = window.document.createElement("script");
internalScript.textContent = "function () {}";
joinUrlSpy.and.callFake(function (base, rel) {
return base + rel;
});
});
it("should do nothing if no linked JS is found", function (done) {
inlineScript.inline(doc, {}).then(function () {
expect(doc.getElementsByTagName("script").length).toEqual(0);
done();
});
});
it("should inline linked JS", function (done) {
doc.head.appendChild(anExternalScript());
inlineScript.inline(doc, {}).then(function () {
expect(doc.head.getElementsByTagName("script").length).toEqual(1);
expect(
doc.head.getElementsByTagName("script")[0].textContent
).toEqual("var b = 1;");
expect(doc.head.getElementsByTagName("script")[0].src).toBe("");
done();
});
});
it("should remove the src attribute from the inlined script", function (done) {
doc.head.appendChild(anotherExternalScript());
inlineScript.inline(doc, {}).then(function () {
expect(doc.head.getElementsByTagName("script").length).toEqual(1);
expect(doc.head.getElementsByTagName("script")[0].src).toBe("");
done();
});
});
it("should keep all other script's attributes inlining", function (done) {
doc.head.appendChild(anotherExternalScript());
inlineScript.inline(doc, {}).then(function () {
expect(doc.head.getElementsByTagName("script").length).toEqual(1);
expect(doc.head.getElementsByTagName("script")[0].type).toEqual(
"text/javascript"
);
expect(doc.head.getElementsByTagName("script")[0].id).toEqual(
"myScript"
);
done();
});
});
it("should place the inlined script where the external node was", function (done) {
doc.head.appendChild(anExternalScript());
doc.body.appendChild(anotherExternalScript());
inlineScript.inline(doc, {}).then(function () {
expect(doc.getElementsByTagName("script").length).toEqual(2);
expect(
doc.head.getElementsByTagName("script")[0].textContent
).toEqual("var b = 1;");
expect(
doc.body.getElementsByTagName("script")[0].textContent
).toEqual("function something() {}");
done();
});
});
it("should not touch internal scripts", function (done) {
doc.head.appendChild(internalScript);
inlineScript.inline(doc, {}).then(function () {
expect(ajaxSpy).not.toHaveBeenCalled();
expect(doc.head.getElementsByTagName("script").length).toEqual(1);
expect(doc.head.getElementsByTagName("script")[0]).toEqual(
internalScript
);
done();
});
});
it("should correctly quote closing HTML tags in the script", function (done) {
doc.head.appendChild(
anExternalScriptWith('var closingScriptTag = "</script>";')
);
inlineScript.inline(doc, {}).then(function () {
expect(
doc.head.getElementsByTagName("script")[0].textContent
).toEqual('var closingScriptTag = "<\\/script>";');
done();
});
});
xit("should not quote a regex", function (done) {
doc.head.appendChild(anExternalScriptWith("/</.test('<');"));
inlineScript.inline(doc, {}).then(function () {
expect(
doc.head.getElementsByTagName("script")[0].textContent
).toEqual("/</.test('<');");
done();
});
});
it("should respect the document's baseURI when loading linked JS", function (done) {
var getDocumentBaseUrlSpy = spyOn(
util,
"getDocumentBaseUrl"
).and.callThrough();
doc = testHelper.readDocumentFixture("externalJS.html");
inlineScript.inline(doc, {}).then(function () {
expect(ajaxSpy).toHaveBeenCalledWith("some.js", {
baseUrl: doc.baseURI,
});
expect(getDocumentBaseUrlSpy).toHaveBeenCalledWith(doc);
done();
});
});
it("should respect optional baseUrl when loading linked JS", function (done) {
doc.head.appendChild(anExternalScriptWith("", "externalScript.js"));
inlineScript
.inline(doc, { baseUrl: "some_base_url/" })
.then(function () {
expect(ajaxSpy).toHaveBeenCalledWith("externalScript.js", {
baseUrl: "some_base_url/",
});
done();
});
});
it("should favour explicit baseUrl over document.baseURI when loading linked JS", function (done) {
doc = testHelper.readDocumentFixture("externalJS.html");
expect(doc.baseURI).not.toBeNull();
expect(doc.baseURI).not.toEqual("about:blank");
inlineScript
.inline(doc, { baseUrl: "some_base_url/" })
.then(function () {
expect(ajaxSpy).toHaveBeenCalledWith("some.js", {
baseUrl: "some_base_url/",
});
done();
});
});
it("should circumvent caching if requested", function (done) {
doc.head.appendChild(anExternalScript());
inlineScript.inline(doc, { cache: "none" }).then(function () {
expect(ajaxSpy).toHaveBeenCalledWith(
jasmine.any(String),
jasmine.objectContaining({
cache: "none",
})
);
done();
});
});
it("should not circumvent caching by default", function (done) {
doc.head.appendChild(anExternalScript());
inlineScript.inline(doc, {}).then(function () {
expect(ajaxSpy).toHaveBeenCalled();
expect(ajaxSpy).not.toHaveBeenCalledWith(
jasmine.any(String),
jasmine.objectContaining({
cache: "none",
})
);
done();
});
});
describe("error handling", function () {
var brokenJsScript, anotherBrokenJsScript;
beforeEach(function () {
brokenJsScript = window.document.createElement("script");
brokenJsScript.src = "a_document_that_doesnt_exist.js";
anotherBrokenJsScript = window.document.createElement("script");
anotherBrokenJsScript.src = "another_document_that_doesnt_exist.js";
joinUrlSpy.and.callThrough();
});
it("should report an error if a script could not be loaded", function (done) {
doc.head.appendChild(brokenJsScript);
inlineScript.inline(doc, {}).then(function (errors) {
expect(errors[0]).toEqual(
jasmine.objectContaining({
resourceType: "script",
url: "THEURL" + "a_document_that_doesnt_exist.js",
msg:
"Unable to load script " +
"THEURL" +
"a_document_that_doesnt_exist.js",
})
);
done();
});
});
it("should only report a failing script as error", function (done) {
doc.head.appendChild(brokenJsScript);
doc.head.appendChild(anExternalScript());
inlineScript.inline(doc, {}).then(function (errors) {
expect(errors.length).toBe(1);
done();
});
});
it("should report multiple failing scripts as error", function (done) {
doc.head.appendChild(brokenJsScript);
doc.head.appendChild(anotherBrokenJsScript);
inlineScript.inline(doc, {}).then(function (errors) {
expect(errors).toEqual([
jasmine.any(Object),
jasmine.any(Object),
]);
expect(errors[0]).not.toEqual(errors[1]);
done();
});
});
it("should report an empty list for a successful script", function (done) {
doc.head.appendChild(anExternalScript());
inlineScript.inline(doc, {}).then(function (errors) {
expect(errors).toEqual([]);
done();
});
});
});
});