liferay-theme-tasks
Version:
A set of tasks for building and deploying Liferay Portal themes.
440 lines (355 loc) • 9.6 kB
JavaScript
/**
* @jest-environment node
*/
/**
* SPDX-FileCopyrightText: © 2017 Liferay, Inc. <https://liferay.com>
* SPDX-License-Identifier: MIT
*/
const fs = require('fs-extra');
const {Gulp} = require('gulp');
const path = require('path');
const {parseString} = require('xml2js');
const project = require('../../../lib/project');
const {
cleanTempTheme,
setupTempTheme,
stripNewlines,
} = require('../../../lib/test/util');
const {registerTasks} = require('../../index');
function assertEqual(actual, expected) {
if (Array.isArray(expected) && Array.isArray(actual)) {
if (
expected.length === actual.length &&
expected.every((item, index) => {
return item === actual[index];
})
) {
return;
}
}
if (expected !== actual) {
fail(
`Expected\n\n${description(expected)}\n\nto equal\n\n${description(
actual
)}`
);
}
}
function assertExists(file) {
if (!fs.existsSync(file)) {
fail(`Expected file does not exist at: ${file}`);
}
}
assertExists.not = (file) => {
if (fs.existsSync(file)) {
fail(`Expected file to not exist at: ${file}`);
}
};
function assertMatches(string, regExp) {
if (!regExp.test(string)) {
fail(`Expected string to match ${regExp}\n\n${string}`);
}
}
function assertTruthy(condition) {
if (!condition) {
fail(`Expected truthy condition but got ${condition}`);
}
}
function description(value) {
try {
return JSON.stringify(value);
}
catch {
return `[unstringifiable value: ${value}]`;
}
}
function fail(message) {
console.error(message);
throw new Error(message);
}
beforeAll(() => {
jest.setTimeout(50000);
process.env.LIFERAY_THEME_STYLED_PATH = path.dirname(
require.resolve('liferay-frontend-theme-styled/package.json')
);
process.env.LIFERAY_THEME_UNSTYLED_PATH = path.dirname(
require.resolve('liferay-frontend-theme-unstyled/package.json')
);
});
afterAll(() => {
jest.setTimeout(30000);
delete process.env.LIFERAY_THEME_STYLED_PATH;
delete process.env.LIFERAY_THEME_UNSTYLED_PATH;
});
describe('using lib_sass', () => {
let buildPath;
let tempTheme;
afterEach(() => {
cleanTempTheme(tempTheme);
});
beforeEach(() => {
buildPath = undefined;
tempTheme = undefined;
});
it('build task should correctly compile theme', (done) => {
let sassOptionsCalled = false;
tempTheme = setupTempTheme({
init: () =>
registerTasks({
distName: 'base-theme',
gulp: new Gulp(),
hookFn: buildHookFn,
sassOptions: (defaults) => {
sassOptionsCalled = true;
defaults.dartSass = false;
assertTruthy(defaults.includePaths);
return defaults;
},
}),
namespace: 'lib_sass_build_task',
themeConfig: {},
themeName: 'base-theme-7-2',
version: '7.2',
});
buildPath = path.join(
tempTheme.tempPath,
project.options.pathBuild.asNative
);
project.gulp.runSequence('build', () => {
assertTruthy(sassOptionsCalled);
done();
});
});
it('build task should correctly compile theme with dart-sass', (done) => {
tempTheme = setupTempTheme({
init: () =>
registerTasks({
distName: 'base-theme',
gulp: new Gulp(),
hookFn: buildHookFn,
}),
namespace: 'dart_sass_build_task',
themeConfig: {},
themeName: 'base-theme-7-2',
version: '7.2',
});
buildPath = path.join(
tempTheme.tempPath,
project.options.pathBuild.asNative
);
project.gulp.runSequence('build', done);
});
function buildHookFn(gulp) {
gulp.hook('after:build:base', _assertBase);
gulp.hook('after:build:clean', _assertClean);
gulp.hook('after:build:compile-css', _assertCompileCss);
gulp.hook('after:build:hook', _assertHook);
gulp.hook('after:build:fix-at-directives', _assertFixAtDirectives);
gulp.hook('after:build:move-compiled-css', _assertMoveCompiledCss);
gulp.hook('after:build:remove-old-css-dir', _assertRemoveOldCssDir);
gulp.hook('after:build:rename-css-dir', _assertRenameCssDir);
gulp.hook('after:build:src', _assertSrc);
gulp.hook('after:build:themelets', _assertThemelets);
gulp.hook('after:build:web-inf', _assertWebInf);
gulp.hook('after:plugin:war', _assertWar);
gulp.hook('before:build', _assertBeforeBuild);
}
function _assertBase(callback) {
assertExists(buildPath);
callback();
}
function _assertBeforeBuild(callback) {
const distPath = path.join(tempTheme.tempPath, 'dist');
const customSrcPath = path.join(tempTheme.tempPath, 'src');
assertExists(customSrcPath);
assertExists.not(buildPath);
assertExists.not(distPath);
callback();
}
function _assertClean(callback) {
assertExists.not(buildPath);
callback();
}
function _assertCompileCss(callback) {
callback();
}
function _assertHook(callback) {
const hookPath = path.join(buildPath, 'WEB-INF', 'liferay-hook.xml');
assertExists(hookPath);
const liferayHookXML = fs.readFileSync(hookPath, {
encoding: 'utf8',
});
parseString(liferayHookXML, (error, result) => {
if (error) {
throw error;
}
assertEqual(result.hook['language-properties'], [
'content/Language_en.properties',
'content/Language_es.properties',
]);
callback();
});
}
function _assertFixAtDirectives(callback) {
const cssPath = path.join(buildPath, 'css');
const mainCssPath = path.join(cssPath, 'main.css');
assertExists(cssPath);
assertMatches(
fs.readFileSync(mainCssPath, 'utf8'),
/@import\surl\(file\.css\?t=[0-9]+\);/
);
callback();
}
function _assertMoveCompiledCss(callback) {
const cssPath = path.join(buildPath, 'css');
assertExists(cssPath);
callback();
}
function _assertRemoveOldCssDir(callback) {
const cssPath = path.join(buildPath, '_css');
assertExists.not(cssPath);
callback();
}
function _assertRenameCssDir(callback) {
const _cssPath = path.join(buildPath, '_css');
assertExists(_cssPath);
callback();
}
function _assertSrc(callback) {
const cssPath = path.join(buildPath, 'css');
const jsPath = path.join(buildPath, 'js');
const templatesPath = path.join(buildPath, 'templates');
const imagesPath = path.join(buildPath, 'images');
const webInfPath = path.join(buildPath, 'WEB-INF');
assertExists(cssPath);
assertExists(jsPath);
assertExists(imagesPath);
assertExists(webInfPath);
assertExists(templatesPath);
const customCSSFileName = '_custom.scss';
const customCSSPath = path.join(cssPath, customCSSFileName);
const fileContent = stripNewlines(
fs.readFileSync(customCSSPath, {
encoding: 'utf8',
})
);
assertTruthy(
fileContent.indexOf(
'/* inject:imports *//* endinject *//* ' +
customCSSFileName +
' */'
) > -1
);
const mainJsPath = path.join(jsPath, 'main.js');
assertMatches(
fs.readFileSync(mainJsPath, 'utf8'),
/console\.log\('main\.js'\)/
);
const baseTextScssPath = path.join(cssPath, 'base', '_text.scss');
assertExists(baseTextScssPath);
const templateLanguage = project.themeConfig.config.templateLanguage;
const initPath = path.join(templatesPath, 'init.' + templateLanguage);
const initCustomPath = path.join(
templatesPath,
'init_custom.' + templateLanguage
);
const navigationPath = path.join(
templatesPath,
'navigation.' + templateLanguage
);
const portalNormalPath = path.join(
templatesPath,
'portal_normal.' + templateLanguage
);
const portalPopUpPath = path.join(
templatesPath,
'portal_pop_up.' + templateLanguage
);
const portletPath = path.join(
templatesPath,
'portlet.' + templateLanguage
);
assertExists(initPath);
assertExists(initCustomPath);
assertExists(navigationPath);
assertExists(portalNormalPath);
assertExists(portalPopUpPath);
assertExists(portletPath);
assertMatches(fs.readFileSync(portalNormalPath, 'utf8'), /BASE_THEME/);
callback();
}
function _assertThemelets(callback) {
const customScssPath = path.join(
buildPath,
'themelets',
'test-themelet',
'css',
'_custom.scss'
);
const iconPngPath = path.join(
buildPath,
'themelets',
'test-themelet',
'images',
'icon.png'
);
const mainJsPath = path.join(
buildPath,
'themelets',
'test-themelet',
'js',
'main.js'
);
const freemarkerPath = path.join(
buildPath,
'themelets',
'test-themelet',
'templates',
'freemarker.ftl'
);
const velocityPath = path.join(
buildPath,
'themelets',
'test-themelet',
'templates',
'velocity.vm'
);
assertExists(customScssPath);
assertExists(iconPngPath);
assertExists(mainJsPath);
assertExists(freemarkerPath);
assertExists(velocityPath);
const customCSSFileName = '_custom.scss';
const customCSSPath = path.join(buildPath, 'css', customCSSFileName);
assertMatches(
fs.readFileSync(customCSSPath, 'utf8'),
/@import "\.\.\/themelets\/test-themelet\/css\/_custom\.scss";/
);
// TODO: add inject tags to themes when in development
const portalNormalPath = path.join(
buildPath,
'templates',
'portal_normal.ftl'
);
assertMatches(
fs.readFileSync(portalNormalPath, 'utf8'),
/<script src="\${theme_display\.getPathThemeRoot\(\)}\/themelets\/test-themelet\/js\/main\.js"><\/script>/
);
callback();
}
function _assertWar(callback) {
const warPath = path.join(tempTheme.tempPath, 'dist', 'base-theme.war');
assertExists(warPath);
callback();
}
function _assertWebInf(callback) {
const webInfPath = path.join(buildPath, 'WEB-INF');
const pluginPackagePath = path.join(
webInfPath,
'liferay-plugin-package.properties'
);
assertExists(webInfPath);
assertExists(pluginPackagePath);
callback();
}
});