utils.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /* global describe, it, beforeEach, afterEach */
  6. 'use strict';
  7. const chai = require( 'chai' );
  8. const expect = chai.expect;
  9. const sinon = require( 'sinon' );
  10. const path = require( 'path' );
  11. const fs = require( 'fs' );
  12. const mainUtils = require( '../../tasks/utils' );
  13. const gzipSize = require( 'gzip-size' );
  14. describe( 'bundle-utils', () => {
  15. const utils = require( '../../tasks/bundle/utils' );
  16. let sandbox;
  17. beforeEach( () => {
  18. sandbox = sinon.sandbox.create();
  19. } );
  20. afterEach( () => {
  21. sandbox.restore();
  22. } );
  23. it( 'should be extended by top level utils', () => {
  24. expect( utils.clean ).to.equal( mainUtils.clean );
  25. } );
  26. describe( 'getModuleFullPath', () => {
  27. it( 'should return full path when passed path not relative', () => {
  28. expect( utils.getModuleFullPath( 'editor-classic/classic' ) ).to.equal( './build/esnext/ckeditor5/editor-classic/classic.js' );
  29. } );
  30. it( 'should return unmodified path when passed path is a relative', () => {
  31. expect( utils.getModuleFullPath( './path/to/editor-classic/classic' ) ).to.equal( './path/to/editor-classic/classic.js' );
  32. expect( utils.getModuleFullPath( '../path/to/editor-classic/classic' ) ).to.equal( '../path/to/editor-classic/classic.js' );
  33. } );
  34. } );
  35. describe( 'getPluginPath()', () => {
  36. it( 'should resolve a simple plugin name to the full path', () => {
  37. expect( utils.getPluginPath( 'typing' ) ).to.equal( './build/esnext/ckeditor5/typing/typing.js' );
  38. } );
  39. it( 'should return full path if passed argument is a relative path', () => {
  40. expect( utils.getPluginPath( 'typing/typing' ) ).to.equal( './build/esnext/ckeditor5/typing/typing.js' );
  41. } );
  42. it( 'should return unmodified plugin path if passed argument is a relative path', () => {
  43. expect( utils.getPluginPath( './typing' ) ).to.equal( './typing.js' );
  44. expect( utils.getPluginPath( '../typing' ) ).to.equal( '../typing.js' );
  45. } );
  46. } );
  47. describe( 'capitalize()', () => {
  48. it( 'should transform first letter of the passed string to uppercase', () => {
  49. expect( utils.capitalize( 'string' ) ).to.equal( 'String' );
  50. expect( utils.capitalize( 'multi word string' ) ).to.equal( 'Multi word string' );
  51. } );
  52. } );
  53. describe( 'renderEntryFileContent()', () => {
  54. it( 'should render file content with proper data', () => {
  55. const result = utils.renderEntryFileContent( './bundle/tmp', {
  56. moduleName: 'MyCKEditor',
  57. editor: 'editor-classic/classic',
  58. features: [
  59. 'delete',
  60. 'path/to/default',
  61. './path/to/custom'
  62. ]
  63. } );
  64. const expected = `
  65. 'use strict';
  66. // Babel helpers.
  67. import '../../node_modules/regenerator-runtime/runtime.js';
  68. import Classic from '../../build/esnext/ckeditor5/editor-classic/classic.js';
  69. import Delete from '../../build/esnext/ckeditor5/delete/delete.js';
  70. import Default from '../../build/esnext/ckeditor5/path/to/default.js';
  71. import Custom from '../../path/to/custom.js';
  72. export default class MyCKEditor extends Classic {
  73. static create( element, config = {} ) {
  74. if ( !config.features ) {
  75. config.features = [];
  76. }
  77. config.features = [ ...config.features, Delete, Default, Custom ];
  78. return Classic.create( element, config );
  79. }
  80. }
  81. `;
  82. expect( result ).to.equal( expected );
  83. } );
  84. it( 'should render file content with unique plugin names', () => {
  85. const result = utils.renderEntryFileContent( './bundle/tmp', {
  86. moduleName: 'MyCKEditor',
  87. editor: 'editor-classic/classic',
  88. features: [
  89. 'plugin',
  90. 'path/to/plugin',
  91. 'other/path/to/plugin'
  92. ]
  93. } );
  94. const expected = `
  95. 'use strict';
  96. // Babel helpers.
  97. import '../../node_modules/regenerator-runtime/runtime.js';
  98. import Classic from '../../build/esnext/ckeditor5/editor-classic/classic.js';
  99. import Plugin from '../../build/esnext/ckeditor5/plugin/plugin.js';
  100. import Plugin1 from '../../build/esnext/ckeditor5/path/to/plugin.js';
  101. import Plugin2 from '../../build/esnext/ckeditor5/other/path/to/plugin.js';
  102. export default class MyCKEditor extends Classic {
  103. static create( element, config = {} ) {
  104. if ( !config.features ) {
  105. config.features = [];
  106. }
  107. config.features = [ ...config.features, Plugin, Plugin1, Plugin2 ];
  108. return Classic.create( element, config );
  109. }
  110. }
  111. `;
  112. expect( result ).to.equal( expected );
  113. } );
  114. it( 'should render file content with proper without features', () => {
  115. const result = utils.renderEntryFileContent( './bundle/tmp', {
  116. moduleName: 'MyCKEditor',
  117. editor: 'editor-classic/classic'
  118. } );
  119. const expected = `
  120. 'use strict';
  121. // Babel helpers.
  122. import '../../node_modules/regenerator-runtime/runtime.js';
  123. import Classic from '../../build/esnext/ckeditor5/editor-classic/classic.js';
  124. export default class MyCKEditor extends Classic {
  125. static create( element, config = {} ) {
  126. if ( !config.features ) {
  127. config.features = [];
  128. }
  129. config.features = [ ...config.features, ];
  130. return Classic.create( element, config );
  131. }
  132. }
  133. `;
  134. expect( result ).to.equal( expected );
  135. } );
  136. } );
  137. describe( 'getFileSize', () => {
  138. it( 'should return file size in bytes', () => {
  139. const filePath = 'path/to/file';
  140. const size = 1337;
  141. const statSyncMock = sandbox.stub( fs, 'statSync', () => {
  142. return { size };
  143. } );
  144. expect( utils.getFileSize( filePath ) ).to.be.equal( size );
  145. sinon.assert.calledWithExactly( statSyncMock, filePath );
  146. } );
  147. } );
  148. describe( 'getGzippedFileSize', () => {
  149. it( 'should return file size in bytes', () => {
  150. const filePath = 'path/to/file';
  151. const size = 1337;
  152. const fileContent = 'some string';
  153. const readFileSyncMock = sandbox.stub( fs, 'readFileSync', () => fileContent );
  154. const gzipSizeMock = sandbox.stub( gzipSize, 'sync', () => 1337 );
  155. expect( utils.getGzippedFileSize( filePath ) ).to.be.equal( size );
  156. sinon.assert.calledWithExactly( readFileSyncMock, filePath );
  157. sinon.assert.calledWithExactly( gzipSizeMock, fileContent );
  158. } );
  159. } );
  160. describe( 'getFilesSizeStats', () => {
  161. let size, gzippedSize;
  162. beforeEach( () => {
  163. size = 1337;
  164. gzippedSize = 543;
  165. sandbox.stub( utils, 'getFileSize', () => size );
  166. sandbox.stub( utils, 'getGzippedFileSize', () => gzippedSize );
  167. } );
  168. it( 'should returns an array with two elements', () => {
  169. const result = utils.getFilesSizeStats( [ 'sub/dir/file.js', 'other/sub/dir/file.css' ], 'root/path' );
  170. expect( result ).to.be.an( 'array' );
  171. expect( result ).to.have.length( 2 );
  172. } );
  173. it( 'should returns list of object with files stats', () => {
  174. const result = utils.getFilesSizeStats( [ 'sub/dir/file.js', 'other/sub/dir/file.css' ], 'root/path' );
  175. expect( result ).to.be.deep.equal( [
  176. { name: 'file.js', size, gzippedSize },
  177. { name: 'file.css', size, gzippedSize }
  178. ] );
  179. } );
  180. it( 'should get files from root directory', () => {
  181. let basenameSpy = sandbox.spy( path, 'basename' );
  182. const result = utils.getFilesSizeStats( [ 'sub/dir/file.js', 'other/sub/dir/file.css' ], 'root/path' );
  183. expect( result[ 0 ] ).to.have.property( 'name', 'file.js' );
  184. expect( result[ 1 ] ).to.have.property( 'name', 'file.css' );
  185. sinon.assert.calledWithExactly( basenameSpy.firstCall, 'root/path/sub/dir/file.js' );
  186. sinon.assert.calledWithExactly( basenameSpy.secondCall, 'root/path/other/sub/dir/file.css' );
  187. } );
  188. it( 'should get files if root directory is not specified', () => {
  189. let basenameSpy = sandbox.spy( path, 'basename' );
  190. const result = utils.getFilesSizeStats( [ 'sub/dir/file.js', 'file.css' ] );
  191. expect( result[ 0 ] ).to.have.property( 'name', 'file.js' );
  192. expect( result[ 1 ] ).to.have.property( 'name', 'file.css' );
  193. sinon.assert.calledWithExactly( basenameSpy.firstCall, 'sub/dir/file.js' );
  194. sinon.assert.calledWithExactly( basenameSpy.secondCall, 'file.css' );
  195. } );
  196. } );
  197. } );