utils.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  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 gulp = require( 'gulp' );
  11. const gutil = require( 'gulp-util' );
  12. const path = require( 'path' );
  13. const stream = require( 'stream' );
  14. const Vinyl = require( 'vinyl' );
  15. const through = require( 'through2' );
  16. describe( 'build-utils', () => {
  17. const utils = require( '../../tasks/gulp/build/utils' );
  18. let sandbox;
  19. beforeEach( () => {
  20. sandbox = sinon.sandbox.create();
  21. } );
  22. afterEach( () => {
  23. sandbox.restore();
  24. } );
  25. describe( 'noop', () => {
  26. it( 'should return PassTrough stream', () => {
  27. const PassThrough = stream.PassThrough;
  28. const ret = utils.noop();
  29. expect( ret instanceof PassThrough ).to.equal( true );
  30. } );
  31. it( 'should return a duplex stream when given a callback and call that callback', () => {
  32. const spy = sinon.spy();
  33. const ret = utils.noop( spy );
  34. ret.write( 'foo' );
  35. expect( spy.called ).to.equal( true );
  36. expect( ret.writable ).to.equal( true );
  37. expect( ret.readable ).to.equal( true );
  38. } );
  39. } );
  40. describe( 'dist', () => {
  41. it( 'should return stream created with gulp.dest', () => {
  42. const distDir = 'dist/';
  43. const format = 'amd';
  44. const destSpy = sandbox.spy( gulp, 'dest' );
  45. const stream = utils.dist( distDir, format );
  46. sinon.assert.calledOnce( destSpy );
  47. sinon.assert.calledWithExactly( destSpy, path.join( distDir, format ) );
  48. expect( stream ).to.equal( destSpy.firstCall.returnValue );
  49. } );
  50. } );
  51. describe( 'transpile', () => {
  52. it( 'should return babel transform stream', ( done ) => {
  53. const Stream = stream.Stream;
  54. const modulePath = '../files/utils/lib';
  55. const appendModuleExtensionSpy = sandbox.spy( utils, 'appendModuleExtension' );
  56. const babelStream = utils.transpile( 'amd', utils.getBabelOptionsForTests( 'amd' ) );
  57. expect( babelStream instanceof Stream ).to.equal( true );
  58. expect( babelStream.readable ).to.equal( true );
  59. expect( babelStream.writable ).to.equal( true );
  60. babelStream.on( 'finish', () => {
  61. sinon.assert.calledOnce( appendModuleExtensionSpy );
  62. expect( appendModuleExtensionSpy.args[ 0 ][ 0 ] ).to.equal( modulePath );
  63. done();
  64. } );
  65. babelStream.pipe(
  66. utils.noop( ( file ) => {
  67. expect( file.contents.toString() ).to.match( /define\(\'tests\'/ );
  68. } )
  69. );
  70. babelStream.write( new Vinyl( {
  71. cwd: '/',
  72. base: '/test/',
  73. path: '/test/file.js',
  74. contents: new Buffer( `import * as lib from '${ modulePath }';` )
  75. } ) );
  76. babelStream.end();
  77. } );
  78. it( 'should report error when transpiling fails', ( done ) => {
  79. const babelStream = utils.transpile( 'amd' );
  80. const utilLogStub = sandbox.stub( gutil, 'log' );
  81. const consoleLogStub = sandbox.stub( console, 'log' );
  82. babelStream.once( 'finish', () => {
  83. sinon.assert.calledTwice( utilLogStub );
  84. sinon.assert.calledOnce( consoleLogStub );
  85. done();
  86. } );
  87. babelStream.write( new Vinyl( {
  88. cwd: '/',
  89. base: '/test/',
  90. path: '/test/file.js',
  91. contents: new Buffer( 'class ;' )
  92. } ) );
  93. babelStream.end();
  94. } );
  95. } );
  96. describe( 'getBabelOptionsForSource', () => {
  97. it( 'should return plugins for amd format', () => {
  98. const plugins = [ 'foo' ];
  99. sandbox.stub( utils, 'getBabelPlugins', () => plugins );
  100. const options = utils.getBabelOptionsForSource( 'format' );
  101. expect( options ).to.have.property( 'plugins', plugins );
  102. expect( options ).to.have.property( 'resolveModuleSource' );
  103. } );
  104. } );
  105. describe( 'getBabelOptionsForTests', () => {
  106. it( 'should return plugins for amd format', () => {
  107. const plugins = [ 'foo' ];
  108. sandbox.stub( utils, 'getBabelPlugins', () => plugins );
  109. const options = utils.getBabelOptionsForTests( 'format' );
  110. expect( options ).to.have.property( 'plugins', plugins );
  111. expect( options ).to.have.property( 'resolveModuleSource' );
  112. expect( options ).to.have.property( 'moduleIds', true );
  113. expect( options ).to.have.property( 'moduleId', 'tests' );
  114. } );
  115. } );
  116. describe( 'getBabelPlugins', () => {
  117. it( 'should return plugins for amd format', () => {
  118. expect( utils.getBabelPlugins( 'amd' ) ).to.be.an( 'array' );
  119. } );
  120. it( 'should throw an exception when incorrect format is provided', () => {
  121. const format = 'incorrect-format';
  122. expect( () => {
  123. utils.getBabelPlugins( format );
  124. } ).to.throw( Error, `Incorrect format: ${ format }` );
  125. } );
  126. } );
  127. describe( 'getBabelPlugins', () => {
  128. it( 'should return plugins for amd format', () => {
  129. expect( utils.getBabelPlugins( 'amd' ) ).to.be.an( 'array' );
  130. } );
  131. it( 'should throw an exception when incorrect format is provided', () => {
  132. const format = 'incorrect-format';
  133. expect( () => {
  134. utils.getBabelPlugins( format );
  135. } ).to.throw( Error, `Incorrect format: ${ format }` );
  136. } );
  137. } );
  138. describe( 'getConversionStreamGenerator', () => {
  139. beforeEach( () => {
  140. sandbox.stub( utils, 'getBabelOptionsForSource', () => 'src' );
  141. sandbox.stub( utils, 'getBabelOptionsForTests', () => 'tests' );
  142. // Stub to avoid writing to the fs.
  143. sandbox.stub( utils, 'dist', () => utils.noop() );
  144. // The transpile converted with append to file contents what was
  145. // passed to it as an options object and that's a result of getBabelOptions*,
  146. // which is stubbed above (will return 'src' or 'tests').
  147. sandbox.stub( utils, 'transpile', ( format, options ) => {
  148. return through( { objectMode: true }, ( file, encoding, callback ) => {
  149. file.contents = new Buffer( file.contents.toString() + ';' + format + ';' + options );
  150. callback( null, file );
  151. } );
  152. } );
  153. sandbox.stub( utils, 'appendBenderLauncher', () => {
  154. return through( { objectMode: true }, ( file, encoding, callback ) => {
  155. file.contents = new Buffer( file.contents.toString() + ';launcher' );
  156. callback( null, file );
  157. } );
  158. } );
  159. } );
  160. it( 'should return function that can be used for creating conversion streams', () => {
  161. const distDir = 'dist/';
  162. const formats = [ 'amd', 'cjs', 'esnext' ];
  163. const fn = utils.getConversionStreamGenerator( distDir );
  164. const streams = formats.reduce( fn, [] );
  165. expect( streams.length ).to.equal( formats.length );
  166. } );
  167. describe( 'created conversion stream', () => {
  168. it( 'should process source JS file', ( done ) => {
  169. const distDir = 'dist/';
  170. const formats = [ 'amd' ];
  171. const fn = utils.getConversionStreamGenerator( distDir );
  172. const streams = formats.reduce( fn, [] );
  173. expect( streams ).to.have.length( 1 );
  174. const stream = streams[ 0 ];
  175. stream.pipe(
  176. utils.noop( ( file ) => {
  177. expect( file.contents.toString() ).to.equal( 'foo();amd;src' );
  178. done();
  179. } )
  180. );
  181. stream.write( new Vinyl( {
  182. cwd: './',
  183. path: 'ckeditor5/core/file.js',
  184. contents: new Buffer( 'foo()' )
  185. } ) );
  186. } );
  187. } );
  188. describe( 'created conversion stream', () => {
  189. it( 'should process test file', ( done ) => {
  190. const distDir = 'dist/';
  191. const formats = [ 'cjs' ];
  192. const fn = utils.getConversionStreamGenerator( distDir );
  193. const streams = formats.reduce( fn, [] );
  194. expect( streams ).to.have.length( 1 );
  195. const stream = streams[ 0 ];
  196. stream.pipe(
  197. utils.noop( ( file ) => {
  198. expect( file.contents.toString() ).to.equal( 'foo();cjs;tests;launcher' );
  199. done();
  200. } )
  201. );
  202. stream.write( new Vinyl( {
  203. cwd: './',
  204. path: 'tests/core/file.js',
  205. contents: new Buffer( 'foo()' )
  206. } ) );
  207. } );
  208. } );
  209. } );
  210. describe( 'pickVersionedFile', () => {
  211. it( 'should rename file for provided format', ( done ) => {
  212. const rename = utils.pickVersionedFile( 'amd' );
  213. rename.pipe(
  214. utils.noop( ( data ) => {
  215. expect( data.basename ).to.equal( 'load.js' );
  216. done();
  217. } )
  218. );
  219. rename.write( new Vinyl( {
  220. cwd: '/',
  221. base: '/test/',
  222. path: '/test/load__amd.js',
  223. contents: new Buffer( '' )
  224. } ) );
  225. rename.end();
  226. } );
  227. } );
  228. describe( 'renamePackageFiles', () => {
  229. it( 'should move source files to correct directories', ( done ) => {
  230. const rename = utils.renamePackageFiles();
  231. rename.pipe(
  232. utils.noop( ( data ) => {
  233. expect( data.path ).to.equal( 'ckeditor5/core/foo/file.js' );
  234. done();
  235. } )
  236. );
  237. rename.write( new Vinyl( {
  238. cwd: './',
  239. path: 'ckeditor5-core/src/foo/file.js',
  240. contents: new Buffer( '' )
  241. } ) );
  242. rename.end();
  243. } );
  244. it( 'should move test files to correct directories', ( done ) => {
  245. const rename = utils.renamePackageFiles();
  246. rename.pipe(
  247. utils.noop( ( data ) => {
  248. expect( data.path ).to.equal( 'tests/core/foo/file.js' );
  249. done();
  250. } )
  251. );
  252. rename.write( new Vinyl( {
  253. cwd: './',
  254. path: 'ckeditor5-core/tests/foo/file.js',
  255. contents: new Buffer( '' )
  256. } ) );
  257. rename.end();
  258. } );
  259. it( 'should throw error when wrong path provided 1', () => {
  260. const rename = utils.renamePackageFiles();
  261. expect( () => {
  262. rename.write( new Vinyl( {
  263. cwd: './',
  264. path: 'plugin/src/file.js',
  265. contents: new Buffer( '' )
  266. } ) );
  267. } ).to.throw( Error );
  268. } );
  269. it( 'should throw error when wrong path provided 2', () => {
  270. const rename = utils.renamePackageFiles();
  271. expect( () => {
  272. rename.write( new Vinyl( {
  273. cwd: './',
  274. path: 'ckeditor5-core/file.js',
  275. contents: new Buffer( '' )
  276. } ) );
  277. } ).to.throw( Error );
  278. } );
  279. } );
  280. describe( 'renameCKEditor5Files', () => {
  281. it( 'should move source files to correct directories', ( done ) => {
  282. const rename = utils.renameCKEditor5Files();
  283. rename.pipe(
  284. utils.noop( ( data ) => {
  285. expect( data.path ).to.equal( 'ckeditor5/foo/file.js' );
  286. done();
  287. } )
  288. );
  289. rename.write( new Vinyl( {
  290. cwd: './',
  291. path: 'src/foo/file.js',
  292. contents: new Buffer( '' )
  293. } ) );
  294. rename.end();
  295. } );
  296. it( 'should move test files to correct directories', ( done ) => {
  297. const rename = utils.renameCKEditor5Files();
  298. rename.pipe(
  299. utils.noop( ( data ) => {
  300. expect( data.path ).to.equal( 'tests/foo/file.js' );
  301. done();
  302. } )
  303. );
  304. rename.write( new Vinyl( {
  305. cwd: './',
  306. path: 'tests/foo/file.js',
  307. contents: new Buffer( '' )
  308. } ) );
  309. rename.end();
  310. } );
  311. it( 'should throw error when wrong path provided 1', () => {
  312. const rename = utils.renameCKEditor5Files();
  313. expect( () => {
  314. rename.write( new Vinyl( {
  315. cwd: './',
  316. path: 'plugin/src/file.js',
  317. contents: new Buffer( '' )
  318. } ) );
  319. } ).to.throw( Error );
  320. } );
  321. } );
  322. describe( 'appendModuleExtension', () => {
  323. it( 'appends module extension when path provided', () => {
  324. const filePath = './path/to/file';
  325. const source = utils.appendModuleExtension( filePath );
  326. expect( source ).to.equal( filePath + '.js' );
  327. } );
  328. it( 'appends module extension when URL is provided', () => {
  329. const url = 'http://example.com/lib';
  330. const source = utils.appendModuleExtension( url );
  331. expect( source ).to.equal( url + '.js' );
  332. } );
  333. it( 'returns unchanged if module is provided', () => {
  334. const module = 'lib/module';
  335. const source = utils.appendModuleExtension( module );
  336. expect( source ).to.equal( module );
  337. } );
  338. } );
  339. describe( 'appendBenderLauncher', () => {
  340. it( 'appends the launcher code to a file', ( done ) => {
  341. const stream = utils.appendBenderLauncher();
  342. stream.pipe(
  343. utils.noop( ( data ) => {
  344. expect( data.contents.toString() ).equal( 'foo();' + utils.benderLauncherCode );
  345. done();
  346. } )
  347. );
  348. stream.write( new Vinyl( {
  349. cwd: './',
  350. path: 'tests/file.js',
  351. contents: new Buffer( 'foo();' )
  352. } ) );
  353. stream.end();
  354. } );
  355. // #62
  356. it( 'does nothing to a null file', ( done ) => {
  357. const stream = utils.appendBenderLauncher();
  358. stream.pipe(
  359. utils.noop( ( data ) => {
  360. expect( data.contents ).to.equal( null );
  361. done();
  362. } )
  363. );
  364. stream.write( new Vinyl( {
  365. cwd: './',
  366. path: 'tests/file.js',
  367. contents: null
  368. } ) );
  369. stream.end();
  370. } );
  371. } );
  372. describe( 'isTestFile', () => {
  373. function test( path, expected ) {
  374. it( `returns ${ expected} for ${ path }`, () => {
  375. const file = new Vinyl( {
  376. cwd: './',
  377. path: path,
  378. contents: new Buffer( '' )
  379. } );
  380. expect( utils.isTestFile( file ) ).to.equal( expected );
  381. } );
  382. }
  383. test( 'tests/file.js', true );
  384. test( 'tests/foo/file.js', true );
  385. test( 'tests/tests.js', true );
  386. test( 'foo/file.js', false );
  387. test( 'foo/tests/file.js', false );
  388. test( 'tests/_foo/file.js', false );
  389. } );
  390. } );