navigation-stack 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +20 -12
- package/lib/cjs/NavigationStack.js +17 -2
- package/lib/cjs/debug.js +12 -0
- package/lib/cjs/getLocationFromInternalLocation.js +2 -2
- package/lib/cjs/navigationBlockers.js +3 -0
- package/lib/cjs/scroll-position/ScrollPositionAutoSaver.js +13 -2
- package/lib/cjs/scroll-position/ScrollPositionRestoration.js +29 -5
- package/lib/cjs/scroll-position/ScrollPositionSaver.js +8 -2
- package/lib/cjs/session/Session.js +6 -0
- package/lib/cjs/session/navigation/operation/operations.js +4 -4
- package/lib/esm/NavigationStack.js +17 -2
- package/lib/esm/debug.js +7 -0
- package/lib/esm/getLocationFromInternalLocation.js +2 -2
- package/lib/esm/navigationBlockers.js +3 -0
- package/lib/esm/scroll-position/ScrollPositionAutoSaver.js +13 -2
- package/lib/esm/scroll-position/ScrollPositionRestoration.js +29 -5
- package/lib/esm/scroll-position/ScrollPositionSaver.js +8 -2
- package/lib/esm/session/Session.js +6 -0
- package/lib/esm/session/navigation/operation/operations.js +4 -4
- package/lib/index.d.ts +10 -9
- package/lib/scroll-position/index.d.ts +3 -3
- package/package.json +1 -1
- package/src/NavigationStack.js +18 -2
- package/src/debug.js +8 -0
- package/src/getLocationFromInternalLocation.js +2 -2
- package/src/navigationBlockers.js +3 -0
- package/src/scroll-position/ScrollPositionAutoSaver.js +19 -2
- package/src/scroll-position/ScrollPositionRestoration.js +92 -47
- package/src/scroll-position/ScrollPositionSaver.js +21 -1
- package/src/session/Session.js +22 -0
- package/src/session/navigation/operation/operations.js +4 -4
- package/test/NavigationStack.test.js +14 -14
- package/test/middlewareTestUtil.js +1 -1
- package/test/redux/locationReducer.test.js +1 -1
- package/test/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.test.js +5 -5
- package/test/redux/middleware/createProgrammaticNavigationBlockerMiddleware.test.js +2 -2
- package/test/redux/middleware/navigationOperationMiddleware.test.js +2 -2
- package/test/scroll-position/ScrollPositionRestoration.test.js +73 -56
- package/test/scroll-position/addScrollableContainer.js +5 -2
- package/test/scroll-position/{addScrollableContainerWithHyperlink.js → addScrollableContainerWithAnchors.js} +8 -2
- package/test/scroll-position/createApp.js +20 -0
- package/test/scroll-position/withScrollableContainerAtIndexPageWithDisabledAutomaticScrollPositionRestoration.js +72 -0
- package/test/session/InMemorySession.test.js +28 -28
- package/test/session/ServerSession.test.js +1 -1
- package/test/session/WebBrowserSession.test.js +17 -17
- package/types/index.d.ts +10 -9
- package/types/scroll-position/index.d.ts +3 -3
- package/test/scroll-position/withScrollableContainerAtIndexPage.js +0 -62
|
@@ -5,6 +5,7 @@ import ScrollPositionSaver from './ScrollPositionSaver';
|
|
|
5
5
|
import ScrollPositionSetter from './ScrollPositionSetter';
|
|
6
6
|
import { PAGE_SCROLLABLE_CONTAINER_KEY } from './constants';
|
|
7
7
|
import LocationDataStorage from '../data-storage/LocationDataStorage';
|
|
8
|
+
import debug from '../debug';
|
|
8
9
|
|
|
9
10
|
function areEqualScrollPositions(scrollPosition1, scrollPosition2) {
|
|
10
11
|
let i = 0;
|
|
@@ -81,12 +82,22 @@ export default class ScrollPositionRestoration {
|
|
|
81
82
|
// this._scrollableContainerKeyCounter++;
|
|
82
83
|
// const scrollableContainerKey = String(this._scrollableContainerKeyCounter);
|
|
83
84
|
|
|
85
|
+
// Validate `scrollableContainerKey`.
|
|
84
86
|
if (scrollableContainerKey === PAGE_SCROLLABLE_CONTAINER_KEY) {
|
|
85
87
|
throw new Error(
|
|
86
88
|
`Scrollable container key "${scrollableContainerKey}" is not allowed`,
|
|
87
89
|
);
|
|
88
90
|
}
|
|
89
91
|
|
|
92
|
+
// Check that it hasn't already been added.
|
|
93
|
+
if (this._scrollableContainers[scrollableContainerKey]) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`Scrollable container key "${scrollableContainerKey}" is already added`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
debug('add scrollable container', scrollableContainerKey);
|
|
100
|
+
|
|
90
101
|
// Add scrollable container entry.
|
|
91
102
|
this._scrollableContainers[scrollableContainerKey] = {
|
|
92
103
|
// Scrollable container element.
|
|
@@ -126,11 +137,22 @@ export default class ScrollPositionRestoration {
|
|
|
126
137
|
scrollableContainerKey,
|
|
127
138
|
);
|
|
128
139
|
if (previouslySavedScrollPosition) {
|
|
140
|
+
debug(
|
|
141
|
+
'restore scroll position on add scrollable container',
|
|
142
|
+
this._location.pathname,
|
|
143
|
+
scrollableContainerKey,
|
|
144
|
+
previouslySavedScrollPosition,
|
|
145
|
+
);
|
|
129
146
|
this._scrollPosition.setScrollableContainerScrollPosition(
|
|
130
147
|
scrollableContainer,
|
|
131
148
|
previouslySavedScrollPosition,
|
|
132
149
|
);
|
|
133
150
|
} else {
|
|
151
|
+
debug(
|
|
152
|
+
'save scroll position on add scrollable container',
|
|
153
|
+
this._location.pathname,
|
|
154
|
+
scrollableContainerKey,
|
|
155
|
+
);
|
|
134
156
|
this._scrollPositionSaver.saveScrollableContainerScrollPosition(
|
|
135
157
|
scrollableContainerKey,
|
|
136
158
|
scrollableContainer,
|
|
@@ -146,12 +168,16 @@ export default class ScrollPositionRestoration {
|
|
|
146
168
|
|
|
147
169
|
// Removes the scrollable container.
|
|
148
170
|
return () => {
|
|
171
|
+
debug('remove scrollable container', scrollableContainerKey);
|
|
172
|
+
|
|
149
173
|
this._scrollPositionSaver._scrollPositionAutoSaver.cancelSaveScrollableContainerScrollPosition(
|
|
150
174
|
scrollableContainerKey,
|
|
151
175
|
);
|
|
176
|
+
|
|
152
177
|
this._scrollPositionSaver._scrollPositionAutoSaver.removeScrollableContainerScrollListener(
|
|
153
178
|
scrollableContainerKey,
|
|
154
179
|
);
|
|
180
|
+
|
|
155
181
|
delete this._scrollableContainers[scrollableContainerKey];
|
|
156
182
|
};
|
|
157
183
|
}
|
|
@@ -231,8 +257,10 @@ export default class ScrollPositionRestoration {
|
|
|
231
257
|
//
|
|
232
258
|
_sessionExecutionStatusListener = ({ running }) => {
|
|
233
259
|
if (running) {
|
|
260
|
+
debug('▶ running');
|
|
234
261
|
this._disableAutomaticScrollRestoration();
|
|
235
262
|
} else {
|
|
263
|
+
debug('⏹ not running');
|
|
236
264
|
this._enableAutomaticScrollRestoration();
|
|
237
265
|
|
|
238
266
|
// There might be previous scroll position already saved in the data storage.
|
|
@@ -266,15 +294,22 @@ export default class ScrollPositionRestoration {
|
|
|
266
294
|
//
|
|
267
295
|
// // Save the current scroll position on the current page while it's still rendered.
|
|
268
296
|
// // This saved scroll position could later be restored in case of returing to this page.
|
|
297
|
+
// // Even if the current scroll position is a default one (scrolled to top), it should still
|
|
298
|
+
// // be saved in order to overwrite any potential previously-saved non-default scroll position.
|
|
269
299
|
// this._scrollPositionSaver.saveScrollPosition();
|
|
270
300
|
// };
|
|
271
301
|
|
|
302
|
+
// Should be called whenever a different location has been rendered (i.e. immediately after).
|
|
303
|
+
// Returns a Promise that resolves when finished restoring scroll position.
|
|
304
|
+
// There's no need to await for that Promise. It's just there because it exists.
|
|
272
305
|
locationRendered(location) {
|
|
273
306
|
// Validate that `location` has a `key`.
|
|
274
307
|
if (!location.key) {
|
|
275
308
|
throw new Error('`location` must have a `key`');
|
|
276
309
|
}
|
|
277
310
|
|
|
311
|
+
debug('rendered location', location.pathname);
|
|
312
|
+
|
|
278
313
|
this._prevLocation = this._location;
|
|
279
314
|
this._location = location;
|
|
280
315
|
|
|
@@ -307,7 +342,7 @@ export default class ScrollPositionRestoration {
|
|
|
307
342
|
|
|
308
343
|
// Set the scroll position for the new page:
|
|
309
344
|
// either restore a previously-saved one or set it to a default scroll position.
|
|
310
|
-
this._setScrollPosition();
|
|
345
|
+
return this._setScrollPosition();
|
|
311
346
|
}
|
|
312
347
|
|
|
313
348
|
// Tells if the current scroll position is the default one.
|
|
@@ -343,59 +378,69 @@ export default class ScrollPositionRestoration {
|
|
|
343
378
|
return true;
|
|
344
379
|
}
|
|
345
380
|
|
|
381
|
+
// Restores scroll position.
|
|
382
|
+
// Returns a Promise that resolves when finished setting scroll position.
|
|
383
|
+
// There's no need to await for this Promise. It just exists.
|
|
346
384
|
_setScrollPosition() {
|
|
347
|
-
|
|
348
|
-
this._scrollableContainers
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
this._scrollableContainers[scrollableContainerKey];
|
|
385
|
+
return Promise.all(
|
|
386
|
+
Object.keys(this._scrollableContainers).map((scrollableContainerKey) => {
|
|
387
|
+
const scrollableContainerEntry =
|
|
388
|
+
this._scrollableContainers[scrollableContainerKey];
|
|
352
389
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
390
|
+
// This function is only used in tests.
|
|
391
|
+
// There seems to be no use of it in real life, hence it's not public API.
|
|
392
|
+
// It's only used in tests.
|
|
393
|
+
if (scrollableContainerEntry._shouldUpdateScrollPositionForLocation) {
|
|
394
|
+
if (
|
|
395
|
+
!scrollableContainerEntry._shouldUpdateScrollPositionForLocation(
|
|
396
|
+
this._location,
|
|
397
|
+
this._prevLocation,
|
|
398
|
+
)
|
|
399
|
+
) {
|
|
400
|
+
return Promise.resolve();
|
|
401
|
+
}
|
|
364
402
|
}
|
|
365
|
-
}
|
|
366
403
|
|
|
367
|
-
|
|
368
|
-
|
|
404
|
+
// Scroll position (or anchor) to set.
|
|
405
|
+
let scrollPositionOrAnchorToSet;
|
|
406
|
+
|
|
407
|
+
// This function is only used in tests.
|
|
408
|
+
// There seems to be no use of it in real life, hence it's not public API.
|
|
409
|
+
// It's only used in tests.
|
|
410
|
+
if (scrollableContainerEntry._getScrollPositionForLocation) {
|
|
411
|
+
scrollPositionOrAnchorToSet =
|
|
412
|
+
scrollableContainerEntry._getScrollPositionForLocation(
|
|
413
|
+
this._location,
|
|
414
|
+
this._prevLocation,
|
|
415
|
+
);
|
|
416
|
+
}
|
|
369
417
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
418
|
+
// Get scroll position (or anchor) to set.
|
|
419
|
+
if (!scrollPositionOrAnchorToSet) {
|
|
420
|
+
scrollPositionOrAnchorToSet =
|
|
421
|
+
scrollableContainerKey === PAGE_SCROLLABLE_CONTAINER_KEY
|
|
422
|
+
? this._getPageScrollPositionOrAnchorToSet(this._location)
|
|
423
|
+
: this._getScrollableContainerScrollPositionToSet(
|
|
424
|
+
this._location,
|
|
425
|
+
scrollableContainerKey,
|
|
426
|
+
);
|
|
427
|
+
}
|
|
380
428
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
scrollableContainerKey
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
this._location,
|
|
388
|
-
scrollableContainerKey,
|
|
389
|
-
);
|
|
390
|
-
}
|
|
429
|
+
debug(
|
|
430
|
+
'restore scroll position',
|
|
431
|
+
this._location.pathname,
|
|
432
|
+
scrollableContainerKey,
|
|
433
|
+
scrollPositionOrAnchorToSet,
|
|
434
|
+
);
|
|
391
435
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
436
|
+
// Set scroll position of scrollable container.
|
|
437
|
+
return scrollableContainerEntry.scrollPositionSetter.set(
|
|
438
|
+
scrollableContainerEntry.scrollableContainer,
|
|
439
|
+
scrollPositionOrAnchorToSet,
|
|
440
|
+
this._scrollPosition,
|
|
441
|
+
);
|
|
442
|
+
}),
|
|
443
|
+
);
|
|
399
444
|
}
|
|
400
445
|
|
|
401
446
|
// Overrides the default `window.history.scrollRestoration` value.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import ScrollPositionAutoSaver from './ScrollPositionAutoSaver';
|
|
4
4
|
import { PAGE_SCROLLABLE_CONTAINER_KEY } from './constants';
|
|
5
|
+
import debug from '../debug';
|
|
5
6
|
|
|
6
7
|
export default class ScrollPositionSaver {
|
|
7
8
|
constructor({
|
|
@@ -43,6 +44,8 @@ export default class ScrollPositionSaver {
|
|
|
43
44
|
return;
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
debug('save scroll position', this._getLocation().pathname);
|
|
48
|
+
|
|
46
49
|
// Get scrollable containers.
|
|
47
50
|
const scrollableContainers = this._getScrollableContainers();
|
|
48
51
|
|
|
@@ -60,12 +63,19 @@ export default class ScrollPositionSaver {
|
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
savePageScrollPosition() {
|
|
66
|
+
debug(
|
|
67
|
+
'save scroll position',
|
|
68
|
+
this._getLocation().pathname,
|
|
69
|
+
PAGE_SCROLLABLE_CONTAINER_KEY,
|
|
70
|
+
this._scrollPosition.getPageScrollPosition(),
|
|
71
|
+
);
|
|
72
|
+
|
|
63
73
|
// * If this is not a scheduled "auto-save" of scroll position
|
|
64
74
|
// and there already exists any scheduled "auto-save" of scroll position,
|
|
65
75
|
// cancel it and save scroll position right now instead.
|
|
66
76
|
// * If this is a scheduled "auto-save" of scroll position,
|
|
67
77
|
// clear the "cancel" function because it's no longer of use.
|
|
68
|
-
this._scrollPositionAutoSaver.cancelSavePageScrollPosition();
|
|
78
|
+
this._scrollPositionAutoSaver.cancelSavePageScrollPosition(true);
|
|
69
79
|
|
|
70
80
|
// Save scroll position.
|
|
71
81
|
this._saveScrollPositionForLocation(
|
|
@@ -79,6 +89,15 @@ export default class ScrollPositionSaver {
|
|
|
79
89
|
scrollableContainerKey,
|
|
80
90
|
scrollableContainer,
|
|
81
91
|
) {
|
|
92
|
+
debug(
|
|
93
|
+
'save scroll position',
|
|
94
|
+
this._getLocation().pathname,
|
|
95
|
+
scrollableContainerKey,
|
|
96
|
+
this._scrollPosition.getScrollableContainerScrollPosition(
|
|
97
|
+
scrollableContainer,
|
|
98
|
+
),
|
|
99
|
+
);
|
|
100
|
+
|
|
82
101
|
// * If this is not a scheduled "auto-save" of scroll position
|
|
83
102
|
// and there already exists any scheduled "auto-save" of scroll position,
|
|
84
103
|
// cancel it and save scroll position right now instead.
|
|
@@ -86,6 +105,7 @@ export default class ScrollPositionSaver {
|
|
|
86
105
|
// clear the "cancel" function because it's no longer of use.
|
|
87
106
|
this._scrollPositionAutoSaver.cancelSaveScrollableContainerScrollPosition(
|
|
88
107
|
scrollableContainerKey,
|
|
108
|
+
true,
|
|
89
109
|
);
|
|
90
110
|
|
|
91
111
|
// Save scroll position.
|
package/src/session/Session.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import debug from '../debug';
|
|
1
2
|
import parseInputLocation from '../parseInputLocation';
|
|
2
3
|
import createSessionKey from './key/createSessionKey';
|
|
3
4
|
import NavigationOutOfBoundsError from './navigation/error/NavigationOutOfBoundsError';
|
|
@@ -48,6 +49,13 @@ export default class Session {
|
|
|
48
49
|
// but if it was possible, this call would be required. It would also be required
|
|
49
50
|
// by `navigation` to call `session.getNextKey()` function to increment `locationKeyIndex`.
|
|
50
51
|
this._updateTerminalLocationIndex(location);
|
|
52
|
+
|
|
53
|
+
debug(
|
|
54
|
+
'current location',
|
|
55
|
+
location.pathname,
|
|
56
|
+
'index',
|
|
57
|
+
this._currentLocationIndex,
|
|
58
|
+
);
|
|
51
59
|
});
|
|
52
60
|
}
|
|
53
61
|
|
|
@@ -94,6 +102,8 @@ export default class Session {
|
|
|
94
102
|
throw new Error('Already started');
|
|
95
103
|
}
|
|
96
104
|
|
|
105
|
+
debug('▶ start session', initialLocation.pathname);
|
|
106
|
+
|
|
97
107
|
this._started = true;
|
|
98
108
|
|
|
99
109
|
const key = this._getNextLocationKey();
|
|
@@ -117,6 +127,8 @@ export default class Session {
|
|
|
117
127
|
throw Error('Already stopped');
|
|
118
128
|
}
|
|
119
129
|
|
|
130
|
+
debug('⏹ stop session');
|
|
131
|
+
|
|
120
132
|
// Once stopped, it won't be able to be restarted.
|
|
121
133
|
this._stopped = true;
|
|
122
134
|
|
|
@@ -148,6 +160,14 @@ export default class Session {
|
|
|
148
160
|
const key = this._getNextLocationKey();
|
|
149
161
|
const index = this._currentLocationIndex + delta;
|
|
150
162
|
|
|
163
|
+
debug(
|
|
164
|
+
operation === NavigationOperations.PUSH ? '↓' : '⇅',
|
|
165
|
+
operation,
|
|
166
|
+
location.pathname,
|
|
167
|
+
'index',
|
|
168
|
+
index,
|
|
169
|
+
);
|
|
170
|
+
|
|
151
171
|
// Navigate to the location.
|
|
152
172
|
const locationResult = this._navigation.navigate(location, {
|
|
153
173
|
operation,
|
|
@@ -173,6 +193,8 @@ export default class Session {
|
|
|
173
193
|
|
|
174
194
|
const index = this._currentLocationIndex + delta;
|
|
175
195
|
|
|
196
|
+
debug(delta > 0 ? '→' : '←', 'shift', delta, 'index', index);
|
|
197
|
+
|
|
176
198
|
// Validate that the new `index` is not out of bounds.
|
|
177
199
|
if (index < 0 || index > this._terminalLocationIndex) {
|
|
178
200
|
throw new NavigationOutOfBoundsError(index);
|
|
@@ -23,19 +23,19 @@ describe('NavigationStack', () => {
|
|
|
23
23
|
navigationStack.push('/new');
|
|
24
24
|
expect(navigationStack.current()).to.include({
|
|
25
25
|
pathname: '/new',
|
|
26
|
-
|
|
26
|
+
index: 1,
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
navigationStack.shift(-1);
|
|
30
30
|
expect(navigationStack.current()).to.include({
|
|
31
31
|
pathname: '/initial',
|
|
32
|
-
|
|
32
|
+
index: 0,
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
navigationStack.shift(+1);
|
|
36
36
|
expect(navigationStack.current()).to.include({
|
|
37
37
|
pathname: '/new',
|
|
38
|
-
|
|
38
|
+
index: 1,
|
|
39
39
|
});
|
|
40
40
|
});
|
|
41
41
|
|
|
@@ -43,7 +43,7 @@ describe('NavigationStack', () => {
|
|
|
43
43
|
navigationStack.replace('/new');
|
|
44
44
|
expect(navigationStack.current()).to.include({
|
|
45
45
|
pathname: '/new',
|
|
46
|
-
|
|
46
|
+
index: 0,
|
|
47
47
|
});
|
|
48
48
|
});
|
|
49
49
|
});
|
|
@@ -71,21 +71,21 @@ describe('NavigationStack (WebBrowserSession)', () => {
|
|
|
71
71
|
await delay(20);
|
|
72
72
|
expect(navigationStack.current()).to.include({
|
|
73
73
|
pathname: '/new',
|
|
74
|
-
|
|
74
|
+
index: 1,
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
navigationStack.shift(-1);
|
|
78
78
|
await delay(20);
|
|
79
79
|
expect(navigationStack.current()).to.include({
|
|
80
80
|
pathname: '/initial',
|
|
81
|
-
|
|
81
|
+
index: 0,
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
navigationStack.shift(+1);
|
|
85
85
|
await delay(20);
|
|
86
86
|
expect(navigationStack.current()).to.include({
|
|
87
87
|
pathname: '/new',
|
|
88
|
-
|
|
88
|
+
index: 1,
|
|
89
89
|
});
|
|
90
90
|
});
|
|
91
91
|
|
|
@@ -94,7 +94,7 @@ describe('NavigationStack (WebBrowserSession)', () => {
|
|
|
94
94
|
await delay(20);
|
|
95
95
|
expect(navigationStack.current()).to.include({
|
|
96
96
|
pathname: '/new',
|
|
97
|
-
|
|
97
|
+
index: 0,
|
|
98
98
|
});
|
|
99
99
|
});
|
|
100
100
|
});
|
|
@@ -121,7 +121,7 @@ describe('NavigationStack.subscribe', () => {
|
|
|
121
121
|
// `.init()` calls subscription listeners.
|
|
122
122
|
expect(listener).to.have.been.calledOnce();
|
|
123
123
|
expect(listener.lastCall.args[0]).to.include({
|
|
124
|
-
// operation: '
|
|
124
|
+
// operation: 'init',
|
|
125
125
|
pathname: '/initial',
|
|
126
126
|
});
|
|
127
127
|
listener.resetHistory();
|
|
@@ -130,7 +130,7 @@ describe('NavigationStack.subscribe', () => {
|
|
|
130
130
|
|
|
131
131
|
expect(listener).to.have.been.calledOnce();
|
|
132
132
|
expect(listener.lastCall.args[0]).to.include({
|
|
133
|
-
// operation: '
|
|
133
|
+
// operation: 'push',
|
|
134
134
|
pathname: '/new',
|
|
135
135
|
});
|
|
136
136
|
listener.resetHistory();
|
|
@@ -139,7 +139,7 @@ describe('NavigationStack.subscribe', () => {
|
|
|
139
139
|
|
|
140
140
|
expect(listener).to.have.been.calledOnce();
|
|
141
141
|
expect(listener.lastCall.args[0]).to.include({
|
|
142
|
-
// operation: '
|
|
142
|
+
// operation: 'replace',
|
|
143
143
|
pathname: '/new-2',
|
|
144
144
|
});
|
|
145
145
|
listener.resetHistory();
|
|
@@ -148,7 +148,7 @@ describe('NavigationStack.subscribe', () => {
|
|
|
148
148
|
|
|
149
149
|
expect(listener).to.have.been.calledOnce();
|
|
150
150
|
expect(listener.lastCall.args[0]).to.include({
|
|
151
|
-
// operation: '
|
|
151
|
+
// operation: 'shift',
|
|
152
152
|
// delta: -1,
|
|
153
153
|
pathname: '/initial',
|
|
154
154
|
});
|
|
@@ -176,7 +176,7 @@ describe('NavigationStack.subscribe', () => {
|
|
|
176
176
|
// `.init()` calls subscription listeners.
|
|
177
177
|
expect(listener).to.have.been.calledOnce();
|
|
178
178
|
expect(listener.lastCall.args[0]).to.include({
|
|
179
|
-
// operation: '
|
|
179
|
+
// operation: 'init',
|
|
180
180
|
pathname: '/initial',
|
|
181
181
|
});
|
|
182
182
|
listener.resetHistory();
|
|
@@ -252,7 +252,7 @@ describe('NavigationStack', () => {
|
|
|
252
252
|
|
|
253
253
|
expect(navigationStack.current()).to.include({
|
|
254
254
|
pathname: '/new',
|
|
255
|
-
|
|
255
|
+
index: 1,
|
|
256
256
|
});
|
|
257
257
|
});
|
|
258
258
|
|
|
@@ -40,7 +40,7 @@ describe('createNonProgrammaticNavigationBlockerMiddleware', () => {
|
|
|
40
40
|
// sandbox.restore();
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
describe('
|
|
43
|
+
describe('shift navigation', () => {
|
|
44
44
|
beforeEach(() => {
|
|
45
45
|
store.dispatch(Actions.push('/new'));
|
|
46
46
|
});
|
|
@@ -53,7 +53,7 @@ describe('createNonProgrammaticNavigationBlockerMiddleware', () => {
|
|
|
53
53
|
expect(store.getState().pathname).to.equal('/initial');
|
|
54
54
|
|
|
55
55
|
expect(blocker.firstCall.args[0]).to.include({
|
|
56
|
-
// operation: '
|
|
56
|
+
// operation: 'shift',
|
|
57
57
|
pathname: '/initial',
|
|
58
58
|
// delta: -1,
|
|
59
59
|
});
|
|
@@ -199,7 +199,7 @@ describe('createNonProgrammaticNavigationBlockerMiddleware', () => {
|
|
|
199
199
|
// session._currentLocationIndex = 0;
|
|
200
200
|
// session._navigation._triggerUpdateInternalLocationMiddlewareListener(
|
|
201
201
|
// session._navigation._createLocationObject({
|
|
202
|
-
// operation: '
|
|
202
|
+
// operation: 'shift',
|
|
203
203
|
// delta: null,
|
|
204
204
|
// }),
|
|
205
205
|
// );
|
|
@@ -222,7 +222,7 @@ describe('createNonProgrammaticNavigationBlockerMiddleware', () => {
|
|
|
222
222
|
// /* eslint-disable no-underscore-dangle */
|
|
223
223
|
// session._navigation._index = 0;
|
|
224
224
|
// session._navigation._subscriptionListener(session._navigation._createLocationObject({
|
|
225
|
-
// operation: '
|
|
225
|
+
// operation: 'shift',
|
|
226
226
|
// delta: null,
|
|
227
227
|
// }));
|
|
228
228
|
// /* eslint-enable no-underscore-dangle */
|
|
@@ -245,7 +245,7 @@ describe('createNonProgrammaticNavigationBlockerMiddleware', () => {
|
|
|
245
245
|
// /* eslint-disable no-underscore-dangle */
|
|
246
246
|
// session._navigation._index = 0;
|
|
247
247
|
// session._navigation._subscriptionListener(session._navigation._createLocationObject({
|
|
248
|
-
// operation: '
|
|
248
|
+
// operation: 'shift',
|
|
249
249
|
// delta: null,
|
|
250
250
|
// }));
|
|
251
251
|
// /* eslint-enable no-underscore-dangle */
|
|
@@ -41,7 +41,7 @@ describe('createProgrammaticNavigationBlockerMiddleware', () => {
|
|
|
41
41
|
// sandbox.restore();
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
describe('
|
|
44
|
+
describe('push navigation', () => {
|
|
45
45
|
it('should block navigation when blocker returns `true`', () => {
|
|
46
46
|
const blocker = sinon.stub().returns(true);
|
|
47
47
|
addNavigationBlocker(blocker);
|
|
@@ -52,7 +52,7 @@ describe('createProgrammaticNavigationBlockerMiddleware', () => {
|
|
|
52
52
|
expect(blocker).to.have.been.calledOnce();
|
|
53
53
|
|
|
54
54
|
expect(blocker.firstCall.args[0]).to.include({
|
|
55
|
-
// operation: '
|
|
55
|
+
// operation: 'push',
|
|
56
56
|
pathname: '/new',
|
|
57
57
|
});
|
|
58
58
|
});
|
|
@@ -22,7 +22,7 @@ describe('navigationOperationMiddleware', () => {
|
|
|
22
22
|
expect(next).to.be.calledWith({
|
|
23
23
|
type: ActionTypes.NAVIGATE,
|
|
24
24
|
payload: {
|
|
25
|
-
operation: '
|
|
25
|
+
operation: 'push',
|
|
26
26
|
location: {
|
|
27
27
|
pathname: '/foo',
|
|
28
28
|
search: '?bar=baz',
|
|
@@ -45,7 +45,7 @@ describe('navigationOperationMiddleware', () => {
|
|
|
45
45
|
expect(next).to.be.calledWith({
|
|
46
46
|
type: ActionTypes.NAVIGATE,
|
|
47
47
|
payload: {
|
|
48
|
-
operation: '
|
|
48
|
+
operation: 'replace',
|
|
49
49
|
location: {
|
|
50
50
|
pathname: '/foo',
|
|
51
51
|
search: '?bar=baz',
|