@@ -5,6 +5,7 @@ import { DOCUMENT } from '@angular/platform-browser';
55import { ScrollService , topMargin } from './scroll.service' ;
66
77describe ( 'ScrollService' , ( ) => {
8+ const topOfPageElem = { } as Element ;
89 let injector : ReflectiveInjector ;
910 let document : MockDocument ;
1011 let location : MockPlatformLocation ;
@@ -16,7 +17,8 @@ describe('ScrollService', () => {
1617
1718 class MockDocument {
1819 body = new MockElement ( ) ;
19- getElementById = jasmine . createSpy ( 'Document getElementById' ) ;
20+ getElementById = jasmine . createSpy ( 'Document getElementById' ) . and . returnValue ( topOfPageElem ) ;
21+ querySelector = jasmine . createSpy ( 'Document querySelector' ) ;
2022 }
2123
2224 class MockElement {
@@ -38,6 +40,69 @@ describe('ScrollService', () => {
3840 scrollService = injector . get ( ScrollService ) ;
3941 } ) ;
4042
43+ describe ( '#topOffset' , ( ) => {
44+ it ( 'should query for the top-bar by CSS selector' , ( ) => {
45+ expect ( document . querySelector ) . not . toHaveBeenCalled ( ) ;
46+
47+ expect ( scrollService . topOffset ) . toBe ( topMargin ) ;
48+ expect ( document . querySelector ) . toHaveBeenCalled ( ) ;
49+ } ) ;
50+
51+ it ( 'should be calculated based on the top-bar\'s height + margin' , ( ) => {
52+ ( document . querySelector as jasmine . Spy ) . and . returnValue ( { clientHeight : 50 } ) ;
53+ expect ( scrollService . topOffset ) . toBe ( 50 + topMargin ) ;
54+ } ) ;
55+
56+ it ( 'should only query for the top-bar once' , ( ) => {
57+ expect ( scrollService . topOffset ) . toBe ( topMargin ) ;
58+ ( document . querySelector as jasmine . Spy ) . calls . reset ( ) ;
59+
60+ expect ( scrollService . topOffset ) . toBe ( topMargin ) ;
61+ expect ( document . querySelector ) . not . toHaveBeenCalled ( ) ;
62+ } ) ;
63+
64+ it ( 'should retrieve the top-bar\'s height again after resize' , ( ) => {
65+ let clientHeight = 50 ;
66+ ( document . querySelector as jasmine . Spy ) . and . callFake ( ( ) => ( { clientHeight} ) ) ;
67+
68+ expect ( scrollService . topOffset ) . toBe ( 50 + topMargin ) ;
69+ expect ( document . querySelector ) . toHaveBeenCalled ( ) ;
70+
71+ ( document . querySelector as jasmine . Spy ) . calls . reset ( ) ;
72+ clientHeight = 100 ;
73+
74+ expect ( scrollService . topOffset ) . toBe ( 50 + topMargin ) ;
75+ expect ( document . querySelector ) . not . toHaveBeenCalled ( ) ;
76+
77+ window . dispatchEvent ( new Event ( 'resize' ) ) ;
78+
79+ expect ( scrollService . topOffset ) . toBe ( 100 + topMargin ) ;
80+ expect ( document . querySelector ) . toHaveBeenCalled ( ) ;
81+ } ) ;
82+ } ) ;
83+
84+ describe ( '#topOfPageElement' , ( ) => {
85+ it ( 'should query for the top-of-page element by ID' , ( ) => {
86+ expect ( document . getElementById ) . not . toHaveBeenCalled ( ) ;
87+
88+ expect ( scrollService . topOfPageElement ) . toBe ( topOfPageElem ) ;
89+ expect ( document . getElementById ) . toHaveBeenCalled ( ) ;
90+ } ) ;
91+
92+ it ( 'should only query for the top-of-page element once' , ( ) => {
93+ expect ( scrollService . topOfPageElement ) . toBe ( topOfPageElem ) ;
94+ ( document . getElementById as jasmine . Spy ) . calls . reset ( ) ;
95+
96+ expect ( scrollService . topOfPageElement ) . toBe ( topOfPageElem ) ;
97+ expect ( document . getElementById ) . not . toHaveBeenCalled ( ) ;
98+ } ) ;
99+
100+ it ( 'should return `<body>` if unable to find the top-of-page element' , ( ) => {
101+ ( document . getElementById as jasmine . Spy ) . and . returnValue ( null ) ;
102+ expect ( scrollService . topOfPageElement ) . toBe ( document . body as any ) ;
103+ } ) ;
104+ } ) ;
105+
41106 describe ( '#scroll' , ( ) => {
42107 it ( 'should scroll to the top if there is no hash' , ( ) => {
43108 location . hash = '' ;
@@ -73,10 +138,28 @@ describe('ScrollService', () => {
73138
74139 describe ( '#scrollToElement' , ( ) => {
75140 it ( 'should scroll to element' , ( ) => {
76- const element = < Element > < any > new MockElement ( ) ;
141+ const element : Element = new MockElement ( ) as any ;
77142 scrollService . scrollToElement ( element ) ;
78143 expect ( element . scrollIntoView ) . toHaveBeenCalled ( ) ;
79- expect ( window . scrollBy ) . toHaveBeenCalledWith ( 0 , - topMargin ) ;
144+ expect ( window . scrollBy ) . toHaveBeenCalledWith ( 0 , - scrollService . topOffset ) ;
145+ } ) ;
146+
147+ it ( 'should scroll all the way to the top if close enough' , ( ) => {
148+ const element : Element = new MockElement ( ) as any ;
149+
150+ ( window as any ) . pageYOffset = 25 ;
151+ scrollService . scrollToElement ( element ) ;
152+
153+ expect ( element . scrollIntoView ) . toHaveBeenCalled ( ) ;
154+ expect ( window . scrollBy ) . toHaveBeenCalledWith ( 0 , - scrollService . topOffset ) ;
155+ ( window . scrollBy as jasmine . Spy ) . calls . reset ( ) ;
156+
157+ ( window as any ) . pageYOffset = 15 ;
158+ scrollService . scrollToElement ( element ) ;
159+
160+ expect ( element . scrollIntoView ) . toHaveBeenCalled ( ) ;
161+ expect ( window . scrollBy ) . toHaveBeenCalledWith ( 0 , - scrollService . topOffset ) ;
162+ expect ( window . scrollBy ) . toHaveBeenCalledWith ( 0 , - 15 ) ;
80163 } ) ;
81164
82165 it ( 'should do nothing if no element' , ( ) => {
0 commit comments