describe('Smooth Scroll', function () { // // Helper Methods // /** * Create a link element, add it to the body. * @public * @param {String} the href attribute of the new link * @param {Boolean} whether to add data-scroll to the link or not * @returns {Element} */ var injectElem = function (href, smooth) { var elt = document.createElement('a'); elt.href = href; if (smooth) { elt.setAttribute('data-scroll', true); } document.body.appendChild(elt); return elt; }; /** * Simulate a click event. * @public * @param {Element} the element to simulate a click on */ var simulateClick = function (elt) { var click = document.createEvent('MouseEvents'); click.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null); elt.dispatchEvent(click); }; // A pattern for settings to validate their format. var settingsStub = { speed: jasmine.any(Number), easing: jasmine.any(String), offset: jasmine.any(Number), updateURL: jasmine.any(Boolean), callback: jasmine.any(Function) }; // // Init // describe('Should initialize plugin', function () { it('Should export the smoothScroll module', function () { expect(smoothScroll).toBeDefined(); }); it('Should expose public functions', function () { expect(smoothScroll.init).toEqual(jasmine.any(Function)); expect(smoothScroll.destroy).toEqual(jasmine.any(Function)); expect(smoothScroll.animateScroll).toEqual(jasmine.any(Function)); }); it('Should add event listeners', function () { spyOn(document, 'addEventListener'); smoothScroll.init(); expect(document.addEventListener).toHaveBeenCalledWith('click', jasmine.any(Function), false); spyOn(document, 'removeEventListener'); smoothScroll.destroy(); expect(document.removeEventListener).toHaveBeenCalledWith('click', jasmine.any(Function), false); }); }); // // Events // describe('Should animate scroll when anchor clicked', function () { var elt = injectElem('#anchor', true); document.body.setAttribute('id', 'anchor'); afterEach(function () { smoothScroll.destroy(); }); it('Should trigger smooth scrolling on click', function () { spyOn(smoothScroll, 'animateScroll'); smoothScroll.init(); simulateClick(elt); expect(smoothScroll.animateScroll).toHaveBeenCalledWith(elt, '#anchor', jasmine.objectContaining(settingsStub)); }); it('Should do nothing if not initialized', function () { spyOn(smoothScroll, 'animateScroll'); simulateClick(elt); expect(smoothScroll.animateScroll).not.toHaveBeenCalled(); }); it('Should do nothing if destroyed', function () { spyOn(smoothScroll, 'animateScroll'); smoothScroll.init(); smoothScroll.destroy(); simulateClick(elt); expect(smoothScroll.animateScroll).not.toHaveBeenCalled(); }); }); describe('Should run callbacks', function () { var elt = injectElem('#anchor', true); document.body.setAttribute('id', 'anchor'); // Generates a callback to test asynchronous calls. var callback = function (eltVal, anchorVal, done) { return function (toggle, anchor) { expect(toggle).toBe(eltVal); expect(anchor).toBe(anchorVal); done(); }; }; afterEach(function () { smoothScroll.destroy(); }); it('Should run callback', function (done) { var settings = { callback: callback(elt, '#anchor', done) }; smoothScroll.init(settings); simulateClick(elt); }); }); });