]> git.proxmox.com Git - extjs.git/blame - extjs/packages/core/test/specs/lang/Function.js
add extjs 6.0.1 sources
[extjs.git] / extjs / packages / core / test / specs / lang / Function.js
CommitLineData
6527f429
DM
1describe("Ext.Function", function() {\r
2 \r
3 var _setTimeout,\r
4 _clearTimeout,\r
5 timeouts,\r
6 timeoutIds,\r
7 clearedTimeoutIds,\r
8 runAfterInvocation = function(spyedFunction, callback, invocationCount) {\r
9 invocationCount = invocationCount || 1;\r
10 waitsFor(function() { return spyedFunction.calls.length >= invocationCount; });\r
11 runs(callback);\r
12 },\r
13 mockTimeout = function() {\r
14 timeouts = [];\r
15 timeoutIds = [];\r
16 clearedTimeoutIds = [];\r
17 \r
18 _setTimeout = window.setTimeout;\r
19 window.setTimeout = function(fn, timeout) {\r
20 timeouts.push(timeout);\r
21 var timeoutId = _setTimeout.apply(this, arguments);\r
22 timeoutIds.push(timeoutId);\r
23 return timeoutId;\r
24 };\r
25 \r
26 _clearTimeout = window.clearTimeout;\r
27 window.clearTimeout = function(timeoutId) {\r
28 clearedTimeoutIds.push(timeoutId);\r
29 _clearTimeout.apply(this, arguments);\r
30 };\r
31 },\r
32 unmockTimeout = function() {\r
33 timeouts = undefined;\r
34 timeoutIds = undefined;\r
35 clearedTimeoutIds = undefined;\r
36 window.setTimeout = _setTimeout;\r
37 window.clearTimeout = _clearTimeout;\r
38 };\r
39\r
40 \r
41 describe("bind", function() {\r
42 var fn,\r
43 bind;\r
44\r
45 beforeEach(function() {\r
46 fn = jasmine.createSpy("bindSpy");\r
47 });\r
48\r
49 it("should return a function if a function is passed as first argument", function() {\r
50 bind = Ext.Function.bind(fn, this);\r
51\r
52 expect(typeof bind === "function").toBe(true);\r
53 });\r
54\r
55 it("should use the correct scope", function() {\r
56 bind = Ext.Function.bind(fn, fakeScope);\r
57\r
58 bind();\r
59\r
60 expect(fn.calls[0].object).toBe(fakeScope);\r
61 });\r
62\r
63 it("should call the first function when it is executed", function() {\r
64 bind = Ext.Function.bind(fn, this);\r
65\r
66 bind();\r
67\r
68 expect(fn).toHaveBeenCalled();\r
69 });\r
70\r
71 describe("argument passing", function() {\r
72\r
73 it("should use default args if none are passed", function() {\r
74 bind = Ext.Function.bind(fn, this, ['a', 'b']);\r
75\r
76 bind();\r
77\r
78 expect(fn).toHaveBeenCalledWith('a', 'b');\r
79 });\r
80\r
81 it("should use passed args if they are present", function() {\r
82 bind = Ext.Function.bind(fn, this);\r
83\r
84 bind('c', 'd');\r
85\r
86 expect(fn).toHaveBeenCalledWith('c', 'd');\r
87 });\r
88\r
89 it("should append args", function() {\r
90 bind = Ext.Function.bind(fn, this, ['a', 'b'], true);\r
91\r
92 bind('c', 'd');\r
93\r
94 expect(fn).toHaveBeenCalledWith('c', 'd', 'a', 'b');\r
95 });\r
96\r
97 it("should append args at the given index", function() {\r
98 bind = Ext.Function.bind(fn, this, ['a', 'b'], 0);\r
99\r
100 bind('c', 'd');\r
101\r
102 expect(fn).toHaveBeenCalledWith('a', 'b', 'c', 'd');\r
103 });\r
104 });\r
105 });\r
106 \r
107 describe("pass", function() {\r
108 it("should pass the specified array of arguments as the first arguments to the given function", function() {\r
109 var fn = jasmine.createSpy(),\r
110 args = [0, 1, 2],\r
111 callback = Ext.Function.pass(fn, args);\r
112 callback(3, 4, 5);\r
113 expect(fn).toHaveBeenCalledWith(0, 1, 2, 3, 4, 5);\r
114 });\r
115 it("should pass the specified string argument as the first argument to the given function", function() {\r
116 var fn = jasmine.createSpy(),\r
117 args = 'a',\r
118 callback = Ext.Function.pass(fn, args);\r
119 callback('b', 'c');\r
120 expect(fn).toHaveBeenCalledWith('a', 'b', 'c');\r
121 });\r
122 it("should pass the specified numeric argument as the first argument to the given function", function() {\r
123 var fn = jasmine.createSpy(),\r
124 args = 0,\r
125 callback = Ext.Function.pass(fn, args);\r
126 callback(1);\r
127 expect(fn).toHaveBeenCalledWith(0, 1);\r
128 });\r
129 it("should pass the specified 'arguments' argument as the first argument to the given funciton", function() {\r
130 var testFunction = function () {\r
131 var fn = jasmine.createSpy(),\r
132 args = arguments,\r
133 callback = Ext.Function.pass(fn, args);\r
134 callback(3, 4, 5);\r
135 expect(fn).toHaveBeenCalledWith(0, 1, 2, 3, 4, 5);\r
136 };\r
137 testFunction(0, 1, 2);\r
138 });\r
139 it("should discard the argument if it's undefined", function() {\r
140 var fn = jasmine.createSpy(),\r
141 args = undefined,\r
142 callback = Ext.Function.pass(fn, args);\r
143 callback(1);\r
144 expect(fn).toHaveBeenCalledWith(1);\r
145 });\r
146 it("should use 'this' as default scope", function() {\r
147 var foo = 'a',\r
148 fn = jasmine.createSpy().andCallFake(function() {\r
149 foo = this.foo;\r
150 }),\r
151 callback = Ext.Function.pass(fn, 'c');\r
152 callback('d');\r
153 expect(fn).toHaveBeenCalledWith('c', 'd');\r
154 expect(foo).toBeUndefined();\r
155 });\r
156 it("should override 'this' with the specified scope", function() {\r
157 var foo = 'a',\r
158 scope = { foo: 'b' },\r
159 fn = jasmine.createSpy().andCallFake(function() {\r
160 foo = this.foo;\r
161 }),\r
162 callback = Ext.Function.pass(fn, 'c', scope);\r
163 callback('d');\r
164 expect(fn).toHaveBeenCalledWith('c', 'd');\r
165 expect(foo).toBe('b');\r
166 });\r
167 });\r
168 \r
169 describe("clone", function() {\r
170 it("should clone the given function", function() {\r
171 var fn = jasmine.createSpy().andCallFake(function(arg) { return 'bar'; }),\r
172 clonedFn = Ext.Function.clone(fn),\r
173 result = clonedFn('foo');\r
174 expect(result).toBe('bar');\r
175 expect(fn).toHaveBeenCalledWith('foo');\r
176 });\r
177 });\r
178\r
179 describe("createInterceptor", function() {\r
180 var interceptor,\r
181 interceptorFn,\r
182 interceptedFn,\r
183 interceptorIsRunFirst,\r
184 interceptedIsRunAfter;\r
185\r
186 beforeEach(function() {\r
187 interceptorIsRunFirst = false;\r
188 interceptedIsRunAfter = false;\r
189\r
190 interceptorFn = jasmine.createSpy("interceptorSpy").andCallFake(function() {\r
191 interceptorIsRunFirst = true;\r
192 });\r
193 interceptedFn = jasmine.createSpy("interceptedSpy").andCallFake(function() {\r
194 interceptedIsRunAfter = interceptorIsRunFirst;\r
195 });\r
196 });\r
197\r
198 describe("if no function is passed", function() {\r
199 it("should return the same function", function() {\r
200 expect(Ext.Function.createInterceptor(interceptedFn)).toEqual(interceptedFn);\r
201 });\r
202 });\r
203\r
204 describe("if a function is passed", function() {\r
205 beforeEach(function() {\r
206 interceptor = Ext.Function.createInterceptor(interceptedFn, interceptorFn, fakeScope);\r
207 interceptor();\r
208 });\r
209\r
210 it("should return a new function", function() {\r
211 expect(typeof interceptor === "function").toBe(true);\r
212 expect(interceptor).not.toEqual(interceptedFn);\r
213 });\r
214\r
215 it("should set the correct scope for the interceptor function", function() {\r
216 expect(interceptorFn.calls[0].object).toBe(fakeScope);\r
217 });\r
218\r
219 it("should call the interceptor function first", function() {\r
220 expect(interceptedIsRunAfter).toBe(true);\r
221 });\r
222\r
223 });\r
224\r
225 describe("if the interceptor function returns false", function() {\r
226 it("should not execute the original function", function() {\r
227 interceptor = Ext.Function.createInterceptor(interceptedFn, function() {\r
228 return false;\r
229 });\r
230\r
231 interceptor();\r
232 expect(interceptedFn).not.toHaveBeenCalled();\r
233 });\r
234 });\r
235 \r
236 describe("returnValue", function(){\r
237 beforeEach(function(){\r
238 interceptedFn = function(){\r
239 return 'Original';\r
240 };\r
241 \r
242 interceptorFn = function(){\r
243 return false;\r
244 };\r
245 });\r
246 \r
247 describe("when interceptorFn returns false", function() {\r
248 it("should return null as a default", function(){\r
249 interceptor = Ext.Function.createInterceptor(interceptedFn, interceptorFn);\r
250 expect(interceptor()).toBeNull();\r
251 });\r
252 \r
253 it("should accept a custom returnValue", function(){\r
254 interceptor = Ext.Function.createInterceptor(interceptedFn, interceptorFn, null, 'Custom');\r
255 expect(interceptor()).toBe('Custom');\r
256 });\r
257 \r
258 it("should accept a falsy returnValue", function(){\r
259 interceptor = Ext.Function.createInterceptor(interceptedFn, interceptorFn, null, false);\r
260 expect(interceptor()).toBe(false);\r
261 });\r
262 });\r
263 \r
264 it("should return the value of the original function if false is not returned", function(){\r
265 interceptorFn = function(){\r
266 return;\r
267 };\r
268 interceptor = Ext.Function.createInterceptor(interceptedFn, interceptorFn);\r
269 expect(interceptor()).toBe('Original');\r
270 })\r
271 });\r
272 });\r
273 \r
274 describe("createDelayed", function() {\r
275 (Ext.isIE8 ? xit : it)("should create bind to the given function to be called after x milliseconds", function() {\r
276 mockTimeout();\r
277 var fn = jasmine.createSpy(),\r
278 delayedFn = Ext.Function.createDelayed(fn, 2);\r
279 \r
280 delayedFn('foo');\r
281 expect(timeouts.shift()).toBe(2);\r
282 \r
283 expect(fn).not.toHaveBeenCalled();\r
284 \r
285 runAfterInvocation(fn, function() {\r
286 expect(fn).toHaveBeenCalledWith('foo');\r
287 });\r
288 unmockTimeout();\r
289 });\r
290 it("should use the specified scope as 'this'", function() {\r
291 var scope = { x: 'foo' },\r
292 fn = jasmine.createSpy().andCallFake(function() { this.x = 'bar' }),\r
293 delayedFn = Ext.Function.createDelayed(fn, 2, scope);\r
294 delayedFn();\r
295 expect(fn).not.toHaveBeenCalled();\r
296 expect(scope.x).toBe('foo');\r
297 \r
298 runAfterInvocation(fn, function() {\r
299 expect(scope.x).toBe('bar');\r
300 });\r
301 });\r
302 it("should override the call arguments with the specified arguments", function() {\r
303 var scope = {},\r
304 args = [0, 1, 2],\r
305 fn = jasmine.createSpy(),\r
306 delayedFn = Ext.Function.createDelayed(fn, 2, scope, args);\r
307 delayedFn(3, 4, 5);\r
308 expect(fn).not.toHaveBeenCalled();\r
309 runAfterInvocation(fn, function() {\r
310 expect(fn).toHaveBeenCalledWith(0, 1, 2); \r
311 });\r
312 });\r
313 it("should append the specified arguments to the call arguments when appendArgs is true", function() {\r
314 var scope = {},\r
315 args = [0, 1, 2],\r
316 fn = jasmine.createSpy(),\r
317 delayedFn = Ext.Function.createDelayed(fn, 2, scope, args, true);\r
318 delayedFn(3, 4, 5);\r
319 expect(fn).not.toHaveBeenCalled();\r
320 runAfterInvocation(fn, function() {\r
321 expect(fn).toHaveBeenCalledWith(3, 4, 5, 0, 1, 2); \r
322 });\r
323 });\r
324 it("should insert the specified arguments into the call arguments at the position specified by appendArgs", function() {\r
325 var scope = {},\r
326 args = [0, 1, 2],\r
327 fn = jasmine.createSpy(),\r
328 delayedFn = Ext.Function.createDelayed(fn, 2, scope, args, 2);\r
329 delayedFn(3, 4, 5);\r
330 expect(fn).not.toHaveBeenCalled();\r
331 runAfterInvocation(fn, function() {\r
332 expect(fn).toHaveBeenCalledWith(3, 4, 0, 1, 2, 5); \r
333 });\r
334 });\r
335 });\r
336\r
337 describe("defer", function() {\r
338 var fn;\r
339\r
340 beforeEach(function(){\r
341 fn = jasmine.createSpy("deferSpy");\r
342 });\r
343\r
344 it("should execute the function after the specified number of milliseconds", function() {\r
345 Ext.defer(fn, 10);\r
346\r
347 waitsFor(function(){\r
348 return fn.calls.length === 1;\r
349 }, "fn was never called");\r
350\r
351 runs(function() {\r
352 expect(fn).toHaveBeenCalled();\r
353 });\r
354 });\r
355\r
356 it("should execute the function directly if the specified number of milliseconds is <= 0", function() {\r
357 Ext.defer(fn, 0);\r
358\r
359 expect(fn).toHaveBeenCalled();\r
360 });\r
361\r
362 it("should set the correct scope", function() {\r
363 Ext.defer(fn, 10, fakeScope);\r
364\r
365 waitsFor(function(){\r
366 return fn.calls.length === 1;\r
367 }, "fn was never called");\r
368\r
369 runs(function() {\r
370 expect(fn.calls[0].object).toBe(fakeScope);\r
371 });\r
372 });\r
373\r
374 it("should pass the correct arguments", function() {\r
375 Ext.defer(fn, 10, this, [1, 2, 3]);\r
376\r
377 waitsFor(function(){\r
378 return fn.calls.length === 1;\r
379 }, "fn was never called");\r
380\r
381 runs(function() {\r
382 expect(fn).toHaveBeenCalledWith(1,2,3);\r
383 });\r
384 });\r
385\r
386 it("should return a timeout number", function() {\r
387 expect(typeof Ext.defer(function() {}, 10) === 'number').toBe(true);\r
388 });\r
389 });\r
390\r
391 describe("createSequence", function() {\r
392 var sequence,\r
393 newFn,\r
394 origFn,\r
395 origFnIsRunFirst,\r
396 newFnIsRunAfter;\r
397\r
398 beforeEach(function() {\r
399 origFnIsRunFirst = false;\r
400 newFnIsRunAfter = false;\r
401\r
402 origFn = jasmine.createSpy("interceptedSpy").andCallFake(function() {\r
403 origFnIsRunFirst = true;\r
404 });\r
405\r
406 newFn = jasmine.createSpy("sequenceSpy").andCallFake(function() {\r
407 newFnIsRunAfter = origFnIsRunFirst;\r
408 });\r
409 });\r
410\r
411 describe("if no function is passed", function() {\r
412 it("should return the same function", function() {\r
413 expect(Ext.Function.createSequence(origFn)).toEqual(origFn);\r
414 });\r
415 });\r
416\r
417 describe("if a function is passed", function() {\r
418 beforeEach(function() {\r
419 sequence = Ext.Function.createSequence(origFn, newFn, fakeScope);\r
420 sequence();\r
421 });\r
422\r
423 it("should return a new function", function() {\r
424 expect(typeof sequence === "function").toBe(true);\r
425 expect(sequence).not.toEqual(origFn);\r
426 });\r
427\r
428 it("should set the correct scope for the sequence function", function() {\r
429 expect(newFn.calls[0].object).toBe(fakeScope);\r
430 });\r
431\r
432 it("should call the sequence function first", function() {\r
433 expect(newFnIsRunAfter).toBe(true);\r
434 });\r
435\r
436 });\r
437 });\r
438 \r
439 describe("createBuffered", function() {\r
440 (Ext.isIE8 ? xit : it)("should prevent the execution of multiple calls of the buffered function within the timeout period", function() {\r
441 mockTimeout();\r
442 var fn = jasmine.createSpy(),\r
443 bufferedFn = Ext.Function.createBuffered(fn, 2);\r
444 \r
445 bufferedFn();\r
446 expect(timeouts.shift()).toBe(2);\r
447 \r
448 bufferedFn();\r
449 expect(clearedTimeoutIds.shift()).toBe(timeoutIds.shift());\r
450 expect(timeouts.shift()).toBe(2);\r
451 \r
452 expect(fn).not.toHaveBeenCalled();\r
453 runAfterInvocation(fn, function() {\r
454 expect(fn.calls.length).toBe(1);\r
455 });\r
456 \r
457 unmockTimeout();\r
458 });\r
459 it("should use the specified scope as 'this'", function() {\r
460 var scope = { x: 1 },\r
461 fn = jasmine.createSpy().andCallFake(function() { this.x++; }),\r
462 bufferedFn = Ext.Function.createBuffered(fn, 20, scope);\r
463 bufferedFn();\r
464 expect(scope.x).toBe(1);\r
465 bufferedFn();\r
466 runAfterInvocation(fn, function() {\r
467 expect(scope.x).toBe(2);\r
468 });\r
469 });\r
470 it("should override the call arguments with the specified ones", function() {\r
471 var scope = {},\r
472 args = ['bar1', 'bar2'],\r
473 fn = jasmine.createSpy(),\r
474 bufferedFn = Ext.Function.createBuffered(fn, 20, scope, args);\r
475 bufferedFn('foo1', 'foo2');\r
476 expect(fn).not.toHaveBeenCalled();\r
477 runAfterInvocation(fn, function() {\r
478 expect(fn).toHaveBeenCalledWith('bar1', 'bar2');\r
479 });\r
480 });\r
481 });\r
482 \r
483 (Ext.isIE8 ? xdescribe : xdescribe)("createThrottled", function() {\r
484 it("should execute only once per each specified time interval", function() {\r
485 mockTimeout();\r
486 var fn = jasmine.createSpy(),\r
487 throttledFn = Ext.Function.createThrottled(fn, 10);\r
488 \r
489 expect(fn).not.toHaveBeenCalled();\r
490 throttledFn();\r
491 expect(clearedTimeoutIds.shift()).toBeUndefined();\r
492 expect(fn.calls.length).toBe(1);\r
493 \r
494 throttledFn();\r
495 expect(timeouts.shift()).not.toBeGreaterThan(10);\r
496 expect(clearedTimeoutIds.shift()).toBeUndefined();\r
497 throttledFn();\r
498 expect(timeouts.shift()).not.toBeGreaterThan(10);\r
499 expect(clearedTimeoutIds.shift()).toBe(timeoutIds.shift());\r
500 throttledFn();\r
501 expect(timeouts.shift()).not.toBeGreaterThan(10);\r
502 expect(clearedTimeoutIds.shift()).toBe(timeoutIds.shift());\r
503 \r
504 expect(fn.calls.length).toBe(1);\r
505 runAfterInvocation(fn, function() {\r
506 expect(fn.calls.length).toEqual(2);\r
507 throttledFn(); // elapsed may have been exceeded here, so this call may execute immediately\r
508 expect(fn.calls.length).not.toBeLessThan(2);\r
509 expect(fn.calls.length).not.toBeGreaterThan(3);\r
510 }, 2);\r
511 unmockTimeout();\r
512 });\r
513 \r
514 it("should use the specified scope as 'this'", function() {\r
515 var scope = {},\r
516 fn = jasmine.createSpy().andCallFake(function(value) { this.x = value; }),\r
517 throttledFn = Ext.Function.createThrottled(fn, 10, scope);\r
518 \r
519 throttledFn('foo');\r
520 throttledFn('bar');\r
521 throttledFn('baz');\r
522 throttledFn('qux');\r
523 \r
524 expect(fn).toHaveBeenCalledWith('foo');\r
525 expect(scope.x).toBe('foo');\r
526 expect(fn.calls.length).toBe(1);\r
527 });\r
528 });\r
529 \r
530 describe("interceptAfter", function() {\r
531 it("should execute interceptor after each method call", function() {\r
532 var monologue = {\r
533 phrases: [],\r
534 addPhrase: function(phrase) {\r
535 this.phrases.push(phrase)\r
536 }\r
537 },\r
538 addMeToo = jasmine.createSpy().andCallFake(function(phrase) {\r
539 this.phrases.push(phrase + ' too');\r
540 });\r
541 \r
542 Ext.Function.interceptAfter(monologue, 'addPhrase', addMeToo);\r
543 monologue.addPhrase('I like you');\r
544 monologue.addPhrase('I love you');\r
545 expect(monologue.phrases).toEqual(['I like you', 'I like you too', 'I love you', 'I love you too']);\r
546 expect(addMeToo).toHaveBeenCalledWith('I like you');\r
547 expect(addMeToo).toHaveBeenCalledWith('I love you');\r
548 });\r
549 \r
550 it("should execute interceptor after each method call with the specified scope as 'this'", function() {\r
551 var monologue = {\r
552 phrases: [],\r
553 addPhrase: function(phrase) {\r
554 this.phrases.push(phrase)\r
555 }\r
556 },\r
557 transcription = {\r
558 phrases: []\r
559 },\r
560 transcriptPhrase = jasmine.createSpy().andCallFake(function(phrase) {\r
561 this.phrases.push("He said: " + phrase);\r
562 });\r
563 \r
564 Ext.Function.interceptAfter(monologue, 'addPhrase', transcriptPhrase, transcription);\r
565 monologue.addPhrase('I like you');\r
566 monologue.addPhrase('I love you');\r
567 expect(monologue.phrases).toEqual(['I like you', 'I love you']);\r
568 expect(transcription.phrases).toEqual(['He said: I like you', 'He said: I love you']);\r
569 expect(transcriptPhrase).toHaveBeenCalledWith('I like you');\r
570 expect(transcriptPhrase).toHaveBeenCalledWith('I love you');\r
571 });\r
572 });\r
573 \r
574 describe('asap', function() {\r
575 it('should call the passed function', function() {\r
576 var called = false;\r
577\r
578 Ext.asap(function(){\r
579 called = true;\r
580 });\r
581\r
582 // Wait for it to have called the function; it's supposed to be called immediately upon exit from the\r
583 // calling event handler.\r
584 waitsFor(function() {\r
585 return called;\r
586 }, 'the asap function to call the passed function');\r
587 });\r
588 it('should not call the passed function if asapCancel called', function() {\r
589 var called = false,\r
590 timer;\r
591\r
592 timer = Ext.asap(function(){\r
593 called = true;\r
594 });\r
595 Ext.asapCancel(timer);\r
596\r
597 // We expect nothing to happen, so there's nothing to wait for.\r
598 // Wait for the most pessmistic time to allow aany erroneous call to occur.\r
599 waits(150);\r
600\r
601 runs(function() {\r
602 expect(called).toBe(false);\r
603 });\r
604 });\r
605 });\r
606});\r