UNPKG

inlineresources

Version:

Inlines style sheets, images, fonts and scripts in HTML documents. Works in the browser.

426 lines (353 loc) 14.2 kB
"use strict"; var inline = require("../../src/inline"), inlineCss = require("../../src/inlineCss"), util = require("../../src/util"), testHelper = require("../testHelper"); describe("Inline styles", function () { var doc, loadCSSImportsForRulesSpy, loadAndInlineCSSResourcesForRulesSpy; var fulfilled = function (value) { return Promise.resolve(value); }; beforeEach(function () { doc = document.implementation.createHTMLDocument(""); loadCSSImportsForRulesSpy = spyOn( inlineCss, "loadCSSImportsForRules" ).and.returnValue( fulfilled({ hasChanges: false, errors: [], }) ); loadAndInlineCSSResourcesForRulesSpy = spyOn( inlineCss, "loadAndInlineCSSResourcesForRules" ).and.returnValue( fulfilled({ hasChanges: false, errors: [], }) ); spyOn(util, "clone").and.callFake(function (object) { return object; }); }); it("should do nothing if no CSS is found", function (done) { inline.loadAndInlineStyles(doc, {}).then(function () { expect(loadCSSImportsForRulesSpy).not.toHaveBeenCalled(); done(); }); }); it("should not touch unrelated CSS", function (done) { testHelper.addStyleToDocument(doc, "span { padding-left: 0; }"); loadCSSImportsForRulesSpy.and.callFake(function (rules) { rules[0] = "fake rule"; return fulfilled({ hasChanges: false, errors: [], }); }); loadAndInlineCSSResourcesForRulesSpy.and.callFake(function (rules) { rules[0] = "something else"; return fulfilled({ hasChanges: false, errors: [], }); }); inline.loadAndInlineStyles(doc, {}).then(function () { expect( doc.head.getElementsByTagName("style")[0].textContent ).toEqual("span { padding-left: 0; }"); done(); }); }); it("should replace an import with the content of the given URL", function (done) { testHelper.addStyleToDocument(doc, '@import url("that.css");'); inline.loadAndInlineStyles(doc, {}).then(function () { expect(loadCSSImportsForRulesSpy).toHaveBeenCalled(); expect( loadCSSImportsForRulesSpy.calls.mostRecent().args[0][0].cssText ).toMatch(/@import url\([ "]?that.css[ "]?\)\s*;/); done(); }); }); it("should inline css resources", function (done) { testHelper.addStyleToDocument( doc, 'span { background-image: url("anImage.png"); }' ); inline.loadAndInlineStyles(doc, {}).then(function () { expect(loadAndInlineCSSResourcesForRulesSpy).toHaveBeenCalled(); expect( loadAndInlineCSSResourcesForRulesSpy.calls.mostRecent() .args[0][0].cssText ).toMatch( /span \{\s*background-image: url\("?anImage.png"?\)\s*;\s*\}/ ); done(); }); }); it("should accept a style element without a type", function (done) { var styleNode = doc.createElement("style"); styleNode.appendChild( doc.createTextNode('@import url("imported.css");') ); doc.head.appendChild(styleNode); inline.loadAndInlineStyles(doc, {}).then(function () { expect(loadCSSImportsForRulesSpy).toHaveBeenCalled(); expect(loadAndInlineCSSResourcesForRulesSpy).toHaveBeenCalled(); done(); }); }); it("should ignore a style element with a non CSS type", function (done) { var styleNode = doc.createElement("style"); styleNode.type = "text/plain"; styleNode.appendChild( doc.createTextNode('@import url("imported.css");') ); doc.head.appendChild(styleNode); inline.loadAndInlineStyles(doc, {}).then(function () { expect(loadCSSImportsForRulesSpy).not.toHaveBeenCalled(); expect(loadAndInlineCSSResourcesForRulesSpy).not.toHaveBeenCalled(); done(); }); }); it("should respect the document's baseURI", function (done) { var getDocumentBaseUrlSpy = spyOn( util, "getDocumentBaseUrl" ).and.callThrough(); doc = testHelper.readDocumentFixture("importCss.html"); inline.loadAndInlineStyles(doc, {}).then(function () { expect(loadCSSImportsForRulesSpy).toHaveBeenCalledWith( jasmine.any(Object), [], { baseUrl: doc.baseURI } ); expect(loadAndInlineCSSResourcesForRulesSpy).toHaveBeenCalledWith( jasmine.any(Object), { baseUrl: doc.baseURI } ); expect(getDocumentBaseUrlSpy).toHaveBeenCalledWith(doc); done(); }); }); it("should favour explicit baseUrl over document.baseURI", function (done) { var baseUrl = "aBaseURI"; doc = testHelper.readDocumentFixture("importCss.html"); expect(doc.baseURI).not.toBeNull(); expect(doc.baseURI).not.toEqual("about:blank"); expect(doc.baseURI).not.toEqual(baseUrl); inline.loadAndInlineStyles(doc, { baseUrl: baseUrl }).then(function () { expect(loadCSSImportsForRulesSpy).toHaveBeenCalledWith( jasmine.any(Object), [], { baseUrl: baseUrl } ); expect(loadAndInlineCSSResourcesForRulesSpy).toHaveBeenCalledWith( jasmine.any(Object), { baseUrl: baseUrl } ); done(); }); }); it("should circumvent caching if requested", function (done) { testHelper.addStyleToDocument(doc, '@import url("that.css");'); inline.loadAndInlineStyles(doc, { cache: "none" }).then(function () { expect(loadCSSImportsForRulesSpy).toHaveBeenCalled(); expect( loadCSSImportsForRulesSpy.calls.mostRecent().args[2].cache ).toEqual("none"); expect(loadAndInlineCSSResourcesForRulesSpy).toHaveBeenCalled(); expect( loadAndInlineCSSResourcesForRulesSpy.calls.mostRecent().args[1] .cache ).toEqual("none"); done(); }); }); it("should not circumvent caching by default", function (done) { testHelper.addStyleToDocument(doc, '@import url("that.css");'); inline.loadAndInlineStyles(doc, {}).then(function () { expect(loadCSSImportsForRulesSpy).toHaveBeenCalled(); expect( loadCSSImportsForRulesSpy.calls.mostRecent().args[2] ).toBeTruthy(); expect(loadAndInlineCSSResourcesForRulesSpy).toHaveBeenCalled(); expect( loadAndInlineCSSResourcesForRulesSpy.calls.mostRecent().args[1] .cache ).not.toBe(false); done(); }); }); it("should cache inlined content if a cache bucket is given", function (done) { var cacheBucket = {}; loadAndInlineCSSResourcesForRulesSpy.and.returnValue( fulfilled({ hasChanges: true, errors: [], }) ); // first call doc = document.implementation.createHTMLDocument(""); testHelper.addStyleToDocument( doc, "background-image { url(anImage.png); }" ); inline .loadAndInlineStyles(doc, { cacheBucket: cacheBucket }) .then(function () { expect(loadCSSImportsForRulesSpy).toHaveBeenCalled(); loadCSSImportsForRulesSpy.calls.reset(); loadAndInlineCSSResourcesForRulesSpy.calls.reset(); // second call doc = document.implementation.createHTMLDocument(""); testHelper.addStyleToDocument( doc, "background-image { url(anImage.png); }" ); inline .loadAndInlineStyles(doc, { cacheBucket: cacheBucket }) .then(function () { expect( loadCSSImportsForRulesSpy ).not.toHaveBeenCalled(); expect( loadAndInlineCSSResourcesForRulesSpy ).not.toHaveBeenCalled(); expect( doc.getElementsByTagName("style")[0].textContent ).toMatch(/background-image\s*{\s*}/); done(); }); }); }); it("should not use cache inlined content if the documents' URLs don't match", function (done) { var cacheBucket = {}; loadAndInlineCSSResourcesForRulesSpy.and.returnValue( fulfilled({ hasChanges: true, errors: [], }) ); // first call doc = document.implementation.createHTMLDocument(""); testHelper.addStyleToDocument( doc, "background-image { url(anImage.png); }" ); inline .loadAndInlineStyles(doc, { cacheBucket: cacheBucket }) .then(function () { expect(loadCSSImportsForRulesSpy).toHaveBeenCalled(); loadCSSImportsForRulesSpy.calls.reset(); loadAndInlineCSSResourcesForRulesSpy.calls.reset(); // second call testHelper .loadHTMLDocumentFixture("image.html") .then(function (doc) { // use a document with different baseUrl testHelper.addStyleToDocument( doc, "background-image { url(anImage.png); }" ); inline .loadAndInlineStyles(doc, { cacheBucket: cacheBucket, }) .then(function () { expect( loadCSSImportsForRulesSpy ).toHaveBeenCalled(); expect( loadAndInlineCSSResourcesForRulesSpy ).toHaveBeenCalled(); done(); }); }); }); }); it("should not cache inlined content if caching turned off", function (done) { var cacheBucket = {}; // first call doc = document.implementation.createHTMLDocument(""); testHelper.addStyleToDocument( doc, "background-image { url(anImage.png); }" ); inline .loadAndInlineStyles(doc, { cacheBucket: cacheBucket, cache: "none", }) .then(function () { expect(loadCSSImportsForRulesSpy).toHaveBeenCalled(); loadCSSImportsForRulesSpy.calls.reset(); // second call doc = document.implementation.createHTMLDocument(""); testHelper.addStyleToDocument( doc, "background-image { url(anImage.png); }" ); inline .loadAndInlineStyles(doc, { cacheBucket: cacheBucket, cache: "none", }) .then(function () { expect(loadCSSImportsForRulesSpy).toHaveBeenCalled(); done(); }); }); }); describe("error handling", function () { it("should report errors", function (done) { loadCSSImportsForRulesSpy.and.returnValue( fulfilled({ hasChanges: false, errors: ["import error"], }) ); loadAndInlineCSSResourcesForRulesSpy.and.returnValue( fulfilled({ hasChanges: false, errors: ["resource error"], }) ); testHelper.addStyleToDocument(doc, '@import url("that.css");'); inline.loadAndInlineStyles(doc, {}).then(function (errors) { expect(errors).toEqual(["import error", "resource error"]); done(); }); }); it("should cache errors alongside if a cache bucket is given", function (done) { var cacheBucket = {}; loadCSSImportsForRulesSpy.and.returnValue( fulfilled({ hasChanges: false, errors: ["import error"], }) ); // first call doc = document.implementation.createHTMLDocument(""); testHelper.addStyleToDocument(doc, '@import url("that.css");'); inline .loadAndInlineStyles(doc, { cacheBucket: cacheBucket }) .then(function () { // second call doc = document.implementation.createHTMLDocument(""); testHelper.addStyleToDocument( doc, '@import url("that.css");' ); inline .loadAndInlineStyles(doc, { cacheBucket: cacheBucket }) .then(function (errors) { expect(errors).toEqual(["import error"]); done(); }); }); }); }); });