Merge pull request #2789 from SergioCrisostomo/upgrade-karma-sauce-launcher
[mootools.git] / Specs / Types / Function.js
blob4a7a1435c604eb8dbef5b53b5ea73de618f5ce7a
1 /*
2 ---
3 name: Function
4 requires: ~
5 provides: ~
6 ...
7 */
9 var dit = /*<1.2compat>*/xit || /*</1.2compat>*/it; // Don't run unless no compat.
11 (function(){
13 var MooTools = new String('MooTools');
15 var fn = function(){
16         return Array.convert(arguments).slice();
19 var Rules = function(){
20         return this + ' rules';
23 var Args = function(){
24         return [this].concat(Array.prototype.slice.call(arguments));
27 describe('Function Method', function(){
29 //<1.2compat>
30         describe('Function.create', function(){
32                 it('should return a new function', function(){
33                         var fnc = $empty.create();
34                         expect($empty).to.not.equal(fnc);
35                 });
37                 it('should return a new function with specified argument', function(){
38                         var fnc = fn.create({'arguments': 'rocks'});
39                         expect(fnc()).to.eql(['rocks']);
40                 });
42                 it('should return a new function with multiple arguments', function(){
43                         var fnc = fn.create({'arguments': ['MooTools', 'rocks']});
44                         expect(fnc()).to.eql(['MooTools', 'rocks']);
45                 });
47                 it('should return a new function bound to an object', function(){
48                         var fnc = Rules.create({'bind': 'MooTools'});
49                         expect(fnc()).to.equal('MooTools rules');
50                 });
52                 it('should return a new function as an event', function(){
53                         var fnc = fn.create({'arguments': [0, 1], 'event': true});
54                         expect(fnc('an Event occurred')).to.eql(['an Event occurred', 0, 1]);
55                 });
56         });
57 //</1.2compat>
59         describe('Function.bind', function(){
61                 it('should return the function bound to an object', function(){
62                         var fnc = Rules.bind('MooTools');
63                         expect(fnc()).to.equal('MooTools rules');
64                 });
66                 it('should return the function bound to an object with specified argument', function(){
67                         var results = Args.bind(MooTools, 'rocks')();
68                         expect(results[0]).to.equal(MooTools);
69                         expect(results[1]).to.equal('rocks');
70                 });
72                 dit('should return the function bound to an object with multiple arguments', function(){
73                         var results = Args.bind(MooTools, ['rocks', 'da house'])();
74                         expect(results[0]).to.equal(MooTools);
75                         expect(results[1]).to.eql(['rocks', 'da house']);
76                 });
78 //<1.2compat>
79                 it('should return the function bound to an object with specified argument', function(){
80                         var fnc = Args.bind(MooTools, 'rocks');
81                         var result = fnc();
82                         expect(result[0]).to.equal(MooTools);
83                         expect(result).to.eql([MooTools, 'rocks']);
84                 });
86                 it('should return the function bound to an object with multiple arguments', function(){
87                         var fnc = Args.bind(MooTools, ['rocks', 'da house']);
88                         var result = fnc();
89                         expect(result[0]).to.equal(MooTools);
90                         expect(result).to.eql([MooTools, 'rocks', 'da house']);
91                 });
93                 it('should return the function bound to an object and make the function an event listener', function(){
94                         var fnc = Args.bindWithEvent(MooTools);
95                         var result = fnc('an Event occurred');
96                         expect(result[0]).to.equal(MooTools);
97                         expect(result).to.eql([MooTools, 'an Event occurred']);
98                 });
100                 it('should return the function bound to an object and make the function event listener with multiple arguments', function(){
101                         var fnc = Args.bindWithEvent(MooTools, ['rocks', 'da house']);
102                         var result = fnc('an Event occurred');
103                         expect(result[0]).to.equal(MooTools);
104                         expect(result).to.eql([MooTools, 'an Event occurred', 'rocks', 'da house']);
105                 });
106 //</1.2compat>
108         });
110         describe('Function.pass', function(){
112                 it('should return a function that when called passes the specified arguments to the original function', function(){
113                         var fnc = fn.pass('MooTools is beautiful and elegant');
114                         expect(fnc()).to.eql(['MooTools is beautiful and elegant']);
115                 });
117                 it('should pass multiple arguments and bind the function to a specific object when it is called', function(){
118                         var fnc = Args.pass(['rocks', 'da house'], MooTools);
119                         var result = fnc();
120                         expect(result[0]).to.equal(MooTools);
121                         expect(result).to.eql([MooTools, 'rocks', 'da house']);
122                 });
124         });
126 //<1.2compat>
127         describe('Function.run', function(){
129                 it('should run the function', function(){
130                         var result = fn.run();
131                         expect(result).to.eql([]);
132                 });
134                 it('should run the function with multiple arguments', function(){
135                         var result = fn.run(['MooTools', 'beautiful', 'elegant']);
136                         expect(result).to.eql(['MooTools', 'beautiful', 'elegant']);
137                 });
139                 it('should run the function with multiple arguments and bind the function to an object', function(){
140                         var result = Args.run(['beautiful', 'elegant'], MooTools);
141                         expect(result[0]).to.equal(MooTools);
142                         expect(result).to.eql([MooTools, 'beautiful', 'elegant']);
143                 });
145         });
146 //</1.2compat>
148         describe('Function.extend', function(){
150                 it('should extend the properties of a function', function(){
151                         var fnc = (function(){}).extend({a: 1, b: 'c'});
152                         expect(fnc.a).to.equal(1);
153                         expect(fnc.b).to.equal('c');
154                 });
156         });
158         describe('Function.attempt', function(){
160                 it('should call the function without raising an exception', function(){
161                         var fnc = function(){
162                                 this_should_not_work();
163                         };
164                         fnc.attempt();
165                 });
167                 it('should return the return value of a function', function(){
168                         var fnc = Function.convert('hello world!');
169                         expect(fnc.attempt()).to.equal('hello world!');
170                 });
172                 it('should return null if the function raises an exception', function(){
173                         var fnc = function(){
174                                 this_should_not_work();
175                         };
176                         expect(fnc.attempt()).to.equal(null);
177                 });
179         });
181         describe('Function.delay', function(){
183                 it('delay should return a timer pointer', function(){
184                         var referenceTimer = setTimeout(function(){}, 10000);
185                         var timer = (function(){}).delay(10000);
186                         expect(typeOf(timer)).to.equal(typeOf(referenceTimer));
187                         clearTimeout(timer);
188                         clearTimeout(referenceTimer);
189                 });
191         });
193         describe('Function.periodical', function(){
195                 it('periodical should return a timer pointer', function(){
196                         var referenceTimer = setInterval(function(){}, 10000);
197                         var timer = (function(){}).periodical(10000);
198                         expect(typeOf(timer)).to.equal(typeOf(referenceTimer));
199                         clearInterval(timer);
200                         clearInterval(referenceTimer);
201                 });
203         });
207 describe('Function.attempt', function(){
209         it('should return the result of the first successful function without executing successive functions', function(){
210                 var calls = 0;
211                 var attempt = Function.attempt(function(){
212                         calls++;
213                         throw new Exception();
214                 }, function(){
215                         calls++;
216                         return 'success';
217                 }, function(){
218                         calls++;
219                         return 'moo';
220                 });
221                 expect(calls).to.equal(2);
222                 expect(attempt).to.equal('success');
223         });
225         it('should return null when no function succeeded', function(){
226                 var calls = 0;
227                 var attempt = Function.attempt(function(){
228                         calls++;
229                         return I_invented_this();
230                 }, function(){
231                         calls++;
232                         return uninstall_ie();
233                 });
234                 expect(calls).to.equal(2);
235                 expect(attempt).to.equal(null);
236         });
240 })();
242 describe('Function.bind', function(){
244         it('should return the function bound to an object', function(){
245                 var spy = sinon.spy();
246                 var f = spy.bind('MooTools');
247                 expect(spy.called).to.equal(false);
248                 f();
249                 expect(spy.calledWith()).to.equal(true);
250                 f('foo', 'bar');
251                 expect(spy.calledWith('foo', 'bar')).to.equal(true);
252         });
254         it('should return the function bound to an object with specified argument', function(){
255                 var binding = {some: 'binding'};
256                 var spy = sinon.stub().returns('something');
257                 var f = spy.bind(binding, 'arg');
259                 expect(spy.called).to.equal(false);
260                 expect(f('additional', 'arguments')).to.equal('something');
261                 expect(spy.lastCall.thisValue).to.equal(binding);
262         });
264         it('should return the function bound to an object with multiple arguments', function(){
265                 var binding = {some: 'binding'};
266                 var spy = sinon.stub().returns('something');
267                 var f = spy.bind(binding, ['foo', 'bar']);
269                 expect(spy.called).to.equal(false);
270                 expect(f('additional', 'arguments')).to.equal('something');
271                 expect(spy.lastCall.thisValue).to.equal(binding);
272         });
274         dit('should still be possible to use it as constructor', function(){
275                 function Alien(type){
276                         this.type = type;
277                 }
279                 var thisArg = {};
280                 var Tribble = Alien.bind(thisArg, 'Polygeminus grex');
282                 // `thisArg` should **not** be used for the `this` binding when called as a constructor.
283                 var fuzzball = new Tribble('Klingon');
284                 expect(fuzzball.type).to.equal('Polygeminus grex');
285         });
287         dit('when using .call(thisArg) on a bound function, it should ignore the thisArg of .call', function(){
288                 var fn = function(){
289                         return [this.foo].concat(Array.slice(arguments));
290                 };
292                 expect(fn.bind({foo: 'bar'})()).to.eql(['bar']);
293                 expect(fn.bind({foo: 'bar'}, 'first').call({foo: 'yeah!'}, 'yooo')).to.eql(['bar', 'first', 'yooo']);
295                 var bound = fn.bind({foo: 'bar'});
296                 var bound2 = fn.bind({foo: 'yep'});
297                 var inst = new bound;
298                 inst.foo = 'noo!!';
299                 expect(bound2.call(inst, 'yoo', 'howdy')).to.eql(['yep', 'yoo', 'howdy']);
300         });
304 describe('Function.pass', function(){
306         it('should return a function that when called passes the specified arguments to the original function', function(){
307                 var spy = sinon.stub().returns('the result');
308                 var fnc = spy.pass('an argument');
309                 expect(spy.called).to.equal(false);
310                 expect(fnc('additional', 'arguments')).to.equal('the result');
311                 expect(spy.calledWith('an argument')).to.equal(true);
312                 expect(spy.callCount).to.equal(1);
313         });
315         it('should pass multiple arguments and bind the function to a specific object when it is called', function(){
316                 var spy = sinon.stub().returns('the result');
317                 var binding = {some: 'binding'};
318                 var fnc = spy.pass(['multiple', 'arguments'], binding);
319                 expect(spy.called).to.equal(false);
320                 expect(fnc('additional', 'arguments')).to.equal('the result');
321                 expect(spy.lastCall.thisValue).to.equal(binding);
322                 expect(spy.calledWith('multiple', 'arguments')).to.equal(true);
323         });
327 describe('Function.extend', function(){
329         it('should extend the properties of a function', function(){
330                 var fnc = (function(){}).extend({a: 1, b: 'c'});
331                 expect(fnc.a).to.equal(1);
332                 expect(fnc.b).to.equal('c');
333         });
337 describe('Function.attempt', function(){
339         it('should call the function without raising an exception', function(){
340                 var fnc = function(){
341                         throw 'up';
342                 };
343                 fnc.attempt();
344         });
346         it('should return the return value of a function', function(){
347                 var spy = sinon.stub().returns('hello world!');
348                 expect(spy.attempt()).to.equal('hello world!');
349         });
351         it('should return null if the function raises an exception', function(){
352                 var fnc = function(){
353                         throw 'up';
354                 };
355                 expect(fnc.attempt()).to.equal(null);
356         });
360 describe('Function.delay', function(){
362         beforeEach(function(){
363                 this.clock = sinon.useFakeTimers();
364         });
366         afterEach(function(){
367                 this.clock.reset();
368                 this.clock.restore();
369         });
371         it('should return a timer pointer', function(){
372                 var spyA = sinon.spy();
373                 var spyB = sinon.spy();
375                 var timerA = spyA.delay(200);
376                 var timerB = spyB.delay(200);
378                 this.clock.tick(100);
380                 expect(spyA.called).to.equal(false);
381                 expect(spyB.called).to.equal(false);
382                 clearTimeout(timerB);
384                 this.clock.tick(250);
385                 expect(spyA.callCount).to.equal(1);
386                 expect(spyB.callCount).to.equal(0);
387                 clearTimeout(timerA);
388         });
390         it('should pass parameter 0', function(){
391                 var spy = sinon.spy();
392                 spy.delay(50, null, 0);
394                 this.clock.tick(100);
395                 expect(spy.calledWith(0)).to.equal(true);
396         });
398         it('should not pass any argument when no arguments passed', function(){
399                 var argumentCount = null;
400                 var spy = function(){
401                         argumentCount = arguments.length;
402                 };
403                 spy.delay(50);
404                 this.clock.tick(100);
405                 expect(argumentCount).to.equal(0);
406         });
410 describe('Function.periodical', function(){
412         beforeEach(function(){
413                 this.clock = sinon.useFakeTimers();
414         });
416         afterEach(function(){
417                 this.clock.reset();
418                 this.clock.restore();
419         });
421         it('should return an interval pointer', function(){
422                 var spy = sinon.spy();
424                 var interval = spy.periodical(10);
425                 expect(spy.called).to.equal(false);
427                 this.clock.tick(100);
429                 expect(spy.callCount).to.be.greaterThan(2);
430                 expect(spy.callCount).to.be.lessThan(15);
431                 clearInterval(interval);
432                 spy.reset();
433                 expect(spy.called).to.equal(false);
435                 this.clock.tick(100);
437                 expect(spy.called).to.equal(false);
438         });
440         it('should pass parameter 0', function(){
441                 var spy = sinon.spy();
442                 var timer = spy.periodical(10, null, 0);
444                 this.clock.tick(100);
446                 expect(spy.calledWith(0)).to.equal(true);
447                 clearInterval(timer);
448         });
450         it('should not pass any argument when no arguments passed', function(){
451                 var argumentCount = null;
452                 var spy = function(){
453                         argumentCount = arguments.length;
454                 };
455                 var timer = spy.periodical(50);
456                 this.clock.tick(100);
458                 expect(argumentCount).to.equal(0);
459                 clearInterval(timer);
460         });