@@ -12,6 +12,50 @@ function createManager() {
1212 return manager ;
1313}
1414
15+ const basicParameterState = {
16+ filters : [
17+ {
18+ dependencies : [ "underscore" , "another" ]
19+ } ,
20+ {
21+ keywords : [ "node" ]
22+ }
23+ ] ,
24+ resultsPerPage : 20 ,
25+ searchTerm : "node" ,
26+ sortDirection : "asc" ,
27+ sortField : "name"
28+ } ;
29+
30+ const basicParameterStateAsUrl =
31+ "?fv-dependencies=underscore&fv-dependencies=another&fv-keywords=node&q=node&size=20&sort-direction=asc&sort-field=name" ;
32+
33+ const parameterStateWithRangeFilters = {
34+ filters : [
35+ {
36+ date : [
37+ {
38+ from : 12 ,
39+ to : 4000
40+ } ,
41+ {
42+ to : 4000
43+ }
44+ ]
45+ } ,
46+ {
47+ cost : [
48+ {
49+ from : 50
50+ }
51+ ]
52+ } ,
53+ {
54+ keywords : "node"
55+ }
56+ ]
57+ } ;
58+
1559it ( "can be initialized" , ( ) => {
1660 const manager = new URLManager ( ) ;
1761 expect ( manager ) . toBeInstanceOf ( URLManager ) ;
@@ -58,20 +102,7 @@ describe("#getStateFromURL", () => {
58102describe ( "#pushStateToURL" , ( ) => {
59103 it ( "will update the url with the url corresponding to the provided state" , ( ) => {
60104 const manager = createManager ( ) ;
61- manager . pushStateToURL ( {
62- filters : [
63- {
64- dependencies : [ "underscore" , "another" ]
65- } ,
66- {
67- keywords : [ "node" ]
68- }
69- ] ,
70- resultsPerPage : 20 ,
71- searchTerm : "node" ,
72- sortDirection : "asc" ,
73- sortField : "name"
74- } ) ;
105+ manager . pushStateToURL ( basicParameterState ) ;
75106 const queryString = manager . history . push . mock . calls [ 0 ] [ 0 ] . search ;
76107 expect ( queryString ) . toEqual (
77108 "?fv-dependencies=underscore&fv-dependencies=another&fv-keywords=node&q=node&size=20&sort-field=name&sort-direction=asc"
@@ -80,31 +111,7 @@ describe("#pushStateToURL", () => {
80111
81112 it ( "will update the url with range filter types" , ( ) => {
82113 const manager = createManager ( ) ;
83- manager . pushStateToURL ( {
84- filters : [
85- {
86- date : [
87- {
88- from : 12 ,
89- to : 4000
90- } ,
91- {
92- to : 4000
93- }
94- ]
95- } ,
96- {
97- cost : [
98- {
99- from : 50
100- }
101- ]
102- } ,
103- {
104- keywords : "node"
105- }
106- ]
107- } ) ;
114+ manager . pushStateToURL ( parameterStateWithRangeFilters ) ;
108115 const queryString = manager . history . push . mock . calls [ 0 ] [ 0 ] . search ;
109116 expect ( queryString ) . toEqual (
110117 "?fr-date=12_4000&fr-date=_4000&fr-cost=50_&fv-keywords=node"
@@ -113,20 +120,94 @@ describe("#pushStateToURL", () => {
113120} ) ;
114121
115122describe ( "#onURLStateChange" , ( ) => {
123+ let manager ;
124+
125+ function setup ( ) {
126+ manager = createManager ( ) ;
127+ }
128+
129+ function pushStateToURL ( state ) {
130+ manager . pushStateToURL ( state ) ;
131+ return manager . history . push . mock . calls [ 0 ] [ 0 ] . search ;
132+ }
133+
134+ function simulateBrowserHistoryEvent ( newUrl ) {
135+ // Since we're not in a real browser, we simulate the change event that
136+ // would have ocurred.
137+ manager . history . listen . mock . calls [ 0 ] [ 0 ] ( {
138+ search : newUrl
139+ } ) ;
140+ }
141+
142+ function subject ( onURLStateChangeHandler , newUrl ) {
143+ // Set our handler, which we be called any time url state changes
144+ manager . onURLStateChange ( onURLStateChangeHandler ) ;
145+
146+ simulateBrowserHistoryEvent ( newUrl ) ;
147+ }
148+
116149 it ( "will call provided callback with updated state when url changes" , ( ) => {
117- const manager = createManager ( ) ;
150+ setup ( ) ;
151+ let newState ;
152+
153+ // Provide url state change handler
154+ subject ( state => {
155+ newState = state ;
156+ } , basicParameterStateAsUrl ) ;
157+
158+ // Verify it is called when url state changes
159+ expect ( newState ) . toEqual ( basicParameterState ) ;
160+ } ) ;
161+
162+ /*
163+ If we triggered the callback every time we pushed state to the url,
164+ we would have an infinite loop.
165+
166+ pushStateToURL -> UpdateUrl -> HistoryEvent -> Handler -> pushstateToURL
167+
168+ Instead, we just want:
169+ pushStateToURL -> UpdateUrl -> HistoryEvent -> Handler
118170
171+ */
172+ it ( "will not trigger callback as a result of pushStateToURL" , ( ) => {
173+ setup ( ) ;
174+
175+ // Push state to the url
176+ // newUrl is the url that the browser changed to
177+ const newUrl = pushStateToURL ( basicParameterState ) ;
119178 let newState ;
120- manager . onURLStateChange ( state => {
179+
180+ // Provide url state change handler
181+ subject ( state => {
121182 newState = state ;
122- } ) ;
183+ } , newUrl ) ;
123184
124- // Simulate state change
125- manager . history . listen . mock . calls [ 0 ] [ 0 ] ( {
126- search :
127- "?fv-dependencies=underscore&fv-keywords=node&q=node&size=20&sort-direction=asc&sort-field=name"
128- } ) ;
185+ // Verify it is called when url state changes
186+ expect ( newState ) . toBe ( undefined ) ;
187+ } ) ;
188+
189+ it ( "will trigger callback if navigating back to a url with browser buttons" , ( ) => {
190+ setup ( ) ;
191+
192+ // Push state to the url
193+ // newUrl is the url that the browser changed to
194+ const newUrl = pushStateToURL ( basicParameterState ) ;
195+ let newState ;
196+
197+ // Provide url state change handler
198+ subject ( state => {
199+ newState = state ;
200+ } , newUrl ) ;
201+
202+ // Verify it is called when url state changes
203+ expect ( newState ) . toBe ( undefined ) ;
204+
205+ // Back button to empty state
206+ simulateBrowserHistoryEvent ( "" ) ;
207+ expect ( newState ) . toEqual ( { } ) ; // Was called, but empty state
129208
130- expect ( newState ) . toMatchSnapshot ( ) ;
209+ // Forward button to double back to the original "newUrl"
210+ simulateBrowserHistoryEvent ( newUrl ) ;
211+ expect ( newState ) . toEqual ( basicParameterState ) ;
131212 } ) ;
132213} ) ;
0 commit comments