UNPKG

angular-snapscroll

Version:

Vertical scroll-and-snap functionality in angular

1,487 lines (1,414 loc) 169 kB
describe('Directive: snapscroll', function () { var $compile, $scope, scrollMock = {}, defaultSnapscrollScrollEasingMock = jasmine.createSpy('easing'); beforeEach(module('snapscroll')); beforeEach(module(function ($provide) { $provide.value('scrollie', scrollMock); $provide.value('defaultSnapscrollScrollEasing', defaultSnapscrollScrollEasingMock); })); beforeEach(inject(function (_$compile_, _$rootScope_) { $compile = _$compile_; $scope = _$rootScope_.$new(); })); afterEach(function () { angular.element(document).find('body').empty(); }); function compileElement(html, appendToBody) { var body, element = angular.element(html); if (!angular.isDefined(appendToBody)) { appendToBody = false; } if (appendToBody) { body = angular.element(document).find('body'); body.append(element); } element = $compile(element)($scope); $scope.$digest(); return element; } function testBeforeSnap(html) { var test = 0; $scope.beforeSnap = function () { test = 1; }; compileElement(html, true); $scope.snapIndex = 1; $scope.$apply(); expect(test).toBe(1); } function testExecutesBeforeSnapOnInitialSnap(html) { var test = 0; $scope.beforeSnap = function () { test = 1; }; compileElement(html, true); expect(test).toBe(1); } function testCorrectSnapIndexPassedToBeforeSnap(html) { var spy = jasmine.createSpy('beforeSnap'); $scope.snapIndex = 0; $scope.beforeSnap = spy; compileElement(html, true); $scope.snapIndex = 1; $scope.$apply(); var calls = spy.calls.all(); expect(calls[0].args).toEqual([0]); expect(calls[1].args).toEqual([1]); } function testAllowsPreventingSnapping(html) { var prevent, test = 0; $scope.beforeSnap = function () { if (prevent) { return false; } test += 1; }; expect(test).toBe(0); compileElement(html, true); expect(test).toBe(1); $scope.$apply(function () { $scope.snapIndex = 1; }); expect(test).toBe(2); prevent = true; $scope.$apply(function () { $scope.snapIndex = 0; }); expect($scope.snapIndex).toBe(1); expect(test).toBe(2); } function testAllowsSnappingToADifferentSnapIndex(html) { var snapIndexOverride; $scope.beforeSnap = function () { if (snapIndexOverride) { return snapIndexOverride; } }; compileElement(html, true); expect($scope.snapIndex).toBe(0); snapIndexOverride = 2; $scope.$apply(function () { $scope.snapIndex = 1; }); expect($scope.snapIndex).toBe(2); } function testIgnoresSnapIndexOverrideIfNotANumber(html) { var snapIndexOverride; $scope.beforeSnap = function () { if (snapIndexOverride !== undefined) { return snapIndexOverride; } }; compileElement(html, true); expect($scope.snapIndex).toBe(0); snapIndexOverride = 'meh'; $scope.$apply(function () { $scope.snapIndex = 1; }); snapIndexOverride = NaN; $scope.$apply(function () { $scope.snapIndex = 0; }); expect($scope.snapIndex).toBe(0); } function testIgnoresInvalidSnapIndexOverride(html) { var snapIndexOverride; $scope.beforeSnap = function () { if (snapIndexOverride) { return snapIndexOverride; } }; compileElement(html, true); expect($scope.snapIndex).toBe(0); snapIndexOverride = 10; $scope.$apply(function () { $scope.snapIndex = 1; }); expect($scope.snapIndex).toBe(1); } function testResetsSnapIndexIfSnappingPrevented(html) { var prevent = false; $scope.beforeSnap = function () { if (prevent) { return false; } }; compileElement(html, true); $scope.snapIndex = 1; $scope.$apply(); expect($scope.snapIndex).toBe(1); prevent = true; $scope.snapIndex = 2; $scope.$apply(); expect($scope.snapIndex).toBe(1); } function testAfterSnap(html) { var test = 0; $scope.afterSnap = function () { test = 1; }; compileElement(html, true); $scope.snapIndex = 1; $scope.$apply(); expect(test).toBe(1); } function testExecutesAfterSnapOnInitialSnap(html) { var test = 0; $scope.afterSnap = function () { test = 1; }; compileElement(html, true); expect(test).toBe(1); } function testCorrectSnapIndexPassedToAfterSnap(html) { var spy = jasmine.createSpy('afterSnap'); $scope.snapIndex = 0; $scope.afterSnap = spy; compileElement(html, true); $scope.snapIndex = 1; $scope.$apply(); var calls = spy.calls.all(); expect(calls[0].args).toEqual([0]); expect(calls[1].args).toEqual([1]); } function triggerThreeMousewheelEvents(element, preventDefault) { element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120, preventDefault: preventDefault }); // mousewheel down element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120, preventDefault: preventDefault }); // mousewheel up element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120, preventDefault: preventDefault }); // mousewheel down } function testPreventsNormalScrollingUsingMousewheel(html) { var element, preventDefault = jasmine.createSpy('preventDefault'); element = compileElement(html, true); triggerThreeMousewheelEvents(element, preventDefault); expect(preventDefault).toHaveBeenCalled(); expect(preventDefault.calls.count()).toBe(3); } function testAllowsNormalScrollingUsingMousewheelWhenDisabled(html) { var element, preventDefault = jasmine.createSpy('preventDefault'); element = compileElement(html, true); triggerThreeMousewheelEvents(element, preventDefault); expect(preventDefault).not.toHaveBeenCalled(); } function testPreventsNormalScrollingUsingMousewheelWhenReEnabled(html) { var element, preventDefault = jasmine.createSpy('preventDefault'); $scope.enabled = false; element = compileElement(html, true); triggerThreeMousewheelEvents(element, preventDefault); expect(preventDefault).not.toHaveBeenCalled(); $scope.$apply(function () { $scope.enabled = true; }); triggerThreeMousewheelEvents(element, preventDefault); expect(preventDefault).toHaveBeenCalled(); expect(preventDefault.calls.count()).toBe(3); } function testPreventsBubblingUpOfMousewheelEventsIfElementIsStillScrollable(html) { var stopPropagation = jasmine.createSpy('stopPropagation'); var element = compileElement(html, true); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120, stopPropagation: stopPropagation }); // try to snap up expect(stopPropagation).not.toHaveBeenCalled(); $scope.$apply(function () { $scope.index = 2; }); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120, stopPropagation: stopPropagation }); // try to snap down expect(stopPropagation).not.toHaveBeenCalled(); $scope.$apply(function () { $scope.index = 1; }); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120, stopPropagation: stopPropagation }); // try to snap up element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120, stopPropagation: stopPropagation }); // then down expect(stopPropagation).toHaveBeenCalled(); expect(stopPropagation.calls.count()).toBe(2); } function testSnapsDownOnMousewheelDown(html, $timeout) { var element; element = compileElement(html, true); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(50); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(2); expect(element[0].scrollTop).toBe(100); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(3); expect(element[0].scrollTop).toBe(150); } function testDoesntSnapDownIfElementIsNotScrollable(html) { var element; element = compileElement(html, true); expect($scope.index).toBeUndefined(); expect(element[0].scrollTop).toBe(0); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBeUndefined(); expect(element[0].scrollTop).toBe(0); } function testSnapsUpOnMousewheelUp(html, $timeout) { var element; $scope.index = 3; element = compileElement(html, true); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(2); expect(element[0].scrollTop).toBe(100); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(50); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(0); expect(element[0].scrollTop).toBe(0); } function testDoesntSnapUpIfElementIsNotScrollable(html) { var element; element = compileElement(html, true); expect($scope.index).toBeUndefined(); expect(element[0].scrollTop).toBe(0); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBeUndefined(); expect(element[0].scrollTop).toBe(0); } function testExecutesBeforeSnapOnMousewheelDown(html, $timeout) { var spy = jasmine.createSpy('beforeSnap'); $scope.beforeSnap = spy; var element = compileElement(html, true); expect(spy).toHaveBeenCalledWith(0); // initial snap spy.calls.reset(); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).toHaveBeenCalledWith(1); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).not.toHaveBeenCalled(); // index still 1 spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).not.toHaveBeenCalled(); // index still 1 spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).toHaveBeenCalledWith(2); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).toHaveBeenCalledWith(3); spy.calls.reset(); } function testCallsBeforeSnapOnMousewheelDownWithWheelEvent(html, $timeout) { var spy = jasmine.createSpy('beforeSnap'); $scope.beforeSnap = spy; var element = compileElement(html, true); expect(spy).toHaveBeenCalledWith(0, undefined); // initial snap spy.calls.reset(); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).toHaveBeenCalledWith(1, jasmine.objectContaining({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 })); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).not.toHaveBeenCalled(); // index still 1 spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).not.toHaveBeenCalled(); // index still 1 spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).toHaveBeenCalledWith(2, jasmine.objectContaining({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 })); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).toHaveBeenCalledWith(3, jasmine.objectContaining({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 })); spy.calls.reset(); } function testCallsAfterSnapOnMousewheelDownWithWheelEvent(html, $timeout) { var spy = jasmine.createSpy('afterSnap'); $scope.afterSnap = spy; var element = compileElement(html, true); expect(spy).toHaveBeenCalledWith(0, undefined); // initial snap spy.calls.reset(); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).toHaveBeenCalledWith(1, jasmine.objectContaining({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 })); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).not.toHaveBeenCalled(); // index still 1 spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).not.toHaveBeenCalled(); // index still 1 spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).toHaveBeenCalledWith(2, jasmine.objectContaining({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 })); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).toHaveBeenCalledWith(3, jasmine.objectContaining({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 })); spy.calls.reset(); } function testCallsBeforeSnapOnMousewheelDownWithWheelEventOnlyWhenAvailable(html, $timeout) { var spy = jasmine.createSpy('beforeSnap'); $scope.beforeSnap = spy; var element = compileElement(html, true); expect(spy).toHaveBeenCalledWith(0, undefined); // initial snap spy.calls.reset(); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).toHaveBeenCalledWith(1, jasmine.objectContaining({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 })); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown $scope.$apply(function () { $scope.index = 2; }); expect(spy).toHaveBeenCalledWith(2, undefined); } function testCallsAfterSnapOnMousewheelDownWithWheelEventOnlyWhenAvailable(html, $timeout) { var spy = jasmine.createSpy('afterSnap'); $scope.afterSnap = spy; var element = compileElement(html, true); expect(spy).toHaveBeenCalledWith(0, undefined); // initial snap spy.calls.reset(); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).toHaveBeenCalledWith(1, jasmine.objectContaining({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 })); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown $scope.$apply(function () { $scope.index = 2; }); expect(spy).toHaveBeenCalledWith(2, undefined); } function testExecutesBeforeSnapOnMousewheelUp(html, $timeout) { var spy = jasmine.createSpy('beforeSnap'); $scope.beforeSnap = spy; $scope.index = 3; var element = compileElement(html, true); expect(spy).toHaveBeenCalledWith(3); // initial snap spy.calls.reset(); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).toHaveBeenCalledWith(2); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).toHaveBeenCalledWith(1); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).not.toHaveBeenCalled(); // index still 1 spy.calls.reset(); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).not.toHaveBeenCalled(); // index still 1 spy.calls.reset(); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).toHaveBeenCalledWith(0); spy.calls.reset(); } function testCallsBeforeSnapOnMousewheelUpWithWheelEvent(html, $timeout) { var spy = jasmine.createSpy('beforeSnap'); $scope.beforeSnap = spy; $scope.index = 3; var element = compileElement(html, true); expect(spy).toHaveBeenCalledWith(3, undefined); // initial snap spy.calls.reset(); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).toHaveBeenCalledWith(2, jasmine.objectContaining({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 })); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).toHaveBeenCalledWith(1, jasmine.objectContaining({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 })); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).not.toHaveBeenCalled(); // index still 1 spy.calls.reset(); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).not.toHaveBeenCalled(); // index still 1 spy.calls.reset(); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).toHaveBeenCalledWith(0, jasmine.objectContaining({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 })); spy.calls.reset(); } function testCallsAfterSnapOnMousewheelUpWithWheelEvent(html, $timeout) { var spy = jasmine.createSpy('afterSnap'); $scope.afterSnap = spy; $scope.index = 3; var element = compileElement(html, true); expect(spy).toHaveBeenCalledWith(3, undefined); // initial snap spy.calls.reset(); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).toHaveBeenCalledWith(2, jasmine.objectContaining({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 })); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).toHaveBeenCalledWith(1, jasmine.objectContaining({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 })); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).not.toHaveBeenCalled(); // index still 1 spy.calls.reset(); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).not.toHaveBeenCalled(); // index still 1 spy.calls.reset(); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).toHaveBeenCalledWith(0, jasmine.objectContaining({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 })); spy.calls.reset(); } function testCallsBeforeSnapOnMousewheelUpWithWheelEventOnlyWhenAvailable(html, $timeout) { var spy = jasmine.createSpy('beforeSnap'); $scope.beforeSnap = spy; $scope.index = 3; var element = compileElement(html, true); expect(spy).toHaveBeenCalledWith(3, undefined); // initial snap spy.calls.reset(); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).toHaveBeenCalledWith(2, jasmine.objectContaining({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 })); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown $scope.$apply(function () { $scope.index = 1; }); expect(spy).toHaveBeenCalledWith(1, undefined); } function testCallsAfterSnapOnMousewheelUpWithWheelEventOnlyWhenAvailable(html, $timeout) { var spy = jasmine.createSpy('afterSnap'); $scope.afterSnap = spy; $scope.index = 3; var element = compileElement(html, true); expect(spy).toHaveBeenCalledWith(3, undefined); // initial snap spy.calls.reset(); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).toHaveBeenCalledWith(2, jasmine.objectContaining({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 })); spy.calls.reset(); $timeout.flush(); // flush the timeout on preventDown $scope.$apply(function () { $scope.index = 1; }); expect(spy).toHaveBeenCalledWith(1, undefined); } function testDoesNotSnapDownIfBeforeSnapReturnsFalseOnMousewheelDown(html) { var spy = jasmine.createSpy('beforeSnap').and.callFake(function (snapIndex) { if (snapIndex === 1) { return false; } }); $scope.beforeSnap = spy; var element = compileElement(html, true); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).toHaveBeenCalledWith(1); expect($scope.index).toBe(0); } function testDoesNotSnapUpIfBeforeSnapReturnsFalseOnMousewheelUp(html) { var spy = jasmine.createSpy('beforeSnap').and.callFake(function (snapIndex) { if (snapIndex === 2) { return false; } }); $scope.beforeSnap = spy; $scope.index = 3; var element = compileElement(html, true); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).toHaveBeenCalledWith(2); expect($scope.index).toBe(3); } function testSnapsToADifferentSnapIndexIfBeforeSnapReturnsNumberOnMousewheelDown(html) { var spy = jasmine.createSpy('beforeSnap').and.callFake(function (snapIndex) { if (snapIndex === 1) { return 2; } }); $scope.beforeSnap = spy; var element = compileElement(html, true); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect(spy).toHaveBeenCalledWith(1); expect($scope.index).toBe(2); } function testSnapsToADifferentSnapIndexIfBeforeSnapReturnsNumberOnMousewheelUp(html) { var spy = jasmine.createSpy('beforeSnap').and.callFake(function (snapIndex) { if (snapIndex === 2) { return 1; } }); $scope.beforeSnap = spy; $scope.index = 3; var element = compileElement(html, true); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect(spy).toHaveBeenCalledWith(2); expect($scope.index).toBe(1); } function testShowsRestOfBigSnapOnMousewheelDown(html, $timeout) { var element; element = compileElement(html, true); expect($scope.index).toBe(0); expect(element[0].scrollTop).toBe(0); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(50); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(100); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(125); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(2); expect(element[0].scrollTop).toBe(175); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(3); expect(element[0].scrollTop).toBe(225); } function testShowsRestOfBigSnapOnMousewheelUp(html, $timeout) { var element; $scope.index = 3; element = compileElement(html, true); expect($scope.index).toBe(3); expect(element[0].scrollTop).toBe(225); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(2); expect(element[0].scrollTop).toBe(175); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(125); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(75); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(50); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(0); expect(element[0].scrollTop).toBe(0); } function testDoesntSnapDownOnNewDownMousewheelIfAlreadyScrolledToBottom(html) { var element; $scope.index = 3; element = compileElement(html, true); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(3); expect(element[0].scrollTop).toBe(150); // try to wheel up then.. element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(2); expect(element[0].scrollTop).toBe(100); } function testDoesntSnapUpOnNewDownMousewheelIfAlreadyScrolltopIsZero(html) { var element; element = compileElement(html, true); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(0); expect(element[0].scrollTop).toBe(0); // try to wheel down then.. element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(50); } function testDoesntSnapDownIfBiggerHeightChildIsScrolledToTheEnd(html, $timeout) { var element; element = compileElement(html, true); expect($scope.index).toBe(0); expect(element[0].scrollTop).toBe(0); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(50); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(100); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(125); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(125); } function testDoesntSnapDownIfBiggerHeightChildIsScrolledToTheBeginning(html, $timeout) { var element; $scope.index = 1; element = compileElement(html, true); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(125); element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(0); expect(element[0].scrollTop).toBe(75); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(0); expect(element[0].scrollTop).toBe(25); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(0); expect(element[0].scrollTop).toBe(0); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', wheelDelta: 120, detail: -120, deltaY: -120 }); expect($scope.index).toBe(0); expect(element[0].scrollTop).toBe(0); } function testStopsListeningToMousewheelWhenScopeIsDestroyed(html) { var element; element = compileElement(html, true); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(50); $scope.$destroy(); element.triggerHandler({ type: 'wheel', wheelDelta: -120, detail: 120, deltaY: 120 }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(50); } function testUsesTheOriginalBrowserMousewheelEvents(html, $timeout) { var element; $scope.index = 3; element = compileElement(html, true); element.triggerHandler({ type: 'wheel', originalEvent: { wheelDelta: 120, detail: -120, deltaY: -120, preventDefault: angular.noop, stopPropagation: angular.noop } }); expect($scope.index).toBe(2); expect(element[0].scrollTop).toBe(100); $timeout.flush(); // flush the timeout on preventDown element.triggerHandler({ type: 'wheel', originalEvent: { wheelDelta: 120, detail: -120, deltaY: -120, preventDefault: angular.noop, stopPropagation: angular.noop } }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(50); $timeout.flush(); // flush the timeout on preventUp element.triggerHandler({ type: 'wheel', originalEvent: { wheelDelta: 120, detail: -120, deltaY: -120, preventDefault: angular.noop, stopPropagation: angular.noop } }); expect($scope.index).toBe(0); expect(element[0].scrollTop).toBe(0); } describe('as an attribute', function () { beforeEach(function () { var failureCallback; scrollMock.to = jasmine.createSpy('scroll.to').and.callFake(function (element, top) { element[0].scrollTop = top; return { then: function (success, error) { failureCallback = error; if (angular.isFunction(success)) { success(); } return this; } }; }); scrollMock.stop = jasmine.createSpy('scroll.stop').and.callFake(function () { if (angular.isFunction(failureCallback)) { failureCallback(); } }); }); it('can be declared as an attribute', function () { expect(function () { compileElement('<div snapscroll=""></div>'); }).not.toThrow(); }); it('sets overflow-y on the element to auto if it\'s not set', function () { var element = compileElement('<div snapscroll=""></div>'); expect(element.css('overflowY')).toBe('auto'); }); it('changes overflow-y to auto if it\'s set to visible', function () { var element = compileElement('<div snapscroll="" style="overflow-y: visible;"></div>'); expect(element.css('overflowY')).toBe('auto'); }); it('changes overflow-y to auto if it\'s set to hidden', function () { var element = compileElement('<div snapscroll="" style="overflow-y: hidden;"></div>'); expect(element.css('overflowY')).toBe('auto'); }); it('does not change overflow-y if it\'s set to scroll', function () { var element = compileElement('<div snapscroll="" style="overflow-y: scroll;"></div>'); expect(element.css('overflowY')).toBe('scroll'); }); it('does not set overflow-y to auto if overflow is set to scroll', function () { var element = compileElement('<div snapscroll="" style="overflow: scroll;"></div>'); expect(element.css('overflowY')).toBe('scroll'); }); it('defaults snapIndex to zero', function () { var html = [ '<div snapscroll="" snap-index="snapIndex" style="height: 50px; overflow: auto">', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '</div>' ].join(''); compileElement(html, true); expect($scope.snapIndex).toBe(0); }); it('does not update snapIndex if the element\'s height is 0', function () { var html = [ '<div snapscroll="" snap-index="snapIndex" style="height: 0; overflow: auto">', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '</div>' ].join(''); compileElement(html, true); expect($scope.snapIndex).toBeUndefined(); }); it('does not update snapIndex if the element has no children', function () { var html = [ '<div snapscroll="" snap-index="snapIndex" style="height: 50px; overflow: auto">', '</div>' ].join(''); compileElement(html, true); expect($scope.snapIndex).toBeUndefined(); }); it('does not update snapIndex if the element\'s children\'s combined height is less than the element\'s height', function () { var html = [ '<div snapscroll="" snap-index="snapIndex" style="height: 50px; overflow: auto">', '<div style="height: 10px"></div>', '<div style="height: 10px"></div>', '<div style="height: 10px"></div>', '</div>' ].join(''); compileElement(html, true); expect($scope.snapIndex).toBeUndefined(); }); it('updates the snapIndex if the element\'s children\'s combined height is greater than the element\'s height', function () { var html = [ '<div snapscroll="" snap-index="snapIndex" style="height: 50px; overflow: auto">', '<div style="height: 10px"></div>', '<div style="height: 60px"></div>', '</div>' ].join(''); compileElement(html, true); expect($scope.snapIndex).toBe(0); }); it('converts a snapIndex to a scrollTop (simple)', function () { var element = compileElement('<div snapscroll=""></div>'); expect(element[0].scrollTop).toBe(0); }); it('converts a snapIndex to a scrollTop (functional)', function () { var element, html = [ '<div snapscroll="" snap-index="index" style="height: 50px; overflow: auto">', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '</div>' ].join(''); $scope.index = 1; element = compileElement(html, true); expect(element[0].scrollTop).toBe(50); }); it('doesn\'t snap to a snapIndex less than zero', function () { var element, html = [ '<div snapscroll="" snap-index="index" style="height: 50px; overflow: auto">', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '</div>' ].join(''); $scope.index = 1; element = compileElement(html, true); $scope.$apply(function () { $scope.index = -1; }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(50); }); it('doesn\'t snap to a snapIndex greater than the number of available snaps (i.e. total - 1 since snapIndex is zero-based)', function () { var element, html = [ '<div snapscroll="" snap-index="index" style="height: 50px; overflow: auto">', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '</div>' ].join(''); $scope.index = 1; element = compileElement(html, true); $scope.$apply(function () { $scope.index = 3; }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(50); }); it('casts any non-integer snapIndex to its nearest integer value', function () { var element, html = [ '<div snapscroll="" snap-index="index" style="height: 50px; overflow: auto">', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '</div>' ].join(''); $scope.index = 0.0000005; element = compileElement(html, true); expect($scope.index).toBe(0); expect(element[0].scrollTop).toBe(0); $scope.$apply(function () { $scope.index = 1.499995; }); expect($scope.index).toBe(1); expect(element[0].scrollTop).toBe(50); $scope.$apply(function () { $scope.index = 1.5; }); expect($scope.index).toBe(2); expect(element[0].scrollTop).toBe(100); }); it('doesn\'t fire before and afterSnap callbacks while resetting the scrollTop unless snapIndex is changed', inject(function ($timeout) { var element, test = 0, html = [ '<div snapscroll="" snap-index="index" after-snap="afterSnap()" style="height: 50px; overflow: auto">', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '</div>' ].join(''); $scope.afterSnap = function () { test += 1; }; element = compileElement(html, true); expect($scope.index).toBe(0); expect(test).toBe(1); element[0].scrollTop = 24; element.triggerHandler('scroll'); $timeout.flush(); expect($scope.index).toBe(0); expect(test).toBe(1); })); it('allows setting an initial snapIndex as an integer', function () { var element, html = [ '<div snapscroll="" snap-index="1" style="height: 50px; overflow: auto">', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '</div>' ].join(''); element = compileElement(html, true); expect(element[0].scrollTop).toBe(50); }); it('allows setting an initial snapIndex using an expression', function () { var element, html = [ '<div snapscroll="" snap-index="1 + 1" style="height: 50px; overflow: auto">', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '</div>' ].join(''); element = compileElement(html, true); expect(element[0].scrollTop).toBe(100); }); it('allows setting an initial snapIndex using an angular expression', function () { var element, html = [ '<div snapscroll="" snap-index="index + 1" style="height: 50px; overflow: auto">', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '<div style="height: 50px"></div>', '