diff --git a/misc/test-lib/helpers.js b/misc/test-lib/helpers.js index b3d4b0f..452c7fd 100644 --- a/misc/test-lib/helpers.js +++ b/misc/test-lib/helpers.js @@ -1,25 +1,57 @@ // jasmine matcher for expecting an element to have a css class // https://github.com/angular/angular.js/blob/master/test/matchers.js beforeEach(function() { - this.addMatchers({ - toHaveClass: function(cls) { - this.message = function() { - return "Expected '" + this.actual + "'" + (this.isNot ? ' not ' : ' ') + "to have class '" + cls + "'."; - }; + jasmine.addMatchers({ + toHaveClass: function(util, customEqualityTesters) { + return { + compare: function(actual, expected) { + var result = { + pass: actual.hasClass(expected) + }; - return this.actual.hasClass(cls); - }, - toBeHidden: function () { - var element = angular.element(this.actual); - return element.hasClass('ng-hide') || - element.css('display') == 'none'; - }, - toHaveFocus: function () { - this.message = function () { - return 'Expected \'' + angular.mock.dump(this.actual) + '\' to have focus'; - }; + if (result.pass) { + result.message = 'Expected "' + actual + '" not to have the "' + expected + '" class.'; + } else { + result.message = 'Expected "' + actual + '" to have the "' + expected + '" class.'; + } - return document.activeElement === this.actual[0]; + return result; + } + } + }, + toBeHidden: function(util, customEqualityTesters) { + return { + compare: function(actual) { + var result = { + pass: actual.hasClass('ng-hide') || actual.css('display') === 'none' + }; + + if (result.pass) { + result.message = 'Expected "' + actual + '" not to be hidden'; + } else { + result.message = 'Expected "' + actual + '" to be hidden'; + } + + return result; + } + } + }, + toHaveFocus: function(util, customEqualityTesters) { + return { + compare: function(actual) { + var result = { + pass: document.activeElement === actual[0] + }; + + if (result.pass) { + result.message = 'Expected "' + actual + '" not to have focus'; + } else { + result.message = 'Expected "' + actual + '" to have focus'; + } + + return result; + } + } } }); }); diff --git a/package.json b/package.json index a5415e1..a02bc58 100644 --- a/package.json +++ b/package.json @@ -22,11 +22,12 @@ "grunt-html2js": "^0.3.0", "grunt-karma": "^0.10.1", "grunt-ngdocs": "~0.1.1", + "jasmine-core": "^2.2.0", "karma": "^0.12.31", "karma-chrome-launcher": "^0.1.7", "karma-coverage": "^0.2.7", "karma-firefox-launcher": "^0.1.4", - "karma-jasmine": "^0.1.5", + "karma-jasmine": "^0.3.5", "node-markdown": "0.1.1", "semver": "^4.3.3", "shelljs": "^0.4.0" diff --git a/src/buttons/test/buttons.spec.js b/src/buttons/test/buttons.spec.js index bd1e817..f1ef660 100644 --- a/src/buttons/test/buttons.spec.js +++ b/src/buttons/test/buttons.spec.js @@ -201,7 +201,7 @@ describe('buttons', function () { expect(btns.eq(1)).not.toHaveClass('active'); btns.eq(0).click(); - expect($scope.model).toEqual(undefined); + expect($scope.model).toBeNull(); expect(btns.eq(1)).not.toHaveClass('active'); expect(btns.eq(0)).not.toHaveClass('active'); }); @@ -225,4 +225,4 @@ describe('buttons', function () { }); }); }); -}); \ No newline at end of file +}); diff --git a/src/carousel/test/carousel.spec.js b/src/carousel/test/carousel.spec.js index f89dab6..86e5a07 100644 --- a/src/carousel/test/carousel.spec.js +++ b/src/carousel/test/carousel.spec.js @@ -262,7 +262,7 @@ describe('carousel', function() { testSlideActive(2); $interval.flush(scope.interval); testSlideActive(0); - spyOn($interval, 'cancel').andCallThrough(); + spyOn($interval, 'cancel').and.callThrough(); scope.$destroy(); expect($interval.cancel).toHaveBeenCalled(); }); @@ -396,17 +396,17 @@ describe('carousel', function() { }); it('issue 1414 - should not continue running timers after scope is destroyed', function() { - spyOn(scope, 'next').andCallThrough(); + spyOn(scope, 'next').and.callThrough(); scope.interval = 2000; scope.$digest(); $interval.flush(scope.interval); - expect(scope.next.calls.length).toBe(1); + expect(scope.next.calls.count()).toBe(1); scope.$destroy(); $interval.flush(scope.interval); - expect(scope.next.calls.length).toBe(1); + expect(scope.next.calls.count()).toBe(1); }); }); }); diff --git a/src/collapse/test/collapse.spec.js b/src/collapse/test/collapse.spec.js index 0efdd33..8ed51fb 100644 --- a/src/collapse/test/collapse.spec.js +++ b/src/collapse/test/collapse.spec.js @@ -107,4 +107,4 @@ describe('collapse directive', function () { }); }); -}); \ No newline at end of file +}); diff --git a/src/datepicker/test/datepicker.spec.js b/src/datepicker/test/datepicker.spec.js index 82b42ee..49e7838 100644 --- a/src/datepicker/test/datepicker.spec.js +++ b/src/datepicker/test/datepicker.spec.js @@ -942,20 +942,20 @@ describe('datepicker directive', function () { }); it('executes the dateDisabled expression for each visible day plus one for validation', function() { - expect($rootScope.dateDisabledHandler.calls.length).toEqual(42 + 1); + expect($rootScope.dateDisabledHandler.calls.count()).toEqual(42 + 1); }); it('executes the dateDisabled expression for each visible month plus one for validation', function() { - $rootScope.dateDisabledHandler.reset(); + $rootScope.dateDisabledHandler.calls.reset(); clickTitleButton(); - expect($rootScope.dateDisabledHandler.calls.length).toEqual(12 + 1); + expect($rootScope.dateDisabledHandler.calls.count()).toEqual(12 + 1); }); it('executes the dateDisabled expression for each visible year plus one for validation', function() { clickTitleButton(); - $rootScope.dateDisabledHandler.reset(); + $rootScope.dateDisabledHandler.calls.reset(); clickTitleButton(); - expect($rootScope.dateDisabledHandler.calls.length).toEqual(20 + 1); + expect($rootScope.dateDisabledHandler.calls.count()).toEqual(20 + 1); }); }); @@ -967,20 +967,20 @@ describe('datepicker directive', function () { }); it('executes the customClass expression for each visible day plus one for validation', function() { - expect($rootScope.customClassHandler.calls.length).toEqual(42); + expect($rootScope.customClassHandler.calls.count()).toEqual(42); }); it('executes the customClass expression for each visible month plus one for validation', function() { - $rootScope.customClassHandler.reset(); + $rootScope.customClassHandler.calls.reset(); clickTitleButton(); - expect($rootScope.customClassHandler.calls.length).toEqual(12); + expect($rootScope.customClassHandler.calls.count()).toEqual(12); }); it('executes the customClass expression for each visible year plus one for validation', function() { clickTitleButton(); - $rootScope.customClassHandler.reset(); + $rootScope.customClassHandler.calls.reset(); clickTitleButton(); - expect($rootScope.customClassHandler.calls.length).toEqual(20); + expect($rootScope.customClassHandler.calls.count()).toEqual(20); }); }); @@ -1316,13 +1316,13 @@ describe('datepicker directive', function () { expect(dropdownEl).toBeHidden(); expect(document.activeElement.tagName).toBe('INPUT'); }); - + it('stops the ESC key from propagating if the dropdown is open, but not when closed', function() { expect(dropdownEl).not.toBeHidden(); dropdownEl.find('button').eq(0).focus(); expect(document.activeElement.tagName).toBe('BUTTON'); - + var documentKey = -1; var getKey = function(evt) { documentKey = evt.which; }; $document.bind('keydown', getKey); @@ -1331,10 +1331,10 @@ describe('datepicker directive', function () { $rootScope.$digest(); expect(dropdownEl).toBeHidden(); expect(documentKey).toBe(-1); - + triggerKeyDown(inputEl, 'esc'); expect(documentKey).toBe(27); - + $document.unbind('keydown', getKey); }); }); @@ -1731,7 +1731,7 @@ describe('datepicker directive', function () { var $body = $document.find('body'), bodyLength = $body.children().length, elm = angular.element( - '
' + '
' ); $compile(elm)($rootScope); $rootScope.$digest(); @@ -1744,7 +1744,7 @@ describe('datepicker directive', function () { bodyLength = $body.children().length, isolatedScope = $rootScope.$new(), elm = angular.element( - '' + '' ); $compile(elm)(isolatedScope); isolatedScope.$digest(); diff --git a/src/modal/test/modal.spec.js b/src/modal/test/modal.spec.js index 2abf152..253e5ef 100644 --- a/src/modal/test/modal.spec.js +++ b/src/modal/test/modal.spec.js @@ -27,60 +27,107 @@ describe('$modal', function () { })); beforeEach(function () { - this.addMatchers({ + jasmine.addMatchers({ + toBeResolvedWith: function(util, customEqualityTesters) { + return { + compare: function(promise, expected) { + promise.then(function(result) { + expect(result).toEqual(expected); - toBeResolvedWith: function(value) { - var resolved; - this.message = function() { - return 'Expected "' + angular.mock.dump(resolved) + '" to be resolved with "' + value + '".'; + if (result === expected) { + result.message = 'Expected "' + angular.mock.dump(result) + '" not to be resolved with "' + expected + '".'; + } else { + result.message = 'Expected "' + angular.mock.dump(result) + '" to be resolved with "' + expected + '".'; + } + }); + + $rootScope.$digest(); + + return {pass: true}; + } }; - this.actual.then(function(result){ - resolved = result; - }); - $rootScope.$digest(); - - return resolved === value; }, + toBeRejectedWith: function(util, customEqualityTesters) { + return { + compare: function(promise, expected) { + var result = {}; - toBeRejectedWith: function(value) { - var rejected; - this.message = function() { - return 'Expected "' + angular.mock.dump(rejected) + '" to be rejected with "' + value + '".'; + promise.then(function() { + + }, function(result) { + expect(result).toEqual(expected); + + if (result === expected) { + result.message = 'Expected "' + angular.mock.dump(result) + '" not to be rejected with "' + expected + '".'; + } else { + result.message = 'Expected "' + angular.mock.dump(result) + '" to be rejected with "' + expected + '".'; + } + }); + + $rootScope.$digest(); + + return {pass: true}; + } }; - this.actual.then(angular.noop, function(reason){ - rejected = reason; - }); - $rootScope.$digest(); - - return rejected === value; }, + toHaveModalOpenWithContent: function(util, customEqualityTesters) { + return { + compare: function(actual, content, selector) { + var contentToCompare, modalDomEls = actual.find('body > div.modal > div.modal-dialog > div.modal-content'); - toHaveModalOpenWithContent: function(content, selector) { + contentToCompare = selector ? modalDomEls.find(selector) : modalDomEls; - var contentToCompare, modalDomEls = this.actual.find('body > div.modal > div.modal-dialog > div.modal-content'); + var result = { + pass: modalDomEls.css('display') === 'block' && contentToCompare.html() === content + }; - this.message = function() { - return '"Expected "' + angular.mock.dump(modalDomEls) + '" to be open with "' + content + '".'; + if (result.pass) { + result.message = '"Expected "' + angular.mock.dump(modalDomEls) + '" not to be open with "' + content + '".'; + } else { + result.message = '"Expected "' + angular.mock.dump(modalDomEls) + '" to be open with "' + content + '".'; + } + + return result; + } }; - - contentToCompare = selector ? modalDomEls.find(selector) : modalDomEls; - return modalDomEls.css('display') === 'block' && contentToCompare.html() == content; }, + toHaveModalsOpen: function(util, customEqualityTesters) { + return { + compare: function(actual, expected) { + var modalDomEls = actual.find('body > div.modal'); - toHaveModalsOpen: function(noOfModals) { + var result = { + pass: util.equals(modalDomEls.length, expected, customEqualityTesters) + }; - var modalDomEls = this.actual.find('body > div.modal'); - return modalDomEls.length === noOfModals; - }, + if (result.pass) { + result.message = 'Expected "' + angular.mock.dump(modalDomEls) + '" not to have "' + expected + '" modals opened.'; + } else { + result.message = 'Expected "' + angular.mock.dump(modalDomEls) + '" to have "' + expected + '" modals opened.'; + } - toHaveBackdrop: function() { - - var backdropDomEls = this.actual.find('body > div.modal-backdrop'); - this.message = function() { - return 'Expected "' + angular.mock.dump(backdropDomEls) + '" to be a backdrop element".'; + return result; + } }; + }, + toHaveBackdrop: function(util, customEqualityTesters) { + return { + compare: function(actual, expected) { + var backdropDomEls = actual.find('body > div.modal-backdrop'); - return backdropDomEls.length === 1; + var result = { + pass: util.equals(backdropDomEls.length, 1, customEqualityTesters) + }; + + if (result.pass) { + result.message = 'Expected "' + angular.mock.dump(backdropDomEls) + '" not to be a backdrop element".'; + } else { + result.message = 'Expected "' + angular.mock.dump(backdropDomEls) + '" to be a backdrop element".'; + } + + return result; + } + }; } }); }); diff --git a/src/position/test/position.spec.js b/src/position/test/position.spec.js index bf615d3..9604819 100644 --- a/src/position/test/position.spec.js +++ b/src/position/test/position.spec.js @@ -16,18 +16,28 @@ describe('position elements', function () { $position = _$position_; })); beforeEach(function () { - this.addMatchers({ - toBePositionedAt: function(top, left) { - this.message = function() { - return 'Expected "(' + this.actual.top + ', ' + this.actual.left + ')" to be positioned at (' + top + ', ' + left + ')'; - }; + jasmine.addMatchers({ + toBePositionedAt: function(util, customEqualityTesters) { + return { + compare: function(actual, top, left) { + var result = { + pass: util.equals(actual.top, top, customEqualityTesters) && + util.equals(actual.left, left, customEqualityTesters) + }; - return this.actual.top == top && this.actual.left == left; + if (result.pass) { + result.message = 'Expected "(' + actual.top + ', ' + actual.left + ')" not to be positioned at (' + top + ', ' + left + ')'; + } else { + result.message = 'Expected "(' + actual.top + ', ' + actual.left + ')" to be positioned at (' + top + ', ' + left + ')'; + } + + return result; + } + }; } }); }); - describe('append-to-body: false', function () { beforeEach(function () { @@ -96,4 +106,4 @@ describe('position elements', function () { }); }); -}); \ No newline at end of file +}); diff --git a/src/tabs/test/tabs.spec.js b/src/tabs/test/tabs.spec.js index d7c1f6d..d2b9b2f 100644 --- a/src/tabs/test/tabs.spec.js +++ b/src/tabs/test/tabs.spec.js @@ -596,7 +596,7 @@ describe('tabs', function() { angular.forEach(scope.tabs, function(tab, i) { if (activeTab === tab) { expect(tab.active).toBe(true); - expect(tab.select.callCount).toBe( (tab.disabled) ? 0 : 1 ); + expect(tab.select.calls.count()).toBe( (tab.disabled) ? 0 : 1 ); expect(_titles.eq(i)).toHaveClass('active'); expect(contents().eq(i).text().trim()).toBe('content ' + i); expect(contents().eq(i)).toHaveClass('active'); diff --git a/src/timepicker/test/timepicker.spec.js b/src/timepicker/test/timepicker.spec.js index 5f2d271..a58e552 100644 --- a/src/timepicker/test/timepicker.spec.js +++ b/src/timepicker/test/timepicker.spec.js @@ -961,7 +961,7 @@ describe('timepicker directive', function () { doClick(btn1, 2); doClick(btn2, 3); $rootScope.$digest(); - expect($rootScope.changeHandler.callCount).toBe(5); + expect($rootScope.changeHandler.calls.count()).toBe(5); }); it('should not be called when model changes programatically', function() { diff --git a/src/tooltip/test/tooltip.spec.js b/src/tooltip/test/tooltip.spec.js index ed6ea98..ec1a576 100644 --- a/src/tooltip/test/tooltip.spec.js +++ b/src/tooltip/test/tooltip.spec.js @@ -460,7 +460,7 @@ describe( 'tooltip positioning', function() { beforeEach(inject(function($rootScope, $compile, _$position_) { $position = _$position_; - spyOn($position, 'positionElements').andCallThrough(); + spyOn($position, 'positionElements').and.callThrough(); scope = $rootScope; scope.text = 'Some Text'; @@ -479,19 +479,19 @@ describe( 'tooltip positioning', function() { scope.$digest(); $timeout.flush(); - var startingPositionCalls = $position.positionElements.calls.length; + var startingPositionCalls = $position.positionElements.calls.count(); scope.$digest(); $timeout.flush(); - expect($position.positionElements.calls.length).toEqual(startingPositionCalls + 1); + expect($position.positionElements.calls.count()).toEqual(startingPositionCalls + 1); // Check that positionElements was called with elm - expect($position.positionElements.calls[startingPositionCalls].args[0][0]) + expect($position.positionElements.calls.argsFor(startingPositionCalls)[0][0]) .toBe(elm[0]); scope.$digest(); $timeout.flush(); - expect($position.positionElements.calls.length).toEqual(startingPositionCalls + 2); - expect($position.positionElements.calls[startingPositionCalls + 1].args[0][0]) + expect($position.positionElements.calls.count()).toEqual(startingPositionCalls + 2); + expect($position.positionElements.calls.argsFor(startingPositionCalls + 1)[0][0]) .toBe(elm[0]); scope.$digest(); })); diff --git a/src/tooltip/test/tooltip2.spec.js b/src/tooltip/test/tooltip2.spec.js index 2127a49..98f2a93 100644 --- a/src/tooltip/test/tooltip2.spec.js +++ b/src/tooltip/test/tooltip2.spec.js @@ -12,16 +12,26 @@ describe('tooltip directive', function () { })); beforeEach(function(){ - this.addMatchers({ - toHaveOpenTooltips: function(noOfOpened) { - var ttipElements = this.actual.find('div.tooltip'); - noOfOpened = noOfOpened || 1; + jasmine.addMatchers({ + toHaveOpenTooltips: function(util, customEqualityTesters) { + return { + compare: function(actual, noOfOpened) { + var ttipElements = actual.find('div.tooltip'); + noOfOpened = noOfOpened || 1; - this.message = function() { - return 'Expected "' + angular.mock.dump(ttipElements) + '" to have "' + ttipElements.length + '" opened tooltips.'; + var result = { + pass: util.equals(ttipElements.length, noOfOpened, customEqualityTesters) + }; + + if (result.message) { + result.message = 'Expected "' + angular.mock.dump(ttipElements) + '" not to have "' + ttipElements.length + '" opened tooltips.'; + } else { + result.message = 'Expected "' + angular.mock.dump(ttipElements) + '" to have "' + ttipElements.length + '" opened tooltips.'; + } + + return result; + } }; - - return ttipElements.length === noOfOpened; } }); }); diff --git a/src/transition/test/transition.spec.js b/src/transition/test/transition.spec.js index 34f744b..aafe1bf 100644 --- a/src/transition/test/transition.spec.js +++ b/src/transition/test/transition.spec.js @@ -62,7 +62,7 @@ describe('$transition', function() { beforeEach(function() { element = angular.element('
'); // Mock up the element.bind method - spyOn(element, 'bind').andCallFake(function(element, handler) { + spyOn(element, 'bind').and.callFake(function(element, handler) { // Store the handler to be used to simulate the end of the transition later triggerTransitionEnd = handler; }); diff --git a/src/typeahead/test/typeahead.spec.js b/src/typeahead/test/typeahead.spec.js index 6dbdf38..741621e 100644 --- a/src/typeahead/test/typeahead.spec.js +++ b/src/typeahead/test/typeahead.spec.js @@ -71,28 +71,48 @@ describe('typeahead tests', function () { //custom matchers beforeEach(function () { - this.addMatchers({ - toBeClosed: function () { - var typeaheadEl = findDropDown(this.actual); - this.message = function () { - return 'Expected "' + angular.mock.dump(typeaheadEl) + '" to be closed.'; + jasmine.addMatchers({ + toBeClosed: function(util, customEqualityTesters) { + return { + compare: function(actual, expected) { + var typeaheadEl = findDropDown(actual); + + var result = { + pass: util.equals(typeaheadEl.hasClass('ng-hide'), true, customEqualityTesters) + }; + + if (result.pass) { + result.message = 'Expected "' + angular.mock.dump(typeaheadEl) + '" not to be closed.'; + } else { + result.message = 'Expected "' + angular.mock.dump(typeaheadEl) + '" to be closed.'; + } + + return result; + } }; - return typeaheadEl.hasClass('ng-hide') === true; + }, + toBeOpenWithActive: function(util, customEqualityTesters) { + return { + compare: function(actual, noOfMatches, activeIdx) { + var typeaheadEl = findDropDown(actual); + var liEls = findMatches(actual); - }, toBeOpenWithActive: function (noOfMatches, activeIdx) { + var result = { + pass: util.equals(typeaheadEl.length, 1, customEqualityTesters) && + util.equals(typeaheadEl.hasClass('ng-hide'), false, customEqualityTesters) && + util.equals(liEls.length, noOfMatches, customEqualityTesters) && + activeIdx === -1 ? !$(liEls).hasClass('active') : $(liEls[activeIdx]).hasClass('active') + }; - var typeaheadEl = findDropDown(this.actual); - var liEls = findMatches(this.actual); + if (result.pass) { + result.message = 'Expected "' + actual + '" not to be opened.'; + } else { + result.message = 'Expected "' + actual + '" to be opened.'; + } - this.message = function () { - return 'Expected "' + this.actual + '" to be opened.'; + return result; + } }; - - return (typeaheadEl.length === 1 && - typeaheadEl.hasClass('ng-hide') === false && - liEls.length === noOfMatches && - (activeIdx === -1 ? !$(liEls).hasClass('active') : $(liEls[activeIdx]).hasClass('active')) - ); } }); }); @@ -614,21 +634,42 @@ describe('typeahead tests', function () { expect(values).not.toContain('match'); })); - it('does not close matches popup on click in input', function () { - var element = prepareInputEl('
'); - var inputEl = findInput(element); + describe('', function() { + // Dummy describe to be able to create an after hook for this tests + var element; - // Note that this bug can only be found when element is in the document - $document.find('body').append(element); - // Extra teardown for this spec - this.after(function () { element.remove(); }); + it('does not close matches popup on click in input', function () { + element = prepareInputEl('
'); + var inputEl = findInput(element); - changeInputValueTo(element, 'b'); + // Note that this bug can only be found when element is in the document + $document.find('body').append(element); - inputEl.click(); - $scope.$digest(); + changeInputValueTo(element, 'b'); - expect(element).toBeOpenWithActive(2, 0); + inputEl.click(); + $scope.$digest(); + + expect(element).toBeOpenWithActive(2, 0); + }); + + it('issue #1773 - should not trigger an error when used with ng-focus', function () { + element = prepareInputEl('
'); + var inputEl = findInput(element); + + // Note that this bug can only be found when element is in the document + $document.find('body').append(element); + + changeInputValueTo(element, 'b'); + var match = $(findMatches(element)[1]).find('a')[0]; + + $(match).click(); + $scope.$digest(); + }); + + afterEach(function() { + element.remove(); + }); }); it('issue #1238 - allow names like "query" to be used inside "in" expressions ', function () { @@ -643,23 +684,6 @@ describe('typeahead tests', function () { expect(element).toBeOpenWithActive(2, 0); }); - it('issue #1773 - should not trigger an error when used with ng-focus', function () { - - var element = prepareInputEl('
'); - var inputEl = findInput(element); - - // Note that this bug can only be found when element is in the document - $document.find('body').append(element); - // Extra teardown for this spec - this.after(function () { element.remove(); }); - - changeInputValueTo(element, 'b'); - var match = $(findMatches(element)[1]).find('a')[0]; - - $(match).click(); - $scope.$digest(); - }); - it('issue #3318 - should set model validity to true when set manually', function () { var element = prepareInputEl(