Model.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. describe('Model', function() {
  2. var Model = $.fullCalendar.Model;
  3. describe('set/get', function() {
  4. it('retrieves a previously set value', function() {
  5. var funcs = {
  6. change: function(val) {
  7. expect(val).toBe(5);
  8. }
  9. };
  10. var spy = spyOn(funcs, 'change').and.callThrough();
  11. var m = new Model();
  12. m.on('change:myvar', funcs.change);
  13. m.set('myvar', 5);
  14. expect(m.get('myvar')).toBe(5);
  15. expect(spy).toHaveBeenCalled();
  16. });
  17. it('retrieves values previously set in bulk', function() {
  18. var m = new Model();
  19. m.set({
  20. myvar: 5,
  21. myothervar: 6
  22. });
  23. expect(m.get('myvar')).toBe(5);
  24. expect(m.get('myothervar')).toBe(6);
  25. });
  26. it('retrieves undefined when not previously set', function() {
  27. var m = new Model();
  28. expect(m.get('myvar')).toBeUndefined();
  29. });
  30. it('can retreive whole internal object', function() {
  31. var m = new Model();
  32. m.set({
  33. myvar: 5,
  34. myothervar: 6
  35. });
  36. expect(m.get()).toEqual({
  37. myvar: 5,
  38. myothervar: 6
  39. });
  40. });
  41. it('fires all before:change events beforehand when setting in bulk', function() {
  42. var ops = [];
  43. var m = new Model();
  44. m.set({
  45. myvar: 5,
  46. myothervar: 6
  47. });
  48. m.on('before:change:myvar', function(val) {
  49. ops.push('before:change:myvar');
  50. });
  51. m.on('before:change:myothervar', function(val) {
  52. ops.push('before:change:myothervar');
  53. });
  54. m.on('change:myvar', function(val) {
  55. ops.push('change:myvar');
  56. });
  57. m.on('change:myothervar', function(val) {
  58. ops.push('change:myothervar');
  59. });
  60. m.set({
  61. myvar: 7,
  62. myothervar: 8
  63. });
  64. expect(ops).toEqual([
  65. 'before:change:myvar',
  66. 'before:change:myothervar',
  67. 'change:myvar',
  68. 'change:myothervar'
  69. ]);
  70. });
  71. });
  72. describe('unset', function() {
  73. it('can unset a single prop', function() {
  74. var m = new Model();
  75. m.set({
  76. myvar: 5,
  77. myothervar: 6
  78. });
  79. m.unset('myvar');
  80. expect(m.get()).toEqual({
  81. myothervar: 6
  82. });
  83. });
  84. it('can unset multiple props', function() {
  85. var m = new Model();
  86. m.set({
  87. myvar: 5,
  88. myothervar: 6,
  89. myothervarr: 7
  90. });
  91. m.unset([ 'myvar', 'myothervar' ]);
  92. expect(m.get()).toEqual({
  93. myothervarr: 7
  94. });
  95. });
  96. });
  97. describe('reset', function() {
  98. it('will change all props', function() {
  99. var m = new Model();
  100. m.set({
  101. foo1: 5,
  102. foo2: 6
  103. });
  104. m.reset({
  105. bar1: 7,
  106. bar2: 8
  107. });
  108. expect(m.get()).toEqual({
  109. bar1: 7,
  110. bar2: 8
  111. });
  112. });
  113. });
  114. describe('has', function() {
  115. it('reports false when not previously set', function() {
  116. var m = new Model();
  117. expect(m.has('myvar')).toBe(false);
  118. });
  119. it('reports true when previously set', function() {
  120. var m = new Model();
  121. m.set('myvar', 5);
  122. expect(m.has('myvar')).toBe(true);
  123. });
  124. });
  125. describe('watch', function() {
  126. describe('when called as a task', function() {
  127. describe('when no deps', function() {
  128. it('resolves immediately', function() {
  129. var funcs = {
  130. start: function() { }
  131. };
  132. var spy = spyOn(funcs, 'start');
  133. var m = new Model();
  134. m.watch('myid', [], funcs.start);
  135. expect(spy).toHaveBeenCalled();
  136. expect(m.has('myid')).toBe(true);
  137. });
  138. });
  139. describe('when all deps already satisfied', function() {
  140. it('resolves immediately', function() {
  141. var funcs = {
  142. start: function() { }
  143. };
  144. var spy = spyOn(funcs, 'start');
  145. var m = new Model();
  146. m.set({
  147. myvar: 5,
  148. myothervar: 6
  149. });
  150. m.watch('myid', [ 'myvar', 'myothervar' ], funcs.start);
  151. expect(spy).toHaveBeenCalled();
  152. expect(m.has('myid')).toBe(true);
  153. });
  154. });
  155. describe('when not all deps satisfied', function() {
  156. it('resolves only after all deps are set', function() {
  157. var funcs = {
  158. start: function() { }
  159. };
  160. var spy = spyOn(funcs, 'start');
  161. var m = new Model();
  162. m.set('myvar', 5);
  163. m.watch('myid', [ 'myvar', 'myothervar' ], funcs.start);
  164. expect(spy).not.toHaveBeenCalled();
  165. expect(m.has('myid')).toBe(false);
  166. m.set('myothervar', 6);
  167. expect(spy).toHaveBeenCalled();
  168. expect(m.has('myid')).toBe(true);
  169. });
  170. });
  171. describe('when previously resolved dep is unset', function() {
  172. it('calls the stop function', function() {
  173. var funcs = {
  174. start: function() { },
  175. stop: function() { }
  176. };
  177. var startSpy = spyOn(funcs, 'start');
  178. var stopSpy = spyOn(funcs, 'stop');
  179. var m = new Model();
  180. m.set('myvar', 5);
  181. m.watch('myid', [ 'myvar', 'myothervar' ], funcs.start, funcs.stop);
  182. m.set('myothervar', 6);
  183. expect(startSpy).toHaveBeenCalled();
  184. expect(stopSpy).not.toHaveBeenCalled();
  185. expect(m.has('myid')).toBe(true);
  186. m.unset('myothervar');
  187. expect(stopSpy).toHaveBeenCalled();
  188. expect(m.has('myid')).toBe(false);
  189. });
  190. });
  191. describe('when resetting a dependency', function() {
  192. it('calls all shutdown funcs before all startup funcs', function() {
  193. var m = new Model();
  194. var ops = [];
  195. m.set('var1', 5);
  196. m.watch('doingSomething1', [ 'var1' ], function() {
  197. ops.push('start1');
  198. }, function() {
  199. ops.push('stop1');
  200. });
  201. m.watch('doingSomething2', [ 'var1' ], function() {
  202. ops.push('start2');
  203. }, function() {
  204. ops.push('stop2');
  205. });
  206. expect(ops).toEqual([
  207. 'start1', 'start2'
  208. ]);
  209. m.set('var1', 6);
  210. expect(ops).toEqual([
  211. 'start1', 'start2',
  212. 'stop1', 'stop2',
  213. 'start1', 'start2'
  214. ]);
  215. });
  216. });
  217. describe('with an optional value', function() {
  218. it('resolves immediately', function() {
  219. var funcs = {
  220. start: function() { },
  221. stop: function() { }
  222. };
  223. var startSpy = spyOn(funcs, 'start');
  224. var stopSpy = spyOn(funcs, 'stop');
  225. var m = new Model();
  226. m.watch('myid', [ '?optvar' ], funcs.start, funcs.stop);
  227. expect(startSpy).toHaveBeenCalled();
  228. expect(stopSpy).not.toHaveBeenCalled();
  229. });
  230. it('calls stop/start when value changed', function() {
  231. var funcs = {
  232. start: function() { },
  233. stop: function() { }
  234. };
  235. var startSpy = spyOn(funcs, 'start');
  236. var stopSpy = spyOn(funcs, 'stop');
  237. var m = new Model();
  238. m.set('optvar', 5);
  239. m.watch('myid', [ '?optvar' ], funcs.start, funcs.stop);
  240. expect(stopSpy).not.toHaveBeenCalled();
  241. expect(startSpy).toHaveBeenCalledTimes(1);
  242. m.set('optvar', 6);
  243. expect(stopSpy).toHaveBeenCalledTimes(1);
  244. expect(startSpy).toHaveBeenCalledTimes(2);
  245. });
  246. it('calls stop/start when value unset', function() {
  247. var funcs = {
  248. start: function() { },
  249. stop: function() { }
  250. };
  251. var startSpy = spyOn(funcs, 'start');
  252. var stopSpy = spyOn(funcs, 'stop');
  253. var m = new Model();
  254. m.set('optvar', 5);
  255. m.watch('myid', [ '?optvar' ], funcs.start, funcs.stop);
  256. expect(stopSpy).not.toHaveBeenCalled();
  257. expect(startSpy).toHaveBeenCalledTimes(1);
  258. m.unset('optvar');
  259. expect(stopSpy).toHaveBeenCalledTimes(1);
  260. expect(startSpy).toHaveBeenCalledTimes(2);
  261. });
  262. });
  263. describe('when multiple deps changed atomically', function() {
  264. it('fires stop/start only once per change', function() {
  265. var funcs = {
  266. start: function() { },
  267. stop: function() { }
  268. };
  269. var startSpy = spyOn(funcs, 'start');
  270. var stopSpy = spyOn(funcs, 'stop');
  271. var m = new Model();
  272. m.set({
  273. myvar1: 5,
  274. myvar2: 6
  275. });
  276. m.watch('taskid', [ 'myvar1', 'myvar2' ], funcs.start, funcs.stop);
  277. m.set({
  278. myvar1: 7,
  279. myvar2: 8
  280. });
  281. expect(stopSpy).toHaveBeenCalledTimes(1);
  282. expect(startSpy).toHaveBeenCalledTimes(2);
  283. });
  284. });
  285. });
  286. describe('when called as a computed value', function() {
  287. describe('when it has no deps', function() {
  288. it('resolves immediately', function() {
  289. var funcs = {
  290. generator: function() {
  291. return 9;
  292. },
  293. change: function(val) {
  294. expect(val).toBe(9);
  295. }
  296. };
  297. var generatorSpy = spyOn(funcs, 'generator').and.callThrough();
  298. var changeSpy = spyOn(funcs, 'change').and.callThrough();
  299. var m = new Model();
  300. m.on('change:myid', funcs.change);
  301. m.watch('myid', [], funcs.generator);
  302. expect(generatorSpy).toHaveBeenCalled();
  303. expect(changeSpy).toHaveBeenCalled();
  304. expect(m.has('myid')).toBe(true);
  305. expect(m.get('myid')).toBe(9);
  306. });
  307. });
  308. describe('when all deps already satisfied', function() {
  309. it('resolves immediately', function() {
  310. var funcs = {
  311. generator: function(deps) {
  312. return deps.myvar + deps.myothervar;
  313. }
  314. };
  315. var spy = spyOn(funcs, 'generator').and.callThrough();
  316. var m = new Model();
  317. m.set({
  318. myvar: 5,
  319. myothervar: 6
  320. });
  321. m.watch('myid', [ 'myvar', 'myothervar' ], funcs.generator);
  322. expect(spy).toHaveBeenCalled();
  323. expect(m.has('myid')).toBe(true);
  324. expect(m.get('myid')).toBe(11);
  325. });
  326. });
  327. describe('when not all deps satisfied', function() {
  328. it('resolves only after all deps are set', function() {
  329. var funcs = {
  330. generator: function(deps) {
  331. return deps.myvar + deps.myothervar;
  332. }
  333. };
  334. var spy = spyOn(funcs, 'generator').and.callThrough();
  335. var m = new Model();
  336. m.set('myvar', 5);
  337. m.watch('myid', [ 'myvar', 'myothervar' ], funcs.generator);
  338. expect(spy).not.toHaveBeenCalled();
  339. expect(m.has('myid')).toBe(false);
  340. m.set('myothervar', 6);
  341. expect(spy).toHaveBeenCalled();
  342. expect(m.has('myid')).toBe(true);
  343. expect(m.get('myid')).toBe(11);
  344. });
  345. describe('when watching an instance', function() {
  346. it('resolves only after final async dep resolves', function(done) {
  347. var funcs = {
  348. generator: function(deps) {
  349. return deps.myvar + deps.myothervar;
  350. }
  351. };
  352. var spy = spyOn(funcs, 'generator').and.callThrough();
  353. var m = new Model();
  354. m.set('myvar', 5);
  355. m.watch('myothervar', [ 'myvar' ], function(deps) {
  356. var deferred = $.Deferred();
  357. setTimeout(function() {
  358. deferred.resolve(deps.myvar * 2);
  359. }, 100);
  360. return deferred.promise();
  361. });
  362. m.watch('myid', [ 'myvar', 'myothervar' ], funcs.generator);
  363. expect(spy).not.toHaveBeenCalled();
  364. expect(m.has('myid')).toBe(false);
  365. setTimeout(function() {
  366. expect(spy).toHaveBeenCalled();
  367. expect(m.has('myid')).toBe(true);
  368. expect(m.get('myid')).toBe(15);
  369. done();
  370. }, 200);
  371. });
  372. });
  373. describe('when using class-methods', function() {
  374. it('resolves only after final async dep resolves', function(done) {
  375. var funcs = {
  376. generator: function(deps) {
  377. return deps.myvar + deps.myothervar;
  378. }
  379. };
  380. var spy = spyOn(funcs, 'generator').and.callThrough();
  381. var MyClass = Model.extend();
  382. MyClass.watch('myothervar', [ 'myvar' ], function(deps) {
  383. var deferred = $.Deferred();
  384. setTimeout(function() {
  385. deferred.resolve(deps.myvar * 2);
  386. }, 100);
  387. return deferred.promise();
  388. });
  389. MyClass.watch('myid', [ 'myvar', 'myothervar' ], funcs.generator);
  390. var m = new MyClass();
  391. m.set({
  392. myvar: 5
  393. });
  394. expect(spy).not.toHaveBeenCalled();
  395. expect(m.has('myid')).toBe(false);
  396. setTimeout(function() {
  397. expect(spy).toHaveBeenCalled();
  398. expect(m.has('myid')).toBe(true);
  399. expect(m.get('myid')).toBe(15);
  400. done();
  401. }, 200);
  402. });
  403. });
  404. });
  405. });
  406. });
  407. describe('unwatch', function() {
  408. it('calls the stop function and won\'t call the start function again', function() {
  409. var funcs = {
  410. start: function() { },
  411. stop: function() { }
  412. };
  413. var startSpy = spyOn(funcs, 'start');
  414. var stopSpy = spyOn(funcs, 'stop');
  415. var m = new Model();
  416. m.set('myvar', 5);
  417. m.watch('myid', [ 'myvar', 'myothervar' ], funcs.start, funcs.stop);
  418. expect(startSpy).not.toHaveBeenCalled();
  419. m.set('myothervar', 6);
  420. expect(startSpy).toHaveBeenCalledTimes(1);
  421. m.unwatch('myid');
  422. expect(stopSpy).toHaveBeenCalledTimes(1);
  423. // doesn't call it again
  424. m.set('myvar', 5);
  425. expect(startSpy).toHaveBeenCalledTimes(1);
  426. });
  427. });
  428. describe('flash', function() {
  429. describe('if already satisfied', function() {
  430. it('calls stop+start', function() {
  431. var funcs = {
  432. start: function(deps) {
  433. expect(deps.dep1).toBe(6);
  434. },
  435. stop: function() { }
  436. };
  437. var startSpy = spyOn(funcs, 'start').and.callThrough();
  438. var stopSpy = spyOn(funcs, 'stop');
  439. var m = new Model();
  440. m.set({ dep1: 6 });
  441. m.watch('task1', [ 'dep1' ], startSpy, stopSpy);
  442. expect(stopSpy).toHaveBeenCalledTimes(0);
  443. expect(startSpy).toHaveBeenCalledTimes(1);
  444. m.flash('task1');
  445. expect(stopSpy).toHaveBeenCalledTimes(1);
  446. expect(startSpy).toHaveBeenCalledTimes(2);
  447. });
  448. });
  449. describe('if not satisfied', function() {
  450. it('does not call stop+start', function() {
  451. var funcs = {
  452. start: function() { },
  453. stop: function() { }
  454. };
  455. var startSpy = spyOn(funcs, 'start');
  456. var stopSpy = spyOn(funcs, 'stop');
  457. var m = new Model();
  458. m.watch('task1', [ 'dep1' ], startSpy, stopSpy);
  459. expect(stopSpy).toHaveBeenCalledTimes(0);
  460. expect(startSpy).toHaveBeenCalledTimes(0);
  461. m.flash('task1');
  462. expect(stopSpy).toHaveBeenCalledTimes(0);
  463. expect(startSpy).toHaveBeenCalledTimes(0);
  464. });
  465. });
  466. });
  467. });