describe('Function', function() { "use strict"; describe('bind', function() { var actual, expected, testSubject; testSubject = { push: function(o) { this.a.push(o); } }; function func() { Array.prototype.forEach.call(arguments, function(a) { this.push(a); }, this); return this; }; beforeEach(function() { actual = []; testSubject.a = []; }); it('binds properly without a context', function() { var context; testSubject.func = function() { context = this; }.bind(); testSubject.func(); expect(context).toBe(function() {return this}.call()); }); it('binds properly without a context, and still supplies bound arguments', function() { var a, context; testSubject.func = function() { a = Array.prototype.slice.call(arguments); context = this; }.bind(undefined, 1,2,3); testSubject.func(1,2,3); expect(a).toEqual([1,2,3,1,2,3]); expect(context).toBe(function() {return this}.call()); }); it('binds a context properly', function() { testSubject.func = func.bind(actual); testSubject.func(1,2,3); expect(actual).toEqual([1,2,3]); expect(testSubject.a).toEqual([]); }); it('binds a context and supplies bound arguments', function() { testSubject.func = func.bind(actual, 1,2,3); testSubject.func(4,5,6); expect(actual).toEqual([1,2,3,4,5,6]); expect(testSubject.a).toEqual([]); }); it('returns properly without binding a context', function() { testSubject.func = function() { return this; }.bind(); var context = testSubject.func(); expect(context).toBe(function() {return this}.call()); }); it('returns properly without binding a context, and still supplies bound arguments', function() { var context; testSubject.func = function() { context = this; return Array.prototype.slice.call(arguments); }.bind(undefined, 1,2,3); actual = testSubject.func(1,2,3); expect(context).toBe(function() {return this}.call()); expect(actual).toEqual([1,2,3,1,2,3]); }); it('returns properly while binding a context properly', function() { var ret; testSubject.func = func.bind(actual); ret = testSubject.func(1,2,3); expect(ret).toBe(actual); expect(ret).not.toBe(testSubject); }); it('returns properly while binding a context and supplies bound arguments', function() { var ret; testSubject.func = func.bind(actual, 1,2,3); ret = testSubject.func(4,5,6); expect(ret).toBe(actual); expect(ret).not.toBe(testSubject); }); it('passes the correct arguments as a constructor', function() { var ret, expected = { name: "Correct" }; testSubject.func = function(arg) { return arg; }.bind({ name: "Incorrect" }); ret = new testSubject.func(expected); expect(ret).toBe(expected); }); it('returns the return value of the bound function when called as a constructor', function () { var oracle = [1, 2, 3]; var subject = function () { return oracle; }.bind(null); var result = new subject; expect(result).toBe(oracle); }); it('returns the correct value if constructor returns primitive', function() { var oracle = [1, 2, 3]; var subject = function () { return oracle; }.bind(null); var result = new subject; expect(result).toBe(oracle); oracle = {}; result = new subject; expect(result).toBe(oracle); oracle = function(){}; result = new subject; expect(result).toBe(oracle); oracle = "asdf"; result = new subject; expect(result).not.toBe(oracle); oracle = null; result = new subject; expect(result).not.toBe(oracle); oracle = true; result = new subject; expect(result).not.toBe(oracle); oracle = 1; result = new subject; expect(result).not.toBe(oracle); }); it('returns the value that instance of original "class" when called as a constructor', function() { var classA = function(x) { this.name = x || "A"; } var classB = classA.bind(null, "B"); var result = new classB; expect(result instanceof classA).toBe(true); expect(result instanceof classB).toBe(true); }); }); });