UNPKG

liferay-npm-bundler-preset-reactjs

Version:

liferay npm bundler preset react

948 lines (740 loc) 23.3 kB
/** * SPDX-FileCopyrightText: © 2017 Liferay, Inc. <https://liferay.com> * SPDX-License-Identifier: LGPL-3.0-or-later */ import child_process from 'child_process'; import FilePath from 'liferay-npm-build-tools-common/lib/file-path'; import path from 'path'; import PkgDesc from '../../pkg-desc'; import {Project} from '../index'; /** * Tests by property */ describe('project', () => { let project; beforeAll(() => { project = new Project( path.join(__dirname, '__fixtures__', 'project', 'standard') ); }); it('returns dir', () => { expect(project.dir.toString()).toBe( path.join(__dirname, '__fixtures__', 'project', 'standard') ); }); it('returns buildDir', () => { expect(project.buildDir.asPosix).toBe('./build'); }); it('returns globalConfig', () => { const {globalConfig} = project; expect(globalConfig.imports).toBeDefined(); const expectedImports = [ 'an-osgi-module', 'frontend-js-web', 'frontend-js-node-shims', ]; expectedImports.map((v) => { expect(globalConfig.imports[v]).toBeDefined(); }); expect(globalConfig.imports['an-osgi-module']).toMatchObject({ d3: '>=3.0.0', react: '>=16.8.5', }); expect(globalConfig.imports['frontend-js-web']).toMatchObject({ '/': '>=8.0.0', }); expect(globalConfig.imports['frontend-js-node-shims']).toMatchObject({ assert: '>=1.2.0', punycode: '>=1.3.1', setimmediate: '>=1.0.0', }); }); }); describe('project.copy', () => { let project; beforeAll(() => { project = new Project( path.join(__dirname, '__fixtures__', 'project', 'standard') ); }); it('returns exclusions for configured package@version', () => { const pkg = new PkgDesc('is-array', '1.0.1', __dirname); expect(project.copy.getExclusions(pkg)).toEqual([ 'test/**/*', 'Makefile', ]); }); it('returns exclusions for configured package', () => { const pkg = new PkgDesc('is-object', '1.0.0', __dirname); expect(project.copy.getExclusions(pkg)).toEqual(['test/**/*']); }); it('returns exclusions for unknown package', () => { const pkg = new PkgDesc('other-package', '1.0.0', __dirname); expect(project.copy.getExclusions(pkg)).toEqual(['__tests__/**/*']); }); it('returns ["**/*"] when configured as true', () => { const pkg = new PkgDesc('is-true', '1.0.0', __dirname); expect(project.copy.getExclusions(pkg)).toEqual(['**/*']); }); }); describe('project.jar', () => { let project; beforeAll(() => { project = new Project( path.join(__dirname, '__fixtures__', 'project', 'standard') ); }); it('returns customManifestHeaders', () => { expect(project.jar.customManifestHeaders).toEqual({ // Coming from .npmbundlerrc 'Responsible': 'john.doe@somewhere.net', // Coming from manifest.json 'Project-Web': 'https://somewhere.net/test-project', 'Project-UUID': 'ED7BA470-8E54-465E-825C-99712043E01C', // Coming from both, but .npmbundlerrc wins 'Project-Name': 'Test Project', }); }); it('returns outputDir', () => { expect(project.jar.outputDir.asPosix).toBe('./dist'); }); it('returns supported', () => { expect(project.jar.supported).toBe(true); }); it('returns webContextPath', () => { expect(project.jar.webContextPath).toBe('/standard'); }); }); describe('project.jar.outputFilename', () => { it('returns correct file', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'project', 'standard') ); expect(project.jar.outputFilename).toBe('output.jar'); }); it('returns package name and version if not specified', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'project', 'bool-create-jar') ); expect(project.jar.outputFilename).toBe('bool-create-jar-1.0.0.jar'); }); it('returns a correct file name for scoped packages', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'project', 'scoped') ); expect(project.jar.outputFilename).toBe('@scoped_project-1.0.0.jar'); }); }); describe('project.jar.requireJsExtender', () => { it('returns false when features/js-extender missing and no portlet in package.json', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'project', 'empty') ); expect(project.jar.requireJsExtender).toBe(false); }); it('returns true when features/js-extender missing and there is portlet in package.json', () => { const project = new Project( path.join( __dirname, '__fixtures__', 'project', 'empty-with-portlet' ) ); expect(project.jar.requireJsExtender).toBe(true); }); it('returns false when create-jar config present and features/js-extender false', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'project', 'create-jar') ); expect(project.jar.requireJsExtender).toBe(false); }); }); describe('project.jar.supported', () => { it('works with true boolean config', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'project', 'bool-create-jar') ); expect(project.jar.supported).toBe(true); }); it('works with false boolean config', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'project', 'false-create-jar') ); expect(project.jar.supported).toBe(false); }); }); describe('project.l10n', () => { let project; beforeAll(() => { project = new Project( path.join(__dirname, '__fixtures__', 'project', 'standard') ); }); it('returns availableLocales', () => { expect(project.l10n.availableLocales).toEqual(['es_ES']); }); it('returns labels for default locale', () => { expect(project.l10n.getLabels()).toEqual({ 'test-project': 'Test Project', }); }); it('returns labels for existing locale', () => { expect(project.l10n.getLabels('es_ES')).toEqual({ 'test-project': 'Proyecto de prueba', }); }); it('returns labels for missing locale', () => { expect(project.l10n.getLabels('fr_FR')).toEqual({}); }); it('returns languageFileBaseName', () => { expect(project.l10n.languageFileBaseName.asNative).toEqual( path.join( __dirname, '__fixtures__', 'project', 'standard', 'features', 'localization', 'Language' ) ); }); it('returns localizationFileMap', () => { expect(project.l10n.localizationFileMap).toEqual({ default: new FilePath( path.join( __dirname, '__fixtures__', 'project', 'standard', 'features', 'localization', 'Language.properties' ) ), es_ES: new FilePath( path.join( __dirname, '__fixtures__', 'project', 'standard', 'features', 'localization', 'Language_es_ES.properties' ) ), }); }); it('returns supported', () => { expect(project.l10n.supported).toBe(true); }); }); describe('project.misc', () => { let project; beforeAll(() => { project = new Project( path.join(__dirname, '__fixtures__', 'project', 'standard') ); }); it('return maxParallelFiles', () => { expect(project.misc.maxParallelFiles).toBe(32); }); }); describe('project.pkgManager', () => { const savedSpawnSync = child_process.spawnSync; afterEach(() => { child_process.spawnSync = savedSpawnSync; }); it('returns npm if only package-lock.json exists', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'pkg-manager', 'npm') ); expect(project.pkgManager).toBe('npm'); }); it('returns yarn if only yarn.lock exists', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'pkg-manager', 'yarn') ); expect(project.pkgManager).toBe('yarn'); }); it('returns npm if no file exists and only npm is found', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'pkg-manager', 'none') ); child_process.spawnSync = (cmd) => ({ error: cmd === 'npm' ? undefined : {}, }); expect(project.pkgManager).toBe('npm'); }); it('returns yarn if no file exists and only yarn is found', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'pkg-manager', 'none') ); child_process.spawnSync = (cmd) => ({ error: cmd === 'yarn' ? undefined : {}, }); expect(project.pkgManager).toBe('yarn'); }); it('returns npm if both files exists and only npm is found', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'pkg-manager', 'both') ); child_process.spawnSync = (cmd) => ({ error: cmd === 'npm' ? undefined : {}, }); expect(project.pkgManager).toBe('npm'); }); it('returns yarn if both files exist and only yarn is found', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'pkg-manager', 'both') ); child_process.spawnSync = (cmd) => ({ error: cmd === 'yarn' ? undefined : {}, }); expect(project.pkgManager).toBe('yarn'); }); it('returns null if both files exist and npm and yarn is found', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'pkg-manager', 'both') ); child_process.spawnSync = () => ({ error: undefined, }); expect(project.pkgManager).toBeNull(); }); }); describe('project.transform', () => { let project; beforeAll(() => { project = new Project( path.join(__dirname, '__fixtures__', 'project', 'transform') ); }); it('loads default "pre" plugins correctly', () => { const pkg = new PkgDesc('package-star', '1.0.0', __dirname); const plugins = project.transform.getPrePluginDescriptors(pkg); expect(plugins[0].run({}, {})).toEqual(0); expect(plugins[0].config).toEqual({}); expect(plugins[1].run({}, {})).toEqual(1); expect(plugins[1].config).toEqual('config-1'); }); it('loads default "post" plugins correctly', () => { const pkg = new PkgDesc('package-star', '1.0.0', __dirname); const plugins = project.transform.getPostPluginDescriptors(pkg); expect(plugins[0].run({}, {})).toEqual(2); expect(plugins[0].config).toEqual({}); expect(plugins[1].run({}, {})).toEqual(3); expect(plugins[1].config).toEqual('config-3'); }); it('loads per-package "pre" plugins correctly', () => { const pkg = new PkgDesc('package', '1.0.0', __dirname); const plugins = project.transform.getPrePluginDescriptors(pkg); expect(plugins[0].run({}, {})).toEqual(4); expect(plugins[0].config).toEqual({}); expect(plugins[1].run({}, {})).toEqual(5); expect(plugins[1].config).toEqual('config-5'); }); it('loads per-package "post" plugins correctly', () => { const pkg = new PkgDesc('package', '1.0.0', __dirname); const plugins = project.transform.getPostPluginDescriptors(pkg); expect(plugins[0].run({}, {})).toEqual(6); expect(plugins[0].config).toEqual({}); expect(plugins[1].run({}, {})).toEqual(7); expect(plugins[1].config).toEqual('config-7'); }); it('loads default babel config correctly', () => { const pkg = new PkgDesc('package-star', '1.0.0', __dirname); const config = project.transform.getBabelConfig(pkg); expect(config).toEqual({config: 'config-*'}); }); it('loads per-package-by-id babel config correctly', () => { const pkg = new PkgDesc('package', '1.0.0', __dirname); const config = project.transform.getBabelConfig(pkg); expect(config).toEqual({config: 'config-package@1.0.0'}); }); it('loads per-package-by-name babel config correctly', () => { const pkg = new PkgDesc('package2', '1.0.0', __dirname); const config = project.transform.getBabelConfig(pkg); expect(config).toEqual({config: 'config-package2'}); }); it('loads babel plugins correctly', () => { const pkg = new PkgDesc('package3', '1.0.0', __dirname); const pluginMocks = { raw: () => false, configured: () => false, }; jest.spyOn(project, 'toolResolve').mockImplementation( (moduleName) => moduleName ); jest.spyOn(project, 'toolRequire').mockImplementation( (moduleName) => pluginMocks[moduleName] ); try { const plugins = project.transform.getBabelPlugins(pkg); expect(plugins).toEqual([ pluginMocks['raw'], [pluginMocks['configured'], {the: 'config'}], ]); } finally { jest.restoreAllMocks(); } }); }); describe('project.versionsInfo', () => { it('works', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'project', 'versions-info') ); const versions = project.versionsInfo; expect(versions.size).toEqual(12); expect(versions.get('liferay-npm-bundler')).toMatchObject({ version: require('../../../package.json').version, path: path.join( '..', '..', '..', '..', '..', '..', '..', '..', 'node_modules', 'liferay-npm-bundler' ), }); expect(versions.get('liferay-npm-build-tools-common')).toMatchObject({ version: require('../../../package.json').version, path: path.join('..', '..', '..', '..', '..', '..'), }); expect(versions.get('loader-0')).toMatchObject({ version: '1.0.0', path: path.join('node_modules', 'loader-0'), }); expect(versions.get('liferay-npm-bundler-plugin-test-0')).toMatchObject( { version: '1.0.0', path: path.join( 'node_modules', 'liferay-npm-bundler-plugin-test-0' ), } ); expect(versions.get('bundler-plugins/dir/plugin-0')).toMatchObject({ version: '1.0.0', path: path.join('node_modules', 'bundler-plugins/dir/plugin-0.js'), }); expect(versions.get('liferay-npm-bundler-plugin-test-1')).toMatchObject( { version: '1.0.0', path: path.join( 'node_modules', 'liferay-npm-bundler-plugin-test-1' ), } ); expect(versions.get('bundler-plugins/dir/plugin-1')).toMatchObject({ version: '1.0.0', path: path.join('node_modules', 'bundler-plugins/dir/plugin-1.js'), }); expect(versions.get('babel-plugin-test-0')).toMatchObject({ version: '1.0.0', path: path.join('node_modules', 'babel-plugin-test-0'), }); expect(versions.get('babel-plugins/dir/plugin-0')).toMatchObject({ version: '1.0.0', path: path.join('node_modules', 'babel-plugins/dir/plugin-0.js'), }); expect(versions.get('babel-plugins/dir/plugin-1')).toMatchObject({ version: '1.0.0', path: path.join('node_modules', 'babel-plugins/dir/plugin-1.js'), }); expect(versions.get('loader-0')).toMatchObject({ version: '1.0.0', path: path.join('node_modules', 'loader-0'), }); expect(versions.get('bundler-plugins/dir/loader-0')).toMatchObject({ version: '1.0.0', path: path.join('node_modules', 'bundler-plugins/dir/loader-0.js'), }); expect(versions.get('bundler-plugins/dir/loader-1')).toMatchObject({ version: '1.0.0', path: path.join('node_modules', 'bundler-plugins/dir/loader-1.js'), }); }); }); /** * Tests by orthogonal features */ describe('default features are detected', () => { it('project.l10n.languageFileBaseName', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'default-features') ); expect(project.l10n.languageFileBaseName.asNative).toBe( path.join( project.dir.asNative, 'features', 'localization', 'Language' ) ); }); }); describe('deprecated config', () => { describe('.npmbundlerrc', () => { it('create-jar/auto-deploy-portlet', () => { const project = new Project( path.join( __dirname, '__fixtures__', 'legacy', 'auto-deploy-portlet' ) ); expect(project.jar.requireJsExtender).toBe(false); }); it('create-jar/web-context-path', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'legacy', 'context-path-1') ); expect(project.jar.webContextPath).toBe('/my-portlet'); }); it('supports legacy package configurations correctly', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'legacy', 'packages-cfg') ); const pkg1 = new PkgDesc('package', '1.0.0', __dirname); const pkg2 = new PkgDesc('package2', '1.0.0', __dirname); const pkg3 = new PkgDesc('package3', '1.0.0', __dirname); const pkgOther = new PkgDesc('other-package', '1.0.0', __dirname); let plugins = project.transform.getPrePluginDescriptors(pkg1); expect(plugins[0].run({}, {})).toEqual(1); plugins = project.transform.getPrePluginDescriptors(pkg2); expect(plugins[0].run({}, {})).toEqual(2); plugins = project.transform.getPrePluginDescriptors(pkg3); expect(plugins[0].run({}, {})).toEqual(4); plugins = project.transform.getPrePluginDescriptors(pkgOther); expect(plugins[0].run({}, {})).toEqual(0); }); }); describe('package.json', () => { it('osgi/web-context-path', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'legacy', 'context-path-2') ); expect(project.jar.webContextPath).toBe('/my-portlet'); }); }); }); describe('empty project defaults', () => { let project; beforeAll(() => { project = new Project( path.join(__dirname, '__fixtures__', 'project', 'empty') ); }); it('loads liferay-npm-bundler-preset-standard preset', () => { expect(project._npmbundlerrc['*']['.babelrc']['presets']).toEqual([ 'liferay-standard', ]); }); it('returns dir', () => { expect(project.dir.toString()).toBe( path.join(__dirname, '__fixtures__', 'project', 'empty') ); }); it('returns buildDir', () => { expect(project.buildDir.asPosix).toBe( './build/resources/main/META-INF/resources' ); }); it('return maxParallelFiles', () => { expect(project.misc.maxParallelFiles).toBe(128); }); describe('project.jar', () => { it('returns customManifestHeaders', () => { expect(project.jar.customManifestHeaders).toEqual({}); }); it('returns outputDir', () => { expect(project.jar.outputDir).toBeUndefined(); }); it('returns outputFilename', () => { expect(project.jar.outputFilename).toBeUndefined(); }); it('returns supported', () => { expect(project.jar.supported).toBe(false); }); it('returns webContextPath', () => { expect(project.jar.webContextPath).toBe('/empty-1.0.0'); }); }); describe('project.l10n', () => { it('returns availableLocales', () => { expect(project.l10n.availableLocales).toBeUndefined(); }); it('returns labels for default locale', () => { expect(project.l10n.getLabels()).toBeUndefined(); }); it('returns labels for missing locale', () => { expect(project.l10n.getLabels('fr_FR')).toBeUndefined(); }); it('returns languageFileBaseName', () => { expect(project.l10n.languageFileBaseName).toBeUndefined(); }); it('returns localizationFileMap', () => { expect(project.l10n.localizationFileMap).toBeUndefined(); }); it('returns supported', () => { expect(project.l10n.supported).toBe(false); }); }); }); describe('honors presets', () => { let project; beforeAll(() => { project = new Project( path.join(__dirname, '__fixtures__', 'project', 'with-preset') ); }); it('loads project.dir from preset', () => { expect(project.dir.asNative).toBe( path.join(__dirname, '__fixtures__', 'project', 'with-preset') ); }); it('loads project.buildDir from preset', () => { expect(project.buildDir.asPosix).toBe('./preset-build'); }); it('loads project.jar.outputDir from preset', () => { expect(project.jar.outputDir.asPosix).toBe('./preset-dist'); }); it('detects JAR configuration even if only in preset', () => { expect(project.jar.supported).toBe(true); }); }); describe('handles autopresets', () => { it('loads autopresets', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'project', 'with-autopreset') ); expect(project.buildDir.asPosix).toBe('./autopreset-build'); }); it('fails on multiple autopresets', () => { expect( () => new Project( path.join( __dirname, '__fixtures__', 'project', 'with-two-autopresets' ) ) ).toThrowError(/Multiple autopreset.*autopreset.*autopreset2.*/); }); it('ignores autopresets on explicitly configured preset', () => { const project = new Project( path.join( __dirname, '__fixtures__', 'project', 'with-ignored-autopreset' ) ); expect(project.buildDir.asPosix).toBe('./preset-build'); }); }); describe('loads plugins as modules (as opposed to packages)', () => { let project; beforeAll(() => { project = new Project( path.join(__dirname, '__fixtures__', 'project', 'with-module-cfg') ); }); it('loads preset from file in package', () => { expect(project.buildDir.asPosix).toBe('./preset-output'); }); it('loads loaders from module in package', () => { const loaders = project.rules.loadersForFile('src/index.js'); expect(loaders).toHaveLength(1); const loader = loaders[0]; expect(loader).toMatchObject({ loader: 'a-config/my-js-loader', options: {}, resolvedModule: 'a-config/my-js-loader', }); expect(loader.exec()).toBe('Hi from loader!'); }); it('loads copy plugins from module in package', () => { const pkg = new PkgDesc( 'a-package', '1.0.0', project.dir.join('node_modules', 'a-package').asNative ); const pluginDescriptors = project.copy.getPluginDescriptors(pkg); expect(pluginDescriptors).toHaveLength(1); const pluginDescriptor = pluginDescriptors[0]; expect(pluginDescriptor).toMatchObject({ name: 'a-config/my-copy-plugin', config: {}, }); expect(pluginDescriptor.run()).toBe('Hi from plugin!'); }); it('loads pre plugins from module in package', () => { const pkg = new PkgDesc( 'a-package', '1.0.0', project.dir.join('node_modules', 'a-package').asNative ); const pluginDescriptors = project.transform.getPrePluginDescriptors( pkg ); expect(pluginDescriptors).toHaveLength(1); const pluginDescriptor = pluginDescriptors[0]; expect(pluginDescriptor).toMatchObject({ name: 'a-config/my-pre-plugin', config: {}, }); expect(pluginDescriptor.run()).toBe('Hi from pre plugin!'); }); it('loads post plugins from module in package', () => { const pkg = new PkgDesc( 'a-package', '1.0.0', project.dir.join('node_modules', 'a-package').asNative ); const pluginDescriptors = project.transform.getPostPluginDescriptors( pkg ); expect(pluginDescriptors).toHaveLength(1); const pluginDescriptor = pluginDescriptors[0]; expect(pluginDescriptor).toMatchObject({ name: 'a-config/my-post-plugin', config: {}, }); expect(pluginDescriptor.run()).toBe('Hi from post plugin!'); }); it('loads babel plugins from module in package', () => { const pkg = new PkgDesc( 'a-package', '1.0.0', project.dir.join('node_modules', 'a-package').asNative ); const babelPlugins = project.transform.getBabelPlugins(pkg); expect(babelPlugins).toHaveLength(2); expect(babelPlugins[0]()).toBe("Hi from preset's babel plugin!"); expect(babelPlugins[1]()).toBe('Hi from babel plugin!'); }); }); describe('specific features', () => { describe('project.jar works with boolean config', () => { const project = new Project( path.join(__dirname, '__fixtures__', 'project', 'bool-create-jar') ); expect(project.jar.supported).toBe(true); expect(project.jar.customManifestHeaders).toEqual({}); expect(project.jar.outputDir.asNative).toBe(project.buildDir.asNative); expect(project.jar.outputFilename).toBe('bool-create-jar-1.0.0.jar'); }); });