diff --git a/lib/tasks/buildThemes.js b/lib/tasks/buildThemes.js index 0dd03688c..a8a80b987 100644 --- a/lib/tasks/buildThemes.js +++ b/lib/tasks/buildThemes.js @@ -11,7 +11,10 @@ const fsInterface = require("@ui5/fs").fsInterface; * @param {module:@ui5/fs.DuplexCollection} parameters.workspace DuplexCollection to read and write files * @param {module:@ui5/fs.AbstractReader} parameters.dependencies Reader or Collection to read dependency files * @param {Object} parameters.options Options - * @param {string} parameters.options.pattern Pattern to locate the files to be processed + * @param {string} parameters.options.projectName Project name + * @param {string} parameters.options.inputPattern Search pattern for *.less files to be built + * @param {string} [parameters.options.librariesPattern] Search pattern for .library files + * @param {boolean} [parameters.options.compress=true] * @returns {Promise} Promise resolving with undefined once data has been written */ module.exports = function({workspace, dependencies, options}) { @@ -27,6 +30,8 @@ module.exports = function({workspace, dependencies, options}) { promises.push(combo.byGlob(options.librariesPattern)); } + const compress = options.compress === undefined ? true : options.compress; + return Promise.all(promises).then(([allResources, availableLibraries]) => { if (!availableLibraries || availableLibraries.length === 0) { // Try to build all themes @@ -55,7 +60,7 @@ module.exports = function({workspace, dependencies, options}) { resources, fs: fsInterface(combo), options: { - compress: true + compress } }); }).then((processedResources) => { diff --git a/test/lib/tasks/buildThemes.integration.js b/test/lib/tasks/buildThemes.integration.js new file mode 100644 index 000000000..91df4647b --- /dev/null +++ b/test/lib/tasks/buildThemes.integration.js @@ -0,0 +1,157 @@ +const test = require("ava"); + +const ui5Builder = require("../../../"); +const tasks = ui5Builder.builder.tasks; +const ui5Fs = require("@ui5/fs"); +const resourceFactory = ui5Fs.resourceFactory; +const DuplexCollection = ui5Fs.DuplexCollection; + +test("integration: simple", (t) => { + const reader = resourceFactory.createAdapter({ + virBasePath: "/" + }); + const writer = resourceFactory.createAdapter({ + virBasePath: "/" + }); + const duplexCollection = new DuplexCollection({reader, writer}); + const dependencies = resourceFactory.createAdapter({ + virBasePath: "/" + }); + + const content = +`@deepSea: #123456; +.fluffyHammer { + color: @deepSea; + padding: 1px 2px 3px 4px; +}`; + const cssExpected = +`.fluffyHammer{color:#123456;padding:1px 2px 3px 4px} +/* Inline theming parameters */ +#sap-ui-theme-super\\.duper\\.looper{background-image:url('data:text/plain;utf-8,%7B%22deepSea%22%3A%22%23123456%22%7D')} +`; + const cssRtlExpected = +`.fluffyHammer{color:#123456;padding:1px 4px 3px 2px} +/* Inline theming parameters */ +#sap-ui-theme-super\\.duper\\.looper{background-image:url('data:text/plain;utf-8,%7B%22deepSea%22%3A%22%23123456%22%7D')} +`; + const parametersExpected = +`{"deepSea":"#123456"}`; + const lessPath = "/resources/super/duper/looper/themes/brightlight/library.source.less"; + const cssPath = "/resources/super/duper/looper/themes/brightlight/library.css"; + const cssRtlPath = "/resources/super/duper/looper/themes/brightlight/library-RTL.css"; + const parametersPath = "/resources/super/duper/looper/themes/brightlight/library-parameters.json"; + + const resource = resourceFactory.createResource({ + path: lessPath, + string: content + }); + return reader.write(resource).then(() => { + return tasks.buildThemes({ + workspace: duplexCollection, + dependencies: dependencies, + options: { + inputPattern: "/resources/**/themes/**/library.source.less" + } + }).then(() => { + return Promise.all([ + writer.byPath(cssPath), + writer.byPath(cssRtlPath), + writer.byPath(parametersPath) + ]); + }).then(([cssResource, cssRtlResource, parametersResource]) => { + t.truthy(cssResource, "CSS resource has been created"); + t.truthy(cssRtlResource, "CSS right-to-left resource has been created"); + t.truthy(parametersResource, "Parameters JSON resource has been created"); + + return Promise.all([ + cssResource.getBuffer(), + cssRtlResource.getBuffer(), + parametersResource.getBuffer() + ]); + }).then(([cssBuffer, cssRtlBuffer, parametersBuffer]) => { + t.deepEqual(cssBuffer.toString(), cssExpected, "Correct CSS content"); + t.deepEqual(cssRtlBuffer.toString(), cssRtlExpected, "Correct CSS right-to-left content"); + t.deepEqual(parametersBuffer.toString(), parametersExpected, "Correct parameters JSON content"); + }); + }); +}); + +test("integration: imports", (t) => { + const reader = resourceFactory.createAdapter({ + virBasePath: "/" + }); + const writer = resourceFactory.createAdapter({ + virBasePath: "/" + }); + const duplexCollection = new DuplexCollection({reader, writer}); + const dependencies = resourceFactory.createAdapter({ + virBasePath: "/" + }); + const lessContent = +`@import "variables.less"; +.fluffyHammer { + color: @deepSea; + padding: 1px 2px 3px 4px; +}`; + const lessVariablesContent = +"@deepSea: #123456;"; + const cssExpected = +`.fluffyHammer{color:#123456;padding:1px 2px 3px 4px} +/* Inline theming parameters */ +#sap-ui-theme-super\\.duper\\.looper{background-image:url('data:text/plain;utf-8,%7B%22deepSea%22%3A%22%23123456%22%7D')} +`; + const cssRtlExpected = +`.fluffyHammer{color:#123456;padding:1px 4px 3px 2px} +/* Inline theming parameters */ +#sap-ui-theme-super\\.duper\\.looper{background-image:url('data:text/plain;utf-8,%7B%22deepSea%22%3A%22%23123456%22%7D')} +`; + const parametersExpected = +`{"deepSea":"#123456"}`; + const lessPath = "/resources/super/duper/looper/themes/brightlight/library.source.less"; + const lessVariablesPath = "/resources/super/duper/looper/themes/brightlight/variables.less"; + const cssPath = "/resources/super/duper/looper/themes/brightlight/library.css"; + const cssRtlPath = "/resources/super/duper/looper/themes/brightlight/library-RTL.css"; + const parametersPath = "/resources/super/duper/looper/themes/brightlight/library-parameters.json"; + + const lessResource = resourceFactory.createResource({ + path: lessPath, + string: lessContent + }); + + const lessVariablesResource = resourceFactory.createResource({ + path: lessVariablesPath, + string: lessVariablesContent + }); + + return Promise.all([lessResource, lessVariablesResource].map((resource) => { + return reader.write(resource); + })).then(() => { + return tasks.buildThemes({ + workspace: duplexCollection, + dependencies: dependencies, + options: { + inputPattern: "/resources/**/themes/**/library.source.less" + } + }).then(() => { + return Promise.all([ + writer.byPath(cssPath), + writer.byPath(cssRtlPath), + writer.byPath(parametersPath) + ]); + }).then(([cssResource, cssRtlResource, parametersResource]) => { + t.truthy(cssResource, "CSS resource has been created"); + t.truthy(cssRtlResource, "CSS right-to-left resource has been created"); + t.truthy(parametersResource, "Parameters JSON resource has been created"); + + return Promise.all([ + cssResource.getBuffer(), + cssRtlResource.getBuffer(), + parametersResource.getBuffer() + ]); + }).then(([cssBuffer, cssRtlBuffer, parametersBuffer]) => { + t.deepEqual(cssBuffer.toString(), cssExpected, "Correct CSS content"); + t.deepEqual(cssRtlBuffer.toString(), cssRtlExpected, "Correct CSS right-to-left content"); + t.deepEqual(parametersBuffer.toString(), parametersExpected, "Correct parameters JSON content"); + }); + }); +}); diff --git a/test/lib/tasks/buildThemes.js b/test/lib/tasks/buildThemes.js index 91df4647b..166fc20e3 100644 --- a/test/lib/tasks/buildThemes.js +++ b/test/lib/tasks/buildThemes.js @@ -1,157 +1,128 @@ const test = require("ava"); -const ui5Builder = require("../../../"); -const tasks = ui5Builder.builder.tasks; -const ui5Fs = require("@ui5/fs"); -const resourceFactory = ui5Fs.resourceFactory; -const DuplexCollection = ui5Fs.DuplexCollection; - -test("integration: simple", (t) => { - const reader = resourceFactory.createAdapter({ - virBasePath: "/" - }); - const writer = resourceFactory.createAdapter({ - virBasePath: "/" - }); - const duplexCollection = new DuplexCollection({reader, writer}); - const dependencies = resourceFactory.createAdapter({ - virBasePath: "/" - }); +const sinon = require("sinon"); +const mock = require("mock-require"); - const content = -`@deepSea: #123456; -.fluffyHammer { - color: @deepSea; - padding: 1px 2px 3px 4px; -}`; - const cssExpected = -`.fluffyHammer{color:#123456;padding:1px 2px 3px 4px} -/* Inline theming parameters */ -#sap-ui-theme-super\\.duper\\.looper{background-image:url('data:text/plain;utf-8,%7B%22deepSea%22%3A%22%23123456%22%7D')} -`; - const cssRtlExpected = -`.fluffyHammer{color:#123456;padding:1px 4px 3px 2px} -/* Inline theming parameters */ -#sap-ui-theme-super\\.duper\\.looper{background-image:url('data:text/plain;utf-8,%7B%22deepSea%22%3A%22%23123456%22%7D')} -`; - const parametersExpected = -`{"deepSea":"#123456"}`; - const lessPath = "/resources/super/duper/looper/themes/brightlight/library.source.less"; - const cssPath = "/resources/super/duper/looper/themes/brightlight/library.css"; - const cssRtlPath = "/resources/super/duper/looper/themes/brightlight/library-RTL.css"; - const parametersPath = "/resources/super/duper/looper/themes/brightlight/library-parameters.json"; - - const resource = resourceFactory.createResource({ - path: lessPath, - string: content - }); - return reader.write(resource).then(() => { - return tasks.buildThemes({ - workspace: duplexCollection, - dependencies: dependencies, - options: { - inputPattern: "/resources/**/themes/**/library.source.less" +let buildThemes = require("../../../lib/tasks/buildThemes"); + +test.beforeEach((t) => { + // Stubbing processors/themeBuilder + t.context.themeBuilderStub = sinon.stub(); + t.context.fsInterfaceStub = sinon.stub(require("@ui5/fs"), "fsInterface"); + t.context.fsInterfaceStub.returns({}); + mock("../../../lib/processors/themeBuilder", t.context.themeBuilderStub); + + // Re-require tested module + buildThemes = mock.reRequire("../../../lib/tasks/buildThemes"); +}); + +test.afterEach.always((t) => { + t.context.fsInterfaceStub.restore(); + mock.stop("../../../lib/processors/themeBuilder"); +}); + +test.serial("buildThemes", async (t) => { + t.plan(6); + + const lessResource = {}; + + const workspace = { + byGlob: async (globPattern) => { + if (globPattern === "/resources/test/library.source.less") { + return [lessResource]; + } else { + return []; } - }).then(() => { - return Promise.all([ - writer.byPath(cssPath), - writer.byPath(cssRtlPath), - writer.byPath(parametersPath) - ]); - }).then(([cssResource, cssRtlResource, parametersResource]) => { - t.truthy(cssResource, "CSS resource has been created"); - t.truthy(cssRtlResource, "CSS right-to-left resource has been created"); - t.truthy(parametersResource, "Parameters JSON resource has been created"); - - return Promise.all([ - cssResource.getBuffer(), - cssRtlResource.getBuffer(), - parametersResource.getBuffer() - ]); - }).then(([cssBuffer, cssRtlBuffer, parametersBuffer]) => { - t.deepEqual(cssBuffer.toString(), cssExpected, "Correct CSS content"); - t.deepEqual(cssRtlBuffer.toString(), cssRtlExpected, "Correct CSS right-to-left content"); - t.deepEqual(parametersBuffer.toString(), parametersExpected, "Correct parameters JSON content"); - }); + }, + write: sinon.stub() + }; + + const cssResource = {}; + const cssRtlResource = {}; + const jsonParametersResource = {}; + + t.context.themeBuilderStub.returns([ + cssResource, + cssRtlResource, + jsonParametersResource + ]); + + await buildThemes({ + workspace, + options: { + projectName: "sap.ui.demo.app", + inputPattern: "/resources/test/library.source.less" + } }); + + t.deepEqual(t.context.themeBuilderStub.callCount, 1, + "Processor should be called once"); + + t.deepEqual(t.context.themeBuilderStub.getCall(0).args[0], { + resources: [lessResource], + fs: {}, + options: { + compress: true // default + } + }, "Processor should be called with expected arguments"); + + t.deepEqual(workspace.write.callCount, 3, + "workspace.write should be called 3 times"); + t.true(workspace.write.calledWithExactly(cssResource)); + t.true(workspace.write.calledWithExactly(cssRtlResource)); + t.true(workspace.write.calledWithExactly(jsonParametersResource)); }); -test("integration: imports", (t) => { - const reader = resourceFactory.createAdapter({ - virBasePath: "/" - }); - const writer = resourceFactory.createAdapter({ - virBasePath: "/" - }); - const duplexCollection = new DuplexCollection({reader, writer}); - const dependencies = resourceFactory.createAdapter({ - virBasePath: "/" - }); - const lessContent = -`@import "variables.less"; -.fluffyHammer { - color: @deepSea; - padding: 1px 2px 3px 4px; -}`; - const lessVariablesContent = -"@deepSea: #123456;"; - const cssExpected = -`.fluffyHammer{color:#123456;padding:1px 2px 3px 4px} -/* Inline theming parameters */ -#sap-ui-theme-super\\.duper\\.looper{background-image:url('data:text/plain;utf-8,%7B%22deepSea%22%3A%22%23123456%22%7D')} -`; - const cssRtlExpected = -`.fluffyHammer{color:#123456;padding:1px 4px 3px 2px} -/* Inline theming parameters */ -#sap-ui-theme-super\\.duper\\.looper{background-image:url('data:text/plain;utf-8,%7B%22deepSea%22%3A%22%23123456%22%7D')} -`; - const parametersExpected = -`{"deepSea":"#123456"}`; - const lessPath = "/resources/super/duper/looper/themes/brightlight/library.source.less"; - const lessVariablesPath = "/resources/super/duper/looper/themes/brightlight/variables.less"; - const cssPath = "/resources/super/duper/looper/themes/brightlight/library.css"; - const cssRtlPath = "/resources/super/duper/looper/themes/brightlight/library-RTL.css"; - const parametersPath = "/resources/super/duper/looper/themes/brightlight/library-parameters.json"; - - const lessResource = resourceFactory.createResource({ - path: lessPath, - string: lessContent - }); - const lessVariablesResource = resourceFactory.createResource({ - path: lessVariablesPath, - string: lessVariablesContent - }); +test.serial("buildThemes (compress = false)", async (t) => { + t.plan(6); - return Promise.all([lessResource, lessVariablesResource].map((resource) => { - return reader.write(resource); - })).then(() => { - return tasks.buildThemes({ - workspace: duplexCollection, - dependencies: dependencies, - options: { - inputPattern: "/resources/**/themes/**/library.source.less" + const lessResource = {}; + + const workspace = { + byGlob: async (globPattern) => { + if (globPattern === "/resources/test/library.source.less") { + return [lessResource]; + } else { + return []; } - }).then(() => { - return Promise.all([ - writer.byPath(cssPath), - writer.byPath(cssRtlPath), - writer.byPath(parametersPath) - ]); - }).then(([cssResource, cssRtlResource, parametersResource]) => { - t.truthy(cssResource, "CSS resource has been created"); - t.truthy(cssRtlResource, "CSS right-to-left resource has been created"); - t.truthy(parametersResource, "Parameters JSON resource has been created"); - - return Promise.all([ - cssResource.getBuffer(), - cssRtlResource.getBuffer(), - parametersResource.getBuffer() - ]); - }).then(([cssBuffer, cssRtlBuffer, parametersBuffer]) => { - t.deepEqual(cssBuffer.toString(), cssExpected, "Correct CSS content"); - t.deepEqual(cssRtlBuffer.toString(), cssRtlExpected, "Correct CSS right-to-left content"); - t.deepEqual(parametersBuffer.toString(), parametersExpected, "Correct parameters JSON content"); - }); + }, + write: sinon.stub() + }; + + const cssResource = {}; + const cssRtlResource = {}; + const jsonParametersResource = {}; + + t.context.themeBuilderStub.returns([ + cssResource, + cssRtlResource, + jsonParametersResource + ]); + + await buildThemes({ + workspace, + options: { + projectName: "sap.ui.demo.app", + inputPattern: "/resources/test/library.source.less", + compress: false + } }); + + t.deepEqual(t.context.themeBuilderStub.callCount, 1, + "Processor should be called once"); + + t.deepEqual(t.context.themeBuilderStub.getCall(0).args[0], { + resources: [lessResource], + fs: {}, + options: { + compress: false + } + }, "Processor should be called with expected arguments"); + + t.deepEqual(workspace.write.callCount, 3, + "workspace.write should be called 3 times"); + t.true(workspace.write.calledWithExactly(cssResource)); + t.true(workspace.write.calledWithExactly(cssRtlResource)); + t.true(workspace.write.calledWithExactly(jsonParametersResource)); });