123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. var path_1 = require("path");
  4. var build = require("./build");
  5. var interfaces_1 = require("./util/interfaces");
  6. var file_cache_1 = require("./util/file-cache");
  7. var watch = require("./watch");
  8. describe('watch', function () {
  9. describe('runBuildUpdate', function () {
  10. it('should require transpile full build for html file add', function () {
  11. var files = [{
  12. event: 'add',
  13. filePath: 'file1.html',
  14. ext: '.html'
  15. }];
  16. watch.runBuildUpdate(context, files);
  17. expect(context.transpileState).toEqual(interfaces_1.BuildState.RequiresBuild);
  18. expect(context.deepLinkState).toEqual(interfaces_1.BuildState.RequiresBuild);
  19. });
  20. it('should require transpile full build for html file change and not already successful bundle', function () {
  21. var files = [{
  22. event: 'change',
  23. filePath: 'file1.html',
  24. ext: '.html'
  25. }];
  26. watch.runBuildUpdate(context, files);
  27. expect(context.transpileState).toEqual(interfaces_1.BuildState.RequiresBuild);
  28. expect(context.deepLinkState).toEqual(interfaces_1.BuildState.RequiresBuild);
  29. });
  30. it('should require template update for html file change and already successful bundle', function () {
  31. var files = [{
  32. event: 'change',
  33. filePath: 'file1.html',
  34. ext: '.html'
  35. }];
  36. context.bundleState = interfaces_1.BuildState.SuccessfulBuild;
  37. watch.runBuildUpdate(context, files);
  38. expect(context.templateState).toEqual(interfaces_1.BuildState.RequiresUpdate);
  39. });
  40. it('should require sass update for ts file unlink', function () {
  41. var files = [{
  42. event: 'unlink',
  43. filePath: 'file1.ts',
  44. ext: '.ts'
  45. }];
  46. watch.runBuildUpdate(context, files);
  47. expect(context.sassState).toEqual(interfaces_1.BuildState.RequiresUpdate);
  48. });
  49. it('should require sass update for ts file add', function () {
  50. var files = [{
  51. event: 'add',
  52. filePath: 'file1.ts',
  53. ext: '.ts'
  54. }];
  55. watch.runBuildUpdate(context, files);
  56. expect(context.sassState).toEqual(interfaces_1.BuildState.RequiresUpdate);
  57. });
  58. it('should require sass update for scss file add', function () {
  59. var files = [{
  60. event: 'add',
  61. filePath: 'file1.scss',
  62. ext: '.scss'
  63. }];
  64. watch.runBuildUpdate(context, files);
  65. expect(context.sassState).toEqual(interfaces_1.BuildState.RequiresUpdate);
  66. });
  67. it('should require sass update for scss file change', function () {
  68. var files = [{
  69. event: 'change',
  70. filePath: 'file1.scss',
  71. ext: '.scss'
  72. }];
  73. watch.runBuildUpdate(context, files);
  74. expect(context.sassState).toEqual(interfaces_1.BuildState.RequiresUpdate);
  75. });
  76. it('should require transpile full build for single ts add, but only bundle update when already successful bundle', function () {
  77. var files = [{
  78. event: 'add',
  79. filePath: 'file1.ts',
  80. ext: '.ts'
  81. }];
  82. context.bundleState = interfaces_1.BuildState.SuccessfulBuild;
  83. watch.runBuildUpdate(context, files);
  84. expect(context.transpileState).toEqual(interfaces_1.BuildState.RequiresBuild);
  85. expect(context.deepLinkState).toEqual(interfaces_1.BuildState.RequiresBuild);
  86. expect(context.bundleState).toEqual(interfaces_1.BuildState.RequiresUpdate);
  87. });
  88. it('should require transpile full build for single ts add', function () {
  89. var files = [{
  90. event: 'add',
  91. filePath: 'file1.ts',
  92. ext: '.ts'
  93. }];
  94. watch.runBuildUpdate(context, files);
  95. expect(context.transpileState).toEqual(interfaces_1.BuildState.RequiresBuild);
  96. expect(context.deepLinkState).toEqual(interfaces_1.BuildState.RequiresBuild);
  97. expect(context.bundleState).toEqual(interfaces_1.BuildState.RequiresBuild);
  98. });
  99. it('should require transpile full build for single ts change and not in file cache', function () {
  100. var files = [{
  101. event: 'change',
  102. filePath: 'file1.ts',
  103. ext: '.ts'
  104. }];
  105. watch.runBuildUpdate(context, files);
  106. expect(context.transpileState).toEqual(interfaces_1.BuildState.RequiresBuild);
  107. expect(context.deepLinkState).toEqual(interfaces_1.BuildState.RequiresBuild);
  108. expect(context.bundleState).toEqual(interfaces_1.BuildState.RequiresBuild);
  109. });
  110. it('should require transpile update only and full bundle build for single ts change and already in file cache and hasnt already had successful bundle', function () {
  111. var files = [{
  112. event: 'change',
  113. filePath: 'file1.ts',
  114. ext: '.ts'
  115. }];
  116. context.bundleState = interfaces_1.BuildState.SuccessfulBuild;
  117. var resolvedFilePath = path_1.resolve('file1.ts');
  118. context.fileCache.set(resolvedFilePath, { path: 'file1.ts', content: 'content' });
  119. watch.runBuildUpdate(context, files);
  120. expect(context.transpileState).toEqual(interfaces_1.BuildState.RequiresUpdate);
  121. expect(context.deepLinkState).toEqual(interfaces_1.BuildState.RequiresUpdate);
  122. expect(context.bundleState).toEqual(interfaces_1.BuildState.RequiresUpdate);
  123. });
  124. it('should require transpile update only and bundle update for single ts change and already in file cache and bundle already successful', function () {
  125. var files = [{
  126. event: 'change',
  127. filePath: 'file1.ts',
  128. ext: '.ts'
  129. }];
  130. var resolvedFilePath = path_1.resolve('file1.ts');
  131. context.fileCache.set(resolvedFilePath, { path: 'file1.ts', content: 'content' });
  132. watch.runBuildUpdate(context, files);
  133. expect(context.transpileState).toEqual(interfaces_1.BuildState.RequiresUpdate);
  134. expect(context.deepLinkState).toEqual(interfaces_1.BuildState.RequiresUpdate);
  135. expect(context.bundleState).toEqual(interfaces_1.BuildState.RequiresBuild);
  136. });
  137. it('should require transpile full build for multiple ts changes', function () {
  138. var files = [{
  139. event: 'change',
  140. filePath: 'file1.ts',
  141. ext: '.ts'
  142. }, {
  143. event: 'change',
  144. filePath: 'file2.ts',
  145. ext: '.ts'
  146. }];
  147. watch.runBuildUpdate(context, files);
  148. expect(context.transpileState).toEqual(interfaces_1.BuildState.RequiresBuild);
  149. expect(context.deepLinkState).toEqual(interfaces_1.BuildState.RequiresBuild);
  150. expect(context.bundleState).toEqual(interfaces_1.BuildState.RequiresBuild);
  151. });
  152. it('should not update bundle state if no transpile changes', function () {
  153. var files = [{
  154. event: 'change',
  155. filePath: 'file1.scss',
  156. ext: '.scss'
  157. }];
  158. watch.runBuildUpdate(context, files);
  159. expect(context.bundleState).toEqual(undefined);
  160. });
  161. it('should do nothing if there are no changed files', function () {
  162. expect(watch.runBuildUpdate(context, [])).toEqual(null);
  163. expect(watch.runBuildUpdate(context, null)).toEqual(null);
  164. });
  165. var context;
  166. beforeEach(function () {
  167. context = {
  168. fileCache: new file_cache_1.FileCache()
  169. };
  170. });
  171. });
  172. describe('prepareWatcher', function () {
  173. it('should do nothing when options.ignored is a function', function () {
  174. var ignoreFn = function () { };
  175. var watcher = { options: { ignored: ignoreFn } };
  176. var context = { srcDir: '/some/src/' };
  177. watch.prepareWatcher(context, watcher);
  178. expect(watcher.options.ignored).toBe(ignoreFn);
  179. });
  180. it('should set replacePathVars when options.ignored is a string', function () {
  181. var watcher = { options: { ignored: path_1.join('{{SRC}}', '**', '*.spec.ts') } };
  182. var context = { srcDir: path_1.join(process.cwd(), 'some', 'src') };
  183. watch.prepareWatcher(context, watcher);
  184. expect(watcher.options.ignored).toEqual(path_1.join(process.cwd(), 'some', 'src', '**', '*.spec.ts'));
  185. });
  186. it('should set replacePathVars when options.ignored is an array of strings', function () {
  187. var watcher = { options: { ignored: [path_1.join('{{SRC}}', '**', '*.spec.ts'), path_1.join('{{SRC}}', 'index.html')] } };
  188. var context = { srcDir: path_1.join(process.cwd(), 'some', 'src') };
  189. watch.prepareWatcher(context, watcher);
  190. expect(watcher.options.ignored[0]).toEqual(path_1.join(process.cwd(), 'some', 'src', '**', '*.spec.ts'));
  191. expect(watcher.options.ignored[1]).toEqual(path_1.join(process.cwd(), 'some', 'src', 'index.html'));
  192. });
  193. it('should set replacePathVars when paths is an array', function () {
  194. var watcher = { paths: [
  195. path_1.join('{{SRC}}', 'some', 'path1'),
  196. path_1.join('{{SRC}}', 'some', 'path2')
  197. ] };
  198. var context = { srcDir: path_1.join(process.cwd(), 'some', 'src') };
  199. watch.prepareWatcher(context, watcher);
  200. expect(watcher.paths.length).toEqual(2);
  201. expect(watcher.paths[0]).toEqual(path_1.join(process.cwd(), 'some', 'src', 'some', 'path1'));
  202. expect(watcher.paths[1]).toEqual(path_1.join(process.cwd(), 'some', 'src', 'some', 'path2'));
  203. });
  204. it('should set replacePathVars when paths is a string', function () {
  205. var watcher = { paths: path_1.join('{{SRC}}', 'some', 'path') };
  206. var context = { srcDir: path_1.join(process.cwd(), 'some', 'src') };
  207. watch.prepareWatcher(context, watcher);
  208. expect(watcher.paths).toEqual(path_1.join(process.cwd(), 'some', 'src', 'some', 'path'));
  209. });
  210. it('should not set options.ignoreInitial if it was provided', function () {
  211. var watcher = { options: { ignoreInitial: false } };
  212. var context = {};
  213. watch.prepareWatcher(context, watcher);
  214. expect(watcher.options.ignoreInitial).toEqual(false);
  215. });
  216. it('should set options.ignoreInitial to true if it wasnt provided', function () {
  217. var watcher = { options: {} };
  218. var context = {};
  219. watch.prepareWatcher(context, watcher);
  220. expect(watcher.options.ignoreInitial).toEqual(true);
  221. });
  222. it('should not set options.cwd from context.rootDir if it was provided', function () {
  223. var watcher = { options: { cwd: '/my/cwd/' } };
  224. var context = { rootDir: '/my/root/dir/' };
  225. watch.prepareWatcher(context, watcher);
  226. expect(watcher.options.cwd).toEqual('/my/cwd/');
  227. });
  228. it('should set options.cwd from context.rootDir if it wasnt provided', function () {
  229. var watcher = {};
  230. var context = { rootDir: '/my/root/dir/' };
  231. watch.prepareWatcher(context, watcher);
  232. expect(watcher.options.cwd).toEqual(context.rootDir);
  233. });
  234. it('should create watcher options when not provided', function () {
  235. var watcher = {};
  236. var context = {};
  237. watch.prepareWatcher(context, watcher);
  238. expect(watcher.options).toBeDefined();
  239. });
  240. });
  241. describe('queueOrRunBuildUpdate', function () {
  242. it('should not queue a build when there isnt an active build', function () {
  243. var changedFileOne = {
  244. event: 'change',
  245. ext: '.ts',
  246. filePath: '/some/fake/path/that/doesnt/matter.ts'
  247. };
  248. var changedFileTwo = {
  249. event: 'change',
  250. ext: '.ts',
  251. filePath: '/some/fake/path/that/doesnt/matter2.ts'
  252. };
  253. var changedFiles = [changedFileOne, changedFileTwo];
  254. var context = {};
  255. spyOn(watch, watch.queueOrRunBuildUpdate.name).and.callThrough();
  256. spyOn(build, build.buildUpdate.name).and.returnValue(Promise.resolve());
  257. var promise = watch.queueOrRunBuildUpdate(changedFiles, context);
  258. return promise.then(function () {
  259. expect(watch.queueOrRunBuildUpdate).toHaveBeenCalledTimes(1);
  260. expect(build.buildUpdate).toHaveBeenCalledWith(changedFiles, context);
  261. expect(watch.buildUpdatePromise).toEqual(null);
  262. expect(watch.queuedChangedFileMap.size).toEqual(0);
  263. });
  264. });
  265. it('should not queue changes when subsequent build is called after the first build', function () {
  266. var changedFileOne = {
  267. event: 'change',
  268. ext: '.ts',
  269. filePath: '/some/fake/path/that/doesnt/matter.ts'
  270. };
  271. var changedFileTwo = {
  272. event: 'change',
  273. ext: '.ts',
  274. filePath: '/some/fake/path/that/doesnt/matter2.ts'
  275. };
  276. var changedFiles = [changedFileOne, changedFileTwo];
  277. var context = {};
  278. spyOn(watch, watch.queueOrRunBuildUpdate.name).and.callThrough();
  279. spyOn(build, build.buildUpdate.name).and.returnValue(Promise.resolve());
  280. var promise = watch.queueOrRunBuildUpdate(changedFiles, context);
  281. return promise.then(function () {
  282. expect(watch.queueOrRunBuildUpdate).toHaveBeenCalledTimes(1);
  283. expect(build.buildUpdate).toHaveBeenCalledWith(changedFiles, context);
  284. expect(watch.buildUpdatePromise).toEqual(null);
  285. expect(watch.queuedChangedFileMap.size).toEqual(0);
  286. return watch.queueOrRunBuildUpdate(changedFiles, context);
  287. }).then(function () {
  288. expect(watch.queueOrRunBuildUpdate).toHaveBeenCalledTimes(2);
  289. expect(build.buildUpdate).toHaveBeenCalledWith(changedFiles, context);
  290. expect(watch.buildUpdatePromise).toEqual(null);
  291. expect(watch.queuedChangedFileMap.size).toEqual(0);
  292. return watch.queueOrRunBuildUpdate(changedFiles, context);
  293. }).then(function () {
  294. expect(watch.queueOrRunBuildUpdate).toHaveBeenCalledTimes(3);
  295. expect(build.buildUpdate).toHaveBeenCalledWith(changedFiles, context);
  296. expect(watch.buildUpdatePromise).toEqual(null);
  297. expect(watch.queuedChangedFileMap.size).toEqual(0);
  298. });
  299. });
  300. it('should queue up changes when a build is active', function () {
  301. var changedFileOne = {
  302. event: 'change',
  303. ext: '.ts',
  304. filePath: '/some/fake/path/that/doesnt/matter.ts'
  305. };
  306. var changedFileTwo = {
  307. event: 'change',
  308. ext: '.ts',
  309. filePath: '/some/fake/path/that/doesnt/matter2.ts'
  310. };
  311. var changedFileThree = {
  312. event: 'change',
  313. ext: '.ts',
  314. filePath: '/some/fake/path/that/doesnt/matter3.ts'
  315. };
  316. var changedFileFour = {
  317. event: 'change',
  318. ext: '.ts',
  319. filePath: '/some/fake/path/that/doesnt/matter4.ts'
  320. };
  321. var changedFileFive = {
  322. event: 'change',
  323. ext: '.ts',
  324. filePath: '/some/fake/path/that/doesnt/matter5.ts'
  325. };
  326. var changedFileSix = {
  327. event: 'change',
  328. ext: '.ts',
  329. filePath: '/some/fake/path/that/doesnt/matter6.ts'
  330. };
  331. var originalChangedFiles = [changedFileOne, changedFileTwo];
  332. var secondSetOfChangedFiles = [changedFileThree, changedFileFour];
  333. var ThirdSetOfChangedFiles = [changedFileTwo, changedFileFour, changedFileFive, changedFileSix];
  334. var context = {};
  335. var firstPromiseResolve = null;
  336. var firstPromise = new Promise(function (resolve, reject) {
  337. firstPromiseResolve = resolve;
  338. });
  339. spyOn(watch, watch.queueOrRunBuildUpdate.name).and.callThrough();
  340. var buildUpdateSpy = spyOn(build, build.buildUpdate.name).and.callFake(function (changedFiles, context) {
  341. if (changedFiles === originalChangedFiles) {
  342. return firstPromise;
  343. }
  344. else {
  345. return Promise.resolve();
  346. }
  347. });
  348. // call the original
  349. expect(watch.buildUpdatePromise).toBeFalsy();
  350. var promise = watch.queueOrRunBuildUpdate(originalChangedFiles, context);
  351. expect(watch.buildUpdatePromise).toBeTruthy();
  352. expect(watch.queuedChangedFileMap.size).toEqual(0);
  353. expect(build.buildUpdate).toHaveBeenCalledTimes(1);
  354. // okay, call again and it should be queued now
  355. watch.queueOrRunBuildUpdate(secondSetOfChangedFiles, context);
  356. expect(watch.buildUpdatePromise).toBeTruthy();
  357. expect(watch.queuedChangedFileMap.size).toEqual(2);
  358. expect(watch.queuedChangedFileMap.get(changedFileThree.filePath)).toEqual(changedFileThree);
  359. expect(watch.queuedChangedFileMap.get(changedFileFour.filePath)).toEqual(changedFileFour);
  360. expect(build.buildUpdate).toHaveBeenCalledTimes(1);
  361. // okay, let's queue some more
  362. watch.queueOrRunBuildUpdate(ThirdSetOfChangedFiles, context);
  363. expect(watch.buildUpdatePromise).toBeTruthy();
  364. expect(watch.queuedChangedFileMap.size).toEqual(5);
  365. expect(watch.queuedChangedFileMap.get(changedFileTwo.filePath)).toEqual(changedFileTwo);
  366. expect(watch.queuedChangedFileMap.get(changedFileThree.filePath)).toEqual(changedFileThree);
  367. expect(watch.queuedChangedFileMap.get(changedFileFour.filePath)).toEqual(changedFileFour);
  368. expect(watch.queuedChangedFileMap.get(changedFileFive.filePath)).toEqual(changedFileFive);
  369. expect(watch.queuedChangedFileMap.get(changedFileSix.filePath)).toEqual(changedFileSix);
  370. expect(build.buildUpdate).toHaveBeenCalledTimes(1);
  371. firstPromiseResolve();
  372. return promise.then(function () {
  373. expect(watch.buildUpdatePromise).toBeFalsy();
  374. expect(watch.queuedChangedFileMap.size).toEqual(0);
  375. expect(build.buildUpdate).toHaveBeenCalledTimes(2);
  376. expect(buildUpdateSpy.calls.first().args[0]).toEqual(originalChangedFiles);
  377. expect(buildUpdateSpy.calls.first().args[1]).toEqual(context);
  378. expect(buildUpdateSpy.calls.mostRecent().args[0].length).toEqual(5);
  379. // make sure the array contains the elements that we expect it to
  380. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileTwo; })[0]).toEqual(changedFileTwo);
  381. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileThree; })[0]).toEqual(changedFileThree);
  382. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileFour; })[0]).toEqual(changedFileFour);
  383. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileFive; })[0]).toEqual(changedFileFive);
  384. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileSix; })[0]).toEqual(changedFileSix);
  385. expect(buildUpdateSpy.calls.mostRecent().args[1]).toEqual(context);
  386. });
  387. });
  388. it('should run buildUpdate on the queued files even if the first build update fails', function () {
  389. var changedFileOne = {
  390. event: 'change',
  391. ext: '.ts',
  392. filePath: '/some/fake/path/that/doesnt/matter.ts'
  393. };
  394. var changedFileTwo = {
  395. event: 'change',
  396. ext: '.ts',
  397. filePath: '/some/fake/path/that/doesnt/matter2.ts'
  398. };
  399. var changedFileThree = {
  400. event: 'change',
  401. ext: '.ts',
  402. filePath: '/some/fake/path/that/doesnt/matter3.ts'
  403. };
  404. var changedFileFour = {
  405. event: 'change',
  406. ext: '.ts',
  407. filePath: '/some/fake/path/that/doesnt/matter4.ts'
  408. };
  409. var changedFileFive = {
  410. event: 'change',
  411. ext: '.ts',
  412. filePath: '/some/fake/path/that/doesnt/matter5.ts'
  413. };
  414. var changedFileSix = {
  415. event: 'change',
  416. ext: '.ts',
  417. filePath: '/some/fake/path/that/doesnt/matter6.ts'
  418. };
  419. var originalChangedFiles = [changedFileOne, changedFileTwo];
  420. var secondSetOfChangedFiles = [changedFileThree, changedFileFour];
  421. var ThirdSetOfChangedFiles = [changedFileTwo, changedFileFour, changedFileFive, changedFileSix];
  422. var context = {};
  423. var firstPromiseReject = null;
  424. var firstPromise = new Promise(function (resolve, reject) {
  425. firstPromiseReject = reject;
  426. });
  427. spyOn(watch, watch.queueOrRunBuildUpdate.name).and.callThrough();
  428. var buildUpdateSpy = spyOn(build, build.buildUpdate.name).and.callFake(function (changedFiles, context) {
  429. if (changedFiles === originalChangedFiles) {
  430. return firstPromise;
  431. }
  432. else {
  433. return Promise.resolve();
  434. }
  435. });
  436. // call the original
  437. expect(watch.buildUpdatePromise).toBeFalsy();
  438. var promise = watch.queueOrRunBuildUpdate(originalChangedFiles, context);
  439. expect(watch.buildUpdatePromise).toBeTruthy();
  440. expect(watch.queuedChangedFileMap.size).toEqual(0);
  441. expect(build.buildUpdate).toHaveBeenCalledTimes(1);
  442. // okay, call again and it should be queued now
  443. watch.queueOrRunBuildUpdate(secondSetOfChangedFiles, context);
  444. expect(watch.buildUpdatePromise).toBeTruthy();
  445. expect(watch.queuedChangedFileMap.size).toEqual(2);
  446. expect(watch.queuedChangedFileMap.get(changedFileThree.filePath)).toEqual(changedFileThree);
  447. expect(watch.queuedChangedFileMap.get(changedFileFour.filePath)).toEqual(changedFileFour);
  448. expect(build.buildUpdate).toHaveBeenCalledTimes(1);
  449. // okay, let's queue some more
  450. watch.queueOrRunBuildUpdate(ThirdSetOfChangedFiles, context);
  451. expect(watch.buildUpdatePromise).toBeTruthy();
  452. expect(watch.queuedChangedFileMap.size).toEqual(5);
  453. expect(watch.queuedChangedFileMap.get(changedFileTwo.filePath)).toEqual(changedFileTwo);
  454. expect(watch.queuedChangedFileMap.get(changedFileThree.filePath)).toEqual(changedFileThree);
  455. expect(watch.queuedChangedFileMap.get(changedFileFour.filePath)).toEqual(changedFileFour);
  456. expect(watch.queuedChangedFileMap.get(changedFileFive.filePath)).toEqual(changedFileFive);
  457. expect(watch.queuedChangedFileMap.get(changedFileSix.filePath)).toEqual(changedFileSix);
  458. expect(build.buildUpdate).toHaveBeenCalledTimes(1);
  459. firstPromiseReject();
  460. return promise.then(function () {
  461. expect(watch.buildUpdatePromise).toBeFalsy();
  462. expect(watch.queuedChangedFileMap.size).toEqual(0);
  463. expect(build.buildUpdate).toHaveBeenCalledTimes(2);
  464. expect(buildUpdateSpy.calls.first().args[0]).toEqual(originalChangedFiles);
  465. expect(buildUpdateSpy.calls.first().args[1]).toEqual(context);
  466. expect(buildUpdateSpy.calls.mostRecent().args[0].length).toEqual(5);
  467. // make sure the array contains the elements that we expect it to
  468. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileTwo; })[0]).toEqual(changedFileTwo);
  469. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileThree; })[0]).toEqual(changedFileThree);
  470. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileFour; })[0]).toEqual(changedFileFour);
  471. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileFive; })[0]).toEqual(changedFileFive);
  472. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileSix; })[0]).toEqual(changedFileSix);
  473. expect(buildUpdateSpy.calls.mostRecent().args[1]).toEqual(context);
  474. });
  475. });
  476. it('should handle multiple queueing and unqueuing events aka advanced test', function () {
  477. var changedFileOne = {
  478. event: 'change',
  479. ext: '.ts',
  480. filePath: '/some/fake/path/that/doesnt/matter.ts'
  481. };
  482. var changedFileTwo = {
  483. event: 'change',
  484. ext: '.ts',
  485. filePath: '/some/fake/path/that/doesnt/matter2.ts'
  486. };
  487. var changedFileThree = {
  488. event: 'change',
  489. ext: '.ts',
  490. filePath: '/some/fake/path/that/doesnt/matter3.ts'
  491. };
  492. var changedFileFour = {
  493. event: 'change',
  494. ext: '.ts',
  495. filePath: '/some/fake/path/that/doesnt/matter4.ts'
  496. };
  497. var changedFileFive = {
  498. event: 'change',
  499. ext: '.ts',
  500. filePath: '/some/fake/path/that/doesnt/matter5.ts'
  501. };
  502. var changedFileSix = {
  503. event: 'change',
  504. ext: '.ts',
  505. filePath: '/some/fake/path/that/doesnt/matter6.ts'
  506. };
  507. var originalChangedFiles = [changedFileOne, changedFileTwo];
  508. var secondSetOfChangedFiles = [changedFileThree, changedFileFour];
  509. var thirdSetOfChangedFiles = [changedFileTwo, changedFileFour, changedFileFive, changedFileSix];
  510. var fourthSetOfChangedFiles = [changedFileOne, changedFileThree];
  511. var fifthSetOfChangedFiles = [changedFileFour, changedFileFive, changedFileSix];
  512. var context = {};
  513. var firstPromiseResolve = null;
  514. var secondPromiseResolve = null;
  515. var thirdPromiseResolve = null;
  516. var firstPromise = new Promise(function (resolve, reject) {
  517. firstPromiseResolve = resolve;
  518. });
  519. var secondPromise = new Promise(function (resolve, reject) {
  520. secondPromiseResolve = resolve;
  521. });
  522. var thirdPromise = new Promise(function (resolve, reject) {
  523. thirdPromiseResolve = resolve;
  524. });
  525. spyOn(watch, watch.queueOrRunBuildUpdate.name).and.callThrough();
  526. var buildUpdateSpy = spyOn(build, build.buildUpdate.name).and.callFake(function (changedFiles, context) {
  527. if (changedFiles === originalChangedFiles) {
  528. return firstPromise;
  529. }
  530. else if (changedFiles.length === 5) {
  531. // hardcode the length for now as it's easier to detect which array it'll be
  532. return secondPromise;
  533. }
  534. else {
  535. return thirdPromise;
  536. }
  537. });
  538. // call the original
  539. expect(watch.buildUpdatePromise).toBeFalsy();
  540. var promise = watch.queueOrRunBuildUpdate(originalChangedFiles, context);
  541. expect(watch.buildUpdatePromise).toBeTruthy();
  542. expect(watch.queuedChangedFileMap.size).toEqual(0);
  543. expect(build.buildUpdate).toHaveBeenCalledTimes(1);
  544. expect(buildUpdateSpy.calls.first().args[0]).toEqual(originalChangedFiles);
  545. expect(buildUpdateSpy.calls.first().args[1]).toEqual(context);
  546. // okay, call again and it should be queued now
  547. watch.queueOrRunBuildUpdate(secondSetOfChangedFiles, context);
  548. expect(watch.buildUpdatePromise).toBeTruthy();
  549. expect(watch.queuedChangedFileMap.size).toEqual(2);
  550. expect(watch.queuedChangedFileMap.get(changedFileThree.filePath)).toEqual(changedFileThree);
  551. expect(watch.queuedChangedFileMap.get(changedFileFour.filePath)).toEqual(changedFileFour);
  552. expect(build.buildUpdate).toHaveBeenCalledTimes(1);
  553. // okay, let's queue some more
  554. watch.queueOrRunBuildUpdate(thirdSetOfChangedFiles, context);
  555. expect(watch.buildUpdatePromise).toBeTruthy();
  556. expect(watch.queuedChangedFileMap.size).toEqual(5);
  557. expect(watch.queuedChangedFileMap.get(changedFileTwo.filePath)).toEqual(changedFileTwo);
  558. expect(watch.queuedChangedFileMap.get(changedFileThree.filePath)).toEqual(changedFileThree);
  559. expect(watch.queuedChangedFileMap.get(changedFileFour.filePath)).toEqual(changedFileFour);
  560. expect(watch.queuedChangedFileMap.get(changedFileFive.filePath)).toEqual(changedFileFive);
  561. expect(watch.queuedChangedFileMap.get(changedFileSix.filePath)).toEqual(changedFileSix);
  562. expect(build.buildUpdate).toHaveBeenCalledTimes(1);
  563. firstPromiseResolve();
  564. return firstPromise.then(function () {
  565. expect(build.buildUpdate).toHaveBeenCalledTimes(2);
  566. expect(buildUpdateSpy.calls.mostRecent().args[0].length).toEqual(5);
  567. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileTwo; })[0]).toEqual(changedFileTwo);
  568. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileThree; })[0]).toEqual(changedFileThree);
  569. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileFour; })[0]).toEqual(changedFileFour);
  570. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileFive; })[0]).toEqual(changedFileFive);
  571. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileSix; })[0]).toEqual(changedFileSix);
  572. expect(buildUpdateSpy.calls.mostRecent().args[1]).toEqual(context);
  573. // okay, give it more changes so it queues that stuff up
  574. // also do some assertions homie
  575. watch.queueOrRunBuildUpdate(fourthSetOfChangedFiles, context);
  576. expect(watch.buildUpdatePromise).toBeTruthy();
  577. expect(watch.queuedChangedFileMap.size).toEqual(2);
  578. expect(watch.queuedChangedFileMap.get(changedFileOne.filePath)).toEqual(changedFileOne);
  579. expect(watch.queuedChangedFileMap.get(changedFileThree.filePath)).toEqual(changedFileThree);
  580. // cool beans yo, go ahead and resolve another promise
  581. secondPromiseResolve();
  582. return secondPromise;
  583. }).then(function () {
  584. expect(build.buildUpdate).toHaveBeenCalledTimes(3);
  585. expect(buildUpdateSpy.calls.mostRecent().args[0].length).toEqual(2);
  586. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileOne; })[0]).toEqual(changedFileOne);
  587. expect(buildUpdateSpy.calls.mostRecent().args[0].concat().filter(function (changedFile) { return changedFile === changedFileThree; })[0]).toEqual(changedFileThree);
  588. // okay, give it more changes so it queues that stuff up
  589. // also do some assertions homie
  590. watch.queueOrRunBuildUpdate(fifthSetOfChangedFiles, context);
  591. expect(watch.buildUpdatePromise).toBeTruthy();
  592. expect(watch.queuedChangedFileMap.size).toEqual(3);
  593. expect(watch.queuedChangedFileMap.get(changedFileFour.filePath)).toEqual(changedFileFour);
  594. expect(watch.queuedChangedFileMap.get(changedFileFive.filePath)).toEqual(changedFileFive);
  595. expect(watch.queuedChangedFileMap.get(changedFileSix.filePath)).toEqual(changedFileSix);
  596. // cool beans yo, go ahead and resolve another promise
  597. thirdPromiseResolve();
  598. return thirdPromise;
  599. }).then(function () {
  600. // return the original promise just to make sure everything is chained together
  601. return promise;
  602. });
  603. });
  604. });
  605. });