|
|
@@ -0,0 +1,254 @@
|
|
|
+/**
|
|
|
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
|
|
|
+ * For licensing, see LICENSE.md.
|
|
|
+ */
|
|
|
+
|
|
|
+/* global describe, it, beforeEach, afterEach */
|
|
|
+
|
|
|
+'use strict';
|
|
|
+
|
|
|
+const chai = require( 'chai' );
|
|
|
+const expect = chai.expect;
|
|
|
+const sinon = require( 'sinon' );
|
|
|
+const path = require( 'path' );
|
|
|
+const fs = require( 'fs' );
|
|
|
+const mainUtils = require( '../../tasks/utils' );
|
|
|
+const gzipSize = require( 'gzip-size' );
|
|
|
+
|
|
|
+describe( 'bundle-utils', () => {
|
|
|
+ const utils = require( '../../tasks/bundle/utils' );
|
|
|
+ let sandbox;
|
|
|
+
|
|
|
+ beforeEach( () => {
|
|
|
+ sandbox = sinon.sandbox.create();
|
|
|
+ } );
|
|
|
+
|
|
|
+ afterEach( () => {
|
|
|
+ sandbox.restore();
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'should be extended by top level utils', () => {
|
|
|
+ expect( utils.clean ).to.equal( mainUtils.clean );
|
|
|
+ } );
|
|
|
+
|
|
|
+ describe( 'getModuleFullPath', () => {
|
|
|
+ it( 'should return full path when passed path not relative', () => {
|
|
|
+ expect( utils.getModuleFullPath( 'editor-classic/classic' ) ).to.equal( './build/esnext/ckeditor5/editor-classic/classic.js' );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'should return unmodified path when passed path is a relative', () => {
|
|
|
+ expect( utils.getModuleFullPath( './path/to/editor-classic/classic' ) ).to.equal( './path/to/editor-classic/classic.js' );
|
|
|
+ expect( utils.getModuleFullPath( '../path/to/editor-classic/classic' ) ).to.equal( '../path/to/editor-classic/classic.js' );
|
|
|
+ } );
|
|
|
+ } );
|
|
|
+
|
|
|
+ describe( 'getPluginPath()', () => {
|
|
|
+ it( 'should resolve a simple plugin name to the full path', () => {
|
|
|
+ expect( utils.getPluginPath( 'typing' ) ).to.equal( './build/esnext/ckeditor5/typing/typing.js' );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'should return full path if passed argument is a relative path', () => {
|
|
|
+ expect( utils.getPluginPath( 'typing/typing' ) ).to.equal( './build/esnext/ckeditor5/typing/typing.js' );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'should return unmodified plugin path if passed argument is a relative path', () => {
|
|
|
+ expect( utils.getPluginPath( './typing' ) ).to.equal( './typing.js' );
|
|
|
+ expect( utils.getPluginPath( '../typing' ) ).to.equal( '../typing.js' );
|
|
|
+ } );
|
|
|
+ } );
|
|
|
+
|
|
|
+ describe( 'capitalize()', () => {
|
|
|
+ it( 'should transform first letter of the passed string to uppercase', () => {
|
|
|
+ expect( utils.capitalize( 'string' ) ).to.equal( 'String' );
|
|
|
+ expect( utils.capitalize( 'multi word string' ) ).to.equal( 'Multi word string' );
|
|
|
+ } );
|
|
|
+ } );
|
|
|
+
|
|
|
+ describe( 'renderEntryFileContent()', () => {
|
|
|
+ it( 'should render file content with proper data', () => {
|
|
|
+ const result = utils.renderEntryFileContent( './bundle/tmp', {
|
|
|
+ moduleName: 'MyCKEditor',
|
|
|
+ editor: 'editor-classic/classic',
|
|
|
+ features: [
|
|
|
+ 'delete',
|
|
|
+ 'path/to/default',
|
|
|
+ './path/to/custom'
|
|
|
+ ]
|
|
|
+ } );
|
|
|
+
|
|
|
+ const expected = `
|
|
|
+'use strict';
|
|
|
+
|
|
|
+// Babel helpers.
|
|
|
+import '../../node_modules/regenerator-runtime/runtime.js';
|
|
|
+
|
|
|
+import Classic from '../../build/esnext/ckeditor5/editor-classic/classic.js';
|
|
|
+import Delete from '../../build/esnext/ckeditor5/delete/delete.js';
|
|
|
+import Default from '../../build/esnext/ckeditor5/path/to/default.js';
|
|
|
+import Custom from '../../path/to/custom.js';
|
|
|
+
|
|
|
+
|
|
|
+export default class MyCKEditor extends Classic {
|
|
|
+ static create( element, config = {} ) {
|
|
|
+ if ( !config.features ) {
|
|
|
+ config.features = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ config.features = [ ...config.features, Delete, Default, Custom ];
|
|
|
+
|
|
|
+ return Classic.create( element, config );
|
|
|
+ }
|
|
|
+}
|
|
|
+`;
|
|
|
+
|
|
|
+ expect( result ).to.equal( expected );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'should render file content with unique plugin names', () => {
|
|
|
+ const result = utils.renderEntryFileContent( './bundle/tmp', {
|
|
|
+ moduleName: 'MyCKEditor',
|
|
|
+ editor: 'editor-classic/classic',
|
|
|
+ features: [
|
|
|
+ 'plugin',
|
|
|
+ 'path/to/plugin',
|
|
|
+ 'other/path/to/plugin'
|
|
|
+ ]
|
|
|
+ } );
|
|
|
+
|
|
|
+ const expected = `
|
|
|
+'use strict';
|
|
|
+
|
|
|
+// Babel helpers.
|
|
|
+import '../../node_modules/regenerator-runtime/runtime.js';
|
|
|
+
|
|
|
+import Classic from '../../build/esnext/ckeditor5/editor-classic/classic.js';
|
|
|
+import Plugin from '../../build/esnext/ckeditor5/plugin/plugin.js';
|
|
|
+import Plugin1 from '../../build/esnext/ckeditor5/path/to/plugin.js';
|
|
|
+import Plugin2 from '../../build/esnext/ckeditor5/other/path/to/plugin.js';
|
|
|
+
|
|
|
+
|
|
|
+export default class MyCKEditor extends Classic {
|
|
|
+ static create( element, config = {} ) {
|
|
|
+ if ( !config.features ) {
|
|
|
+ config.features = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ config.features = [ ...config.features, Plugin, Plugin1, Plugin2 ];
|
|
|
+
|
|
|
+ return Classic.create( element, config );
|
|
|
+ }
|
|
|
+}
|
|
|
+`;
|
|
|
+
|
|
|
+ expect( result ).to.equal( expected );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'should render file content with proper without features', () => {
|
|
|
+ const result = utils.renderEntryFileContent( './bundle/tmp', {
|
|
|
+ moduleName: 'MyCKEditor',
|
|
|
+ editor: 'editor-classic/classic'
|
|
|
+ } );
|
|
|
+
|
|
|
+ const expected = `
|
|
|
+'use strict';
|
|
|
+
|
|
|
+// Babel helpers.
|
|
|
+import '../../node_modules/regenerator-runtime/runtime.js';
|
|
|
+
|
|
|
+import Classic from '../../build/esnext/ckeditor5/editor-classic/classic.js';
|
|
|
+
|
|
|
+
|
|
|
+export default class MyCKEditor extends Classic {
|
|
|
+ static create( element, config = {} ) {
|
|
|
+ if ( !config.features ) {
|
|
|
+ config.features = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ config.features = [ ...config.features, ];
|
|
|
+
|
|
|
+ return Classic.create( element, config );
|
|
|
+ }
|
|
|
+}
|
|
|
+`;
|
|
|
+
|
|
|
+ expect( result ).to.equal( expected );
|
|
|
+ } );
|
|
|
+ } );
|
|
|
+
|
|
|
+ describe( 'getFileSize', () => {
|
|
|
+ it( 'should return file size in bytes', () => {
|
|
|
+ const filePath = 'path/to/file';
|
|
|
+ const size = 1337;
|
|
|
+ const statSyncMock = sandbox.stub( fs, 'statSync', () => {
|
|
|
+ return { size };
|
|
|
+ } );
|
|
|
+
|
|
|
+ expect( utils.getFileSize( filePath ) ).to.be.equal( size );
|
|
|
+ sinon.assert.calledWithExactly( statSyncMock, filePath );
|
|
|
+ } );
|
|
|
+ } );
|
|
|
+
|
|
|
+ describe( 'getGzippedFileSize', () => {
|
|
|
+ it( 'should return file size in bytes', () => {
|
|
|
+ const filePath = 'path/to/file';
|
|
|
+ const size = 1337;
|
|
|
+ const fileContent = 'some string';
|
|
|
+ const readFileSyncMock = sandbox.stub( fs, 'readFileSync', () => fileContent );
|
|
|
+ const gzipSizeMock = sandbox.stub( gzipSize, 'sync', () => 1337 );
|
|
|
+
|
|
|
+ expect( utils.getGzippedFileSize( filePath ) ).to.be.equal( size );
|
|
|
+ sinon.assert.calledWithExactly( readFileSyncMock, filePath );
|
|
|
+ sinon.assert.calledWithExactly( gzipSizeMock, fileContent );
|
|
|
+ } );
|
|
|
+ } );
|
|
|
+
|
|
|
+ describe( 'getFilesSizeStats', () => {
|
|
|
+ let size, gzippedSize;
|
|
|
+
|
|
|
+ beforeEach( () => {
|
|
|
+ size = 1337;
|
|
|
+ gzippedSize = 543;
|
|
|
+
|
|
|
+ sandbox.stub( utils, 'getFileSize', () => size );
|
|
|
+ sandbox.stub( utils, 'getGzippedFileSize', () => gzippedSize );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'should returns an array with two elements', () => {
|
|
|
+ const result = utils.getFilesSizeStats( [ 'sub/dir/file.js', 'other/sub/dir/file.css' ], 'root/path' );
|
|
|
+
|
|
|
+ expect( result ).to.be.an( 'array' );
|
|
|
+ expect( result ).to.have.length( 2 );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'should returns list of object with files stats', () => {
|
|
|
+ const result = utils.getFilesSizeStats( [ 'sub/dir/file.js', 'other/sub/dir/file.css' ], 'root/path' );
|
|
|
+
|
|
|
+ expect( result ).to.be.deep.equal( [
|
|
|
+ { name: 'file.js', size, gzippedSize },
|
|
|
+ { name: 'file.css', size, gzippedSize }
|
|
|
+ ] );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'should get files from root directory', () => {
|
|
|
+ let basenameSpy = sandbox.spy( path, 'basename' );
|
|
|
+
|
|
|
+ const result = utils.getFilesSizeStats( [ 'sub/dir/file.js', 'other/sub/dir/file.css' ], 'root/path' );
|
|
|
+
|
|
|
+ expect( result[ 0 ] ).to.have.property( 'name', 'file.js' );
|
|
|
+ expect( result[ 1 ] ).to.have.property( 'name', 'file.css' );
|
|
|
+ sinon.assert.calledWithExactly( basenameSpy.firstCall, 'root/path/sub/dir/file.js' );
|
|
|
+ sinon.assert.calledWithExactly( basenameSpy.secondCall, 'root/path/other/sub/dir/file.css' );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'should get files if root directory is not specified', () => {
|
|
|
+ let basenameSpy = sandbox.spy( path, 'basename' );
|
|
|
+
|
|
|
+ const result = utils.getFilesSizeStats( [ 'sub/dir/file.js', 'file.css' ] );
|
|
|
+
|
|
|
+ expect( result[ 0 ] ).to.have.property( 'name', 'file.js' );
|
|
|
+ expect( result[ 1 ] ).to.have.property( 'name', 'file.css' );
|
|
|
+ sinon.assert.calledWithExactly( basenameSpy.firstCall, 'sub/dir/file.js' );
|
|
|
+ sinon.assert.calledWithExactly( basenameSpy.secondCall, 'file.css' );
|
|
|
+ } );
|
|
|
+ } );
|
|
|
+} );
|