Tests/Specs: Replace Chai with expect.js for assertions, because of browser support.
[mootools.git] / Specs / Core / Core.js
blob52db3b450e7686af217e45d6dec62d97532ffddc
1 /*
2 ---
3 name: Core
4 requires: ~
5 provides: ~
6 ...
7 */
9 //<1.2compat>
10 describe('$A', function(){
12         it('should return a copy for an array', function(){
13                 var arr1 = [1,2,3];
14                 var arr2 = $A(arr1);
15                 expect(arr1).to.not.equal(arr2);
16         });
18         it('should return an array for an Elements collection', function(){
19                 var div1 = document.createElement('div');
20                 var div2 = document.createElement('div');
21                 var div3 = document.createElement('div');
23                 div1.appendChild(div2);
24                 div1.appendChild(div3);
26                 var array = $A(div1.getElementsByTagName('*'));
27                 expect(Array.type(array)).to.equal(true);
28         });
30         it('should return an array for arguments', function(){
31                 var fnTest = function(){
32                         return $A(arguments);
33                 };
34                 var arr = fnTest(1,2,3);
35                 expect(Array.type(arr)).to.equal(true);
36                 expect(arr.length).to.equal(3);
37         });
39 });
41 describe('$arguments', function(){
43         it('should return the argument passed according to the index', function(){
44                 expect($arguments(0)('a','b','c','d')).to.equal('a');
45                 expect($arguments(1)('a','b','c','d')).to.equal('b');
46                 expect($arguments(2)('a','b','c','d')).to.equal('c');
47                 expect($arguments(3)('a','b','c','d')).to.equal('d');
48         });
50 });
52 describe('$chk', function(){
54         it('should return false on false', function(){
55                 expect($chk(false)).to.equal(false);
56         });
58         it('should return false on null', function(){
59                 expect($chk(null)).to.equal(false);
60         });
62         it('should return false on undefined', function(){
63                 expect($chk(undefined)).to.equal(false);
64         });
66         it('should return true on 0', function(){
67                 expect($chk(0)).to.equal(true);
68         });
70         it('should return true for any truthsie', function(){
71                 expect($chk(1)).to.equal(true);
72                 expect($chk({})).to.equal(true);
73                 expect($chk(true)).to.equal(true);
74         });
76 });
78 describe('$clear', function(){
80         it('should clear timeouts', function(){
81                 var timeout = setTimeout(function(){}, 100);
82                 expect($clear(timeout)).to.equal(null);
83         });
85         it('should clear intervals', function(){
86                 var interval = setInterval(function(){}, 100);
87                 expect($clear(interval)).to.equal(null);
88         });
90 });
92 describe('$defined', function(){
94         it('should return true on 0', function(){
95                 expect($defined(0)).to.equal(true);
96         });
98         it('should return true on false', function(){
99                 expect($defined(false)).to.equal(true);
100         });
102         it('should return false on null', function(){
103                 expect($defined(null)).to.equal(false);
104         });
106         it('should return false on undefined', function(){
107                 expect($defined(undefined)).to.equal(false);
108         });
112 describe('$each', function(){
114         it('should call the function for each item in Function arguments', function(){
115                 var daysArr = [];
116                 (function(){
117                         $each(arguments, function(value, key){
118                                 daysArr[key] = value;
119                         });
120                 })('Sun','Mon','Tue');
122                 expect(daysArr).to.eql(['Sun','Mon','Tue']);
123         });
125         it('should call the function for each item in the array', function(){
126                 var daysArr = [];
127                 $each(['Sun','Mon','Tue'], function(value, key){
128                         daysArr[key] = value;
129                 });
131                 expect(daysArr).to.eql(['Sun','Mon','Tue']);
132         });
134         it('should call the function for each item in the object', function(){
135                 var daysObj = {};
136                 $each({first: "Sunday", second: "Monday", third: "Tuesday"}, function(value, key){
137                         daysObj[key] = value;
138                 });
140                 expect(daysObj).to.eql({first: 'Sunday', second: 'Monday', third: 'Tuesday'});
141         });
145 describe('$extend', function(){
147         it('should extend two objects', function(){
148                 var obj1 = {a: 1, b: 2};
149                 var obj2 = {b: 3, c: 4};
150                 $extend(obj1, obj2);
151                 expect(obj1).to.eql({a: 1, b: 3, c: 4});
152         });
154         it('should overwrite properties', function(){
155                 var obj1 = {a: 1, b: 2};
156                 var obj2 = {b: 3, c: 4, a: 5};
157                 $extend(obj1, obj2);
158                 expect(obj1).to.eql({a: 5, b: 3, c: 4});
159         });
161         it('should not extend with null argument', function(){
162                 var obj1 = {a: 1, b: 2};
163                 $extend(obj1);
164                 expect(obj1).to.eql({a: 1, b: 2});
165         });
169 describe('$lambda', function(){
171         it('if a function is passed in that function should be returned', function(){
172                 var fn = function(a,b){ return a; };
173                 expect($lambda(fn)).to.equal(fn);
174         });
176         it('should return a function that returns the value passed when called', function(){
177                 expect($lambda('hello world!')()).to.equal('hello world!');
178         });
182 describe('$merge', function(){
184         it('should dereference objects', function(){
185                 var obj1 = {a: 1, b: 2};
186                 var obj2 = $merge(obj1);
187                 expect(obj1).to.not.equal(obj2);
188         });
190         it('should merge any arbitrary number of nested objects', function(){
191                 var obj1 = {a: {a: 1, b: 2, c: 3}, b: 2};
192                 var obj2 = {a: {a: 2, b: 8, c: 3, d: 8}, b: 3, c: 4};
193                 var obj3 = {a: {a: 3}, b: 3, c: false};
194                 expect($merge(obj1, obj2, obj3)).to.eql({a: {a: 3, b: 8, c: 3, d: 8}, b: 3, c: false});
195         });
199 describe('$pick', function(){
201         it('should return the first false argument', function(){
202                 var picked1 = $pick(null, undefined, false, [1,2,3], {});
203                 expect(picked1).to.equal(false);
204         });
206         it('should return the first defined argument', function(){
207                 var picked1 = $pick(null, undefined, null, [1,2,3], {});
208                 expect(picked1).to.eql([1,2,3]);
209         });
213 describe('$random', function(){
215         it('should return a number between two numbers specified', function(){
216                 var rand = $random(1, 3);
217                 expect(rand).to.be.within(1, 3);
218         });
222 describe('$splat', function(){
224         it('should transform a non array into an array', function(){
225                 expect($splat(1)).to.eql([1]);
226         });
228         it('should transforum an undefined or null into an empty array', function(){
229                 expect($splat(null)).to.eql([]);
230                 expect($splat(undefined)).to.eql([]);
231         });
233         it('should ignore and return an array', function(){
234                 expect($splat([1,2,3])).to.eql([1,2,3]);
235         });
239 describe('$time', function(){
241         it('should return a timestamp', function(){
242                 expect(Number.type($time())).to.equal(true);
243         });
245         it('should be within a reasonable range', function(){
246                 var time = $time();
247                 expect(time).to.be.greaterThan(1e12);
248                 expect(time).to.be.lessThan(1e13);
249         });
253 describe('$try', function(){
255         it('should return the result of the first successful function without executing successive functions', function(){
256                 var calls = 0;
257                 var attempt = $try(function(){
258                         calls++;
259                         throw new Exception();
260                 }, function(){
261                         calls++;
262                         return 'success';
263                 }, function(){
264                         calls++;
265                         return 'moo';
266                 });
267                 expect(calls).to.equal(2);
268                 expect(attempt).to.equal('success');
269         });
271         it('should return null when no function succeeded', function(){
272                 var calls = 0;
273                 var attempt = $try(function(){
274                         calls++;
275                         return I_invented_this();
276                 }, function(){
277                         calls++;
278                         return uninstall_ie();
279                 });
280                 expect(calls).to.equal(2);
281                 expect(attempt).to.equal(null);
282         });
287 describe('$type', function(){
289         it("should return 'array' for Array objects", function(){
290                 expect($type([1,2])).to.equal('array');
291         });
293         it("should return 'string' for String objects", function(){
294                 expect($type('ciao')).to.equal('string');
295         });
297         it("should return 'regexp' for RegExp objects", function(){
298                 expect($type(/_/)).to.equal('regexp');
299         });
301         it("should return 'function' for Function objects", function(){
302                 expect($type(function(){})).to.equal('function');
303         });
305         it("should return 'number' for Number objects", function(){
306                 expect($type(10)).to.equal('number');
307                 expect($type(NaN)).to.not.equal('number');
308         });
310         it("should return 'boolean' for Boolean objects", function(){
311                 expect($type(true)).to.equal('boolean');
312                 expect($type(false)).to.equal('boolean');
313         });
315         it("should return 'object' for Object objects", function(){
316                 expect($type({a:2})).to.equal('object');
317         });
319         it("should return 'arguments' for Function arguments", function(){
320                 if (window.opera){ // Seems like the Opera guys can't decide on this
321                         var type = $type(arguments);
322                         expect(type == 'array' || type == 'arguments').to.equal(true);
323                         return;
324                 }
326                 expect($type(arguments)).to.equal('arguments');
327         });
329         it("should return false for null objects", function(){
330                 expect($type(null)).to.equal(false);
331         });
333         it("should return false for undefined objects", function(){
334                 expect($type(undefined)).to.equal(false);
335         });
337         it("should return 'collection' for HTMLElements collections", function(){
338                 expect($type(document.getElementsByTagName('*'))).to.equal('collection');
339         });
341         it("should return 'element' for an Element", function(){
342                 var div = document.createElement('div');
343                 expect($type(div)).to.equal('element');
344         });
346         it("should return 'array' for Elements", function(){
347                 expect($type(new Elements)).to.equal('array');
348         });
350         it("should return 'window' for the window object", function(){
351                 expect($type(window)).to.equal('window');
352         });
354         it("should return 'document' for the document object", function(){
355                 expect($type(document)).to.equal('document');
356         });
360 describe('$unlink', function(){
362         it("should unlink an object recursivly", function(){
363                 var inner = {b: 2};
364                 var obj = {a: 1, inner: inner};
365                 var copy = $unlink(obj);
366                 obj.a = 10;
367                 inner.b = 20;
369                 expect(obj.a).to.equal(10);
370                 expect(obj.inner.b).to.equal(20);
371                 expect($type(obj)).to.equal('object');
373                 expect(copy.a).to.equal(1);
374                 expect(copy.inner.b).to.equal(2);
375                 expect($type(copy)).to.equal('object');
376         });
378         it("should unlink an Hash", function(){
379                 var hash = new Hash({a: 'one'});
380                 var copy = $unlink(hash);
382                 expect($type(hash)).to.equal('hash');
383                 expect($type(copy)).to.equal('hash');
385                 copy.set('a', 'two');
387                 expect(hash.get('a')).to.equal('one');
388                 expect(copy.get('a')).to.equal('two');
389         });
393 describe('Hash.getLength', function(){
395         it("should return the number of items in it", function(){
396                 var hash = new Hash({});
397                 expect(hash.getLength()).to.equal(0);
398                 hash.set('mootools', 'awesome');
399                 hash.milk = 'yummy';
400                 expect(hash.getLength()).to.equal(2);
401         });
403         it("should not fail when length is set", function(){
404                 var hash = new Hash({'length': 10});
405                 expect(hash.getLength()).to.equal(1);
406         });
408         it("should work as a generic on objects", function(){
409                 expect(Hash.getLength({})).to.equal(0);
410                 expect(Hash.getLength({'': '', '0': '0', 'length': 99})).to.equal(3);
411         });
415 describe('$H', function(){
417         it("should create a new hash", function(){
418                 var hash = $H({});
419                 expect($type(hash)).to.equal('hash');
420         });
424 //</1.2compat>
427 describe('Function.prototype.overloadSetter', function(){
429         var collector, setter;
430         beforeEach(function(){
431                 collector = {};
432                 setter = (function(key, value){
433                         collector[key] = value;
434                 });
435         });
437         it('should call a specific setter', function(){
438                 setter = setter.overloadSetter();
439                 setter('key', 'value');
441                 expect(collector).to.eql({key: 'value'});
443                 setter({
444                         otherKey: 1,
445                         property: 2
446                 });
448                 expect(collector).to.eql({
449                         key: 'value',
450                         otherKey: 1,
451                         property: 2
452                 });
454                 setter({
455                         key: 3
456                 });
457                 setter('otherKey', 4);
459                 expect(collector).to.eql({
460                         key: 3,
461                         otherKey: 4,
462                         property: 2
463                 });
464         });
466         it('should only works with objects in plural mode', function(){
467                 setter = setter.overloadSetter(true);
469                 setter({
470                         a: 'b',
471                         c: 'd'
472                 });
474                 expect(collector).to.eql({
475                         a: 'b',
476                         c: 'd'
477                 });
478         });
482 describe('Function.prototype.overloadGetter', function(){
484         var object, getter;
485         beforeEach(function(){
486                 object = {
487                         aa: 1,
488                         bb: 2,
489                         cc: 3
490                 };
492                 getter = (function(key){
493                         return object[key] || null;
494                 });
495         });
497         it('should call a getter for each argument', function(){
498                 getter = getter.overloadGetter();
500                 expect(getter('aa')).to.equal(1);
501                 expect(getter('bb')).to.equal(2);
502                 expect(getter('cc')).to.equal(3);
503                 expect(getter('dd')).to.equal(null);
505                 expect(getter('aa', 'bb', 'cc')).to.eql(object);
506                 expect(getter(['aa', 'bb', 'cc'])).to.eql(object);
507                 expect(getter(['aa', 'cc', 'dd'])).to.eql({aa: 1, cc: 3, dd: null});
508         });
510         it('should work in plural mode', function(){
511                 getter = getter.overloadGetter(true);
513                 expect(getter('aa')).to.eql({
514                         aa: 1
515                 });
517                 expect(getter(['aa', 'bb'])).to.eql({
518                         aa: 1,
519                         bb: 2
520                 });
522         })
526 describe('typeOf', function(){
528         it("should return 'array' for Array objects", function(){
529                 expect(typeOf([1,2])).to.equal('array');
530         });
532         it("should return 'string' for String objects", function(){
533                 expect(typeOf('ciao')).to.equal('string');
534         });
536         it("should return 'regexp' for RegExp objects", function(){
537                 expect(typeOf(/_/)).to.equal('regexp');
538         });
540         it("should return 'function' for Function objects", function(){
541                 expect(typeOf(function(){})).to.equal('function');
542         });
544         it("should return 'number' for Number objects", function(){
545                 expect(typeOf(10)).to.equal('number');
546                 expect(typeOf(NaN)).to.not.equal('number');
547         });
549         it("should return 'boolean' for Boolean objects", function(){
550                 expect(typeOf(true)).to.equal('boolean');
551                 expect(typeOf(false)).to.equal('boolean');
552         });
554         it("should return 'object' for Object objects", function(){
555                 expect(typeOf({a:2})).to.equal('object');
556         });
558         it("should return 'arguments' for Function arguments", function(){
559                 if (typeof window != 'undefined' && window.opera){ // Seems like the Opera guys can't decide on this
560                         var type = typeOf(arguments);
561                         expect(type == 'array' || type == 'arguments').to.equal(true);
562                         return;
563                 }
565                 expect(typeOf(arguments)).to.equal('arguments');
566         });
568         it("should return 'null' for null objects", function(){
569                 expect(typeOf(null)).to.equal('null');
570         });
572         it("should return 'null' for undefined objects", function(){
573                 expect(typeOf(undefined)).to.equal('null');
574         });
578 describe('instanceOf', function(){
580         it("should return false on null object", function(){
581                 expect(instanceOf(null, null)).to.equal(false);
582         });
584         it("should return true for Arrays", function(){
585                 expect(instanceOf([], Array)).to.equal(true);
586         });
588         it("should return true for Numbers", function(){
589                 expect(instanceOf(1, Number)).to.equal(true);
590         });
592         it("should return true for Objects", function(){
593                 expect(instanceOf({}, Object)).to.equal(true);
594         });
596         it("should return true for Dates", function(){
597                 expect(instanceOf(new Date(), Date)).to.equal(true);
598         });
600         it("should return true for Booleans", function(){
601                 expect(instanceOf(true, Boolean)).to.equal(true);
602         });
604         it("should return true for RegExps", function(){
605                 expect(instanceOf(/_/, RegExp)).to.equal(true);
606         });
608         it("should respect the parent property of a custom object", function(){
609                 var X = function(){};
610                 X.parent = Array;
611                 expect(instanceOf(new X, Array)).to.equal(true);
612         });
614         // todo(ibolmo)
615         var dit = typeof window != 'undefined' && window.Element && Element.set ? it : xit;
616         dit("should return true for Element instances", function(){
617                 expect(instanceOf(new Element('div'), Element)).to.equal(true);
618         });
622 describe('Array.from', function(){
624         it('should return the same array', function(){
625                 var arr1 = [1,2,3];
626                 var arr2 = Array.from(arr1);
627                 expect(arr1).to.equal(arr2);
628         });
630         it('should return an array for arguments', function(){
631                 var fnTest = function(){
632                         return Array.from(arguments);
633                 };
634                 var arr = fnTest(1,2,3);
635                 expect(Type.isArray(arr)).to.equal(true);
636                 expect(arr.length).to.equal(3);
637         });
639         it('should transform a non array into an array', function(){
640                 expect(Array.from(1)).to.eql([1]);
641         });
643         it('should transforum an undefined or null into an empty array', function(){
644                 expect(Array.from(null)).to.eql([]);
645                 expect(Array.from(undefined)).to.eql([]);
646         });
648         it('should ignore and return an array', function(){
649                 expect(Array.from([1,2,3])).to.eql([1,2,3]);
650         });
652         it('should return a copy of arguments or the arguments if it is of type array', function(){
653                 // In Opera arguments is an array so it does not return a copy
654                 // This is intended. Array.from is expected to return an Array from an array-like-object
655                 // It does not make a copy when the passed in value is an array already
656                 var args, type, copy = (function(){
657                         type = typeOf(arguments);
658                         args = arguments;
660                         return Array.from(arguments);
661                 })(1, 2);
663                 if (type === 'array'){
664                         expect(copy).to.equal(args);
665                 } else {
666                         expect(copy).to.not.equal(args);
667                 }
668         });
672 describe('String.from', function(){
674         it('should convert to type string', function(){
675                 expect(typeOf(String.from('string'))).to.equal('string');
677                 expect(typeOf(String.from(1))).to.equal('string');
679                 expect(typeOf(String.from(new Date))).to.equal('string');
681                 expect(typeOf(String.from(function(){}))).to.equal('string');
682         });
686 describe('Function.from', function(){
688         it('if a function is passed in that function should be returned', function(){
689                 var fn = function(a,b){ return a; };
690                 expect(Function.from(fn)).to.equal(fn);
691         });
693         it('should return a function that returns the value passed when called', function(){
694                 expect(Function.from('hello world!')()).to.equal('hello world!');
695         });
699 describe('Number.from', function(){
701         it('should return the number representation of a string', function(){
702                 expect(Number.from("10")).to.equal(10);
703                 expect(Number.from("10px")).to.equal(10);
704         });
706         it('should return null when it fails to return a number type', function(){
707                 expect(Number.from("ciao")).to.equal(null);
708         });
712 describe('Type', function(){
714         var Instrument = new Type('Instrument', function(name){
715                 this.name = name;
716         }).implement({
718                 method: function(){
719                         return 'playing ' + this.name;
720                 }
722         });
724         var Car = new Type('Car', function(name){
725                 this.name = name;
726         }).implement({
728                 method: (function(){
729                         return 'driving a ' + this.name;
730                 }).protect()
732         });
734         it('should allow implementation over existing methods when a method is not protected', function(){
735                 Instrument.implement({
736                         method: function(){
737                                 return 'playing a guitar';
738                         }
739                 });
740                 var myInstrument = new Instrument('Guitar');
741                 expect(myInstrument.method()).to.equal('playing a guitar');
742         });
744         it('should not override a method when it is protected', function(){
745                 Car.implement({
746                         method: function(){
747                                 return 'hell no!';
748                         }
749                 });
750                 var myCar = new Car('nice car');
751                 expect(myCar.method()).to.equal('driving a nice car');
752         });
754         it('should allow generic calls', function(){
755                 expect(Car.method({name: 'not so nice car'})).to.equal('driving a not so nice car');
756         });
758         it("should be a Type", function(){
759                 expect(Type.isType(Instrument)).to.equal(true);
760         });
762         it("should generate and evaluate correct types", function(){
763                 var myCar = new Car('nice car');
764                 expect(Type.isCar(myCar)).to.equal(true);
765         });
767         it("isEnumerable method on Type should return true for arrays, arguments, objects with a numerical length property", function(){
768                 expect(Type.isEnumerable([1,2,3])).to.equal(true);
769                 (function(){
770                         expect(Type.isEnumerable(arguments)).to.equal(true);
771                 })(1,2,3);
772                 expect(Type.isEnumerable({length: 2})).to.equal(true);
773         });
775         it('sould chain any function on a type', function(){
776                 var MyType = new Type('MyType', function(){}.implement({
777                         a: function(){}
778                 }));
780                 expect(MyType.alias('a', 'b').implement({
781                         method: function(){}
782                 }).extend({
783                         staticMethod: function(){}
784                 })).to.equal(MyType);
785         });
789 describe('Object.keys', function(){     
791         var object = { a: 'string', b: 233, c: {} };
793         it('keys should return an empty array', function(){
794                 expect(Object.keys({})).to.eql([]);
795         });
797         it('should return an array containing the keys of the object', function(){
798                 expect(Object.keys(object)).to.eql(['a', 'b', 'c']);
799         });
801         it('should return an array containing non-enum keys', function(){
802                 var buggy = {constructor: 'foo', valueOf: 'bar'};
803                 var keys = Object.keys(buggy).join('');
804                 expect(keys.indexOf('constructor')).to.not.equal(-1);
805                 expect(keys.indexOf('valueOf')).to.not.equal(-1);
806         });
810 describe('Object.each', function(){
812         it('should call the function for each item in the object', function(){
813                 var daysObj = {};
814                 Object.each({first: "Sunday", second: "Monday", third: "Tuesday"}, function(value, key){
815                         daysObj[key] = value;
816                 });
818                 expect(daysObj).to.eql({first: 'Sunday', second: 'Monday', third: 'Tuesday'});
819         });
821         it('should call non-enumerable properties too', function(){
822                 var obj = {
823                         foo: 'bar',
824                         constructor: "constructor",
825                         hasOwnProperty: "hasOwnProperty",
826                         isPrototypeOf: "isPrototypeOf",
827                         propertyIsEnumerable: "propertyIsEnumerable",
828                         toLocaleString: "toLocaleString",
829                         toString: "toString",
830                         valueOf: "valueOf"
831                 };
833                 var keysInObject = true, iteration = 0;
834                 var props = ['foo', 'hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'].join('');
836                 Object.each(obj, function(i, k){
837                         iteration++;
838                         if (props.indexOf(k) == -1) keysInObject = false;  
839                 });
841                 expect(keysInObject).to.equal(true);
842                 expect(iteration).to.equal(8);
843         });
847 describe('Array.each', function(){
849         it('should call the function for each item in Function arguments', function(){
850                 var daysArr = [];
851                 (function(){
852                         Array.each(Array.from(arguments), function(value, key){
853                                 daysArr[key] = value;
854                         });
855                 })('Sun','Mon','Tue');
857                 expect(daysArr).to.eql(['Sun','Mon','Tue']);
858         });
860         it('should call the function for each item in the array', function(){
861                 var daysArr = [];
862                 Array.each(['Sun','Mon','Tue'], function(value, i){
863                         daysArr.push(value);
864                 });
866                 expect(daysArr).to.eql(['Sun','Mon','Tue']);
867         });
869         it('should not iterate over deleted elements', function(){
870                 var array = [0, 1, 2, 3],
871                         testArray = [];
872                 delete array[1];
873                 delete array[2];
875                 array.each(function(value){
876                         testArray.push(value);
877                 });
879                 expect(testArray).to.eql([0, 3]);
880         });
884 describe('Array.clone', function(){
885         it('should recursively clone and dereference arrays and objects, while mantaining the primitive values', function(){
886                 var a = [1,2,3, [1,2,3, {a: [1,2,3]}]];
887                 var b = Array.clone(a);
888                 expect(a).to.not.equal(b);
889                 expect(a[3]).to.not.equal(b[3]);
890                 expect(a[3][3]).to.not.equal(b[3][3]);
891                 expect(a[3][3].a).to.not.equal(b[3][3].a);
893                 expect(a[3]).to.eql(b[3]);
894                 expect(a[3][3]).to.eql(b[3][3]);
895                 expect(a[3][3].a).to.eql(b[3][3].a);
896         });
899 describe('Object.clone', function(){
900         it('should recursively clone and dereference arrays and objects, while mantaining the primitive values', function(){
901                 var a = {a:[1,2,3, [1,2,3, {a: [1,2,3]}]]};
902                 var b = Object.clone(a);
903                 expect(a).to.not.equal(b);
904                 expect(a.a[3]).to.not.equal(b.a[3]);
905                 expect(a.a[3][3]).to.not.equal(b.a[3][3]);
906                 expect(a.a[3][3].a).to.not.equal(b.a[3][3].a);
908                 expect(a.a[3]).to.eql(b.a[3]);
909                 expect(a.a[3][3]).to.eql(b.a[3][3]);
910                 expect(a.a[3][3].a).to.eql(b.a[3][3].a);
911         });
914 describe('Object.merge', function(){
916         it('should merge any object inside the passed in object, and should return the passed in object', function(){
917                 var a = {a:1, b:2, c: {a:1, b:2, c:3}};
918                 var b = {c: {d:4}, d:4};
919                 var c = {a: 5, c: {a:5}};
921                 var merger = Object.merge(a, b);
923                 expect(merger).to.eql({a:1, b:2, c:{a:1, b:2, c:3, d:4}, d:4});
924                 expect(merger).to.equal(a);
926                 expect(Object.merge(a, b, c)).to.eql({a:5, b:2, c:{a:5, b:2, c:3, d:4}, d:4});
927         });
929         it('should recursively clone sub objects and sub-arrays', function(){
930                 var a = {a:1, b:2, c: {a:1, b:2, c:3}, d: [1,2,3]};
931                 var b = {e: {a:1}, f: [1,2,3]};
933                 var merger = Object.merge(a, b);
935                 expect(a.e).to.not.equal(b.e);
936                 expect(a.f).to.not.equal(b.f);
937         });
941 describe('Object.append', function(){
942         it('should combine two objects', function(){
943                 var a = {a: 1, b: 2}, b = {b: 3, c: 4};
944                 expect(Object.append(a, b)).to.eql({a: 1, b: 3, c: 4});
946                 a = {a: 1, b: 2}; b = {b: 3, c: 4};
947                 expect(Object.append(a, b)).to.equal(a);
949                 a = {a: 1, b: 2}; b = {b: 3, c: 4};
950                 var c = {a: 2, d: 5};
951                 expect(Object.append(a, b, c)).to.eql({a: 2, b: 3, c: 4, d: 5});
952         });
955 describe('Date.now', function(){
957         it('should return a timestamp', function(){
958                 expect(Type.isNumber(Date.now())).to.equal(true);
959         });
963 describe('String.uniqueID', function(){
965         it('should be a string', function(){
966                 expect(typeof String.uniqueID()).to.equal('string');
967         });
969         it("should generate unique ids", function(){
970                 expect(String.uniqueID()).to.not.equal(String.uniqueID());
971         });
975 describe('typeOf Client', function(){
977         var dit = typeof document == 'undefined' ? xit : it;
978         dit("should return 'collection' for HTMLElements collections", function(){
979                 expect(typeOf(document.getElementsByTagName('*'))).to.equal('collection');
980         });
982         dit("should return 'element' for an Element", function(){
983                 var div = document.createElement('div');
984                 expect(typeOf(div)).to.equal('element');
985         });
987         // todo(ibolmo)
988         if (typeof window != 'undefined' && window.Elements) dit("should return 'elements' for Elements", function(){
989                 expect(typeOf(new Elements)).to.equal('elements');
990         });
992         if (typeof window != 'undefined' && window.Browser) dit("should return 'window' for the window object", function(){
993                 expect(typeOf(window)).to.equal('window');
994         });
996         if (typeof window != 'undefined' && window.Browser) dit("should return 'document' for the document object", function(){
997                 expect(typeOf(document)).to.equal('document');
998         });
1002 describe('Array.from', function(){
1004         var dit = typeof document == 'undefined' ? xit : it;
1005         dit('should return an array for an Elements collection', function(){
1006                 var div1 = document.createElement('div');
1007                 var div2 = document.createElement('div');
1008                 var div3 = document.createElement('div');
1010                 div1.appendChild(div2);
1011                 div1.appendChild(div3);
1013                 var array = Array.from(div1.getElementsByTagName('*'));
1014                 expect(Type.isArray(array)).to.equal(true);
1015         });
1017         dit('should return an array for an Options collection', function(){
1018                 var div = document.createElement('div');
1019                 div.innerHTML = '<select><option>a</option></select>';
1020                 var select = div.firstChild;
1021                 var array = Array.from(select.options);
1022                 expect(Type.isArray(array)).to.equal(true);
1023         });
1028 describe('Core', function(){
1030         describe('typeOf', function(){
1031                 it('should correctly report the type of arguments when using "use strict"', function(){
1032                         "use strict";
1033                         expect(typeOf(arguments)).to.equal('arguments');
1034                 });
1035         });