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.
Files changed (49) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +20 -12
  3. package/lib/cjs/NavigationStack.js +17 -2
  4. package/lib/cjs/debug.js +12 -0
  5. package/lib/cjs/getLocationFromInternalLocation.js +2 -2
  6. package/lib/cjs/navigationBlockers.js +3 -0
  7. package/lib/cjs/scroll-position/ScrollPositionAutoSaver.js +13 -2
  8. package/lib/cjs/scroll-position/ScrollPositionRestoration.js +29 -5
  9. package/lib/cjs/scroll-position/ScrollPositionSaver.js +8 -2
  10. package/lib/cjs/session/Session.js +6 -0
  11. package/lib/cjs/session/navigation/operation/operations.js +4 -4
  12. package/lib/esm/NavigationStack.js +17 -2
  13. package/lib/esm/debug.js +7 -0
  14. package/lib/esm/getLocationFromInternalLocation.js +2 -2
  15. package/lib/esm/navigationBlockers.js +3 -0
  16. package/lib/esm/scroll-position/ScrollPositionAutoSaver.js +13 -2
  17. package/lib/esm/scroll-position/ScrollPositionRestoration.js +29 -5
  18. package/lib/esm/scroll-position/ScrollPositionSaver.js +8 -2
  19. package/lib/esm/session/Session.js +6 -0
  20. package/lib/esm/session/navigation/operation/operations.js +4 -4
  21. package/lib/index.d.ts +10 -9
  22. package/lib/scroll-position/index.d.ts +3 -3
  23. package/package.json +1 -1
  24. package/src/NavigationStack.js +18 -2
  25. package/src/debug.js +8 -0
  26. package/src/getLocationFromInternalLocation.js +2 -2
  27. package/src/navigationBlockers.js +3 -0
  28. package/src/scroll-position/ScrollPositionAutoSaver.js +19 -2
  29. package/src/scroll-position/ScrollPositionRestoration.js +92 -47
  30. package/src/scroll-position/ScrollPositionSaver.js +21 -1
  31. package/src/session/Session.js +22 -0
  32. package/src/session/navigation/operation/operations.js +4 -4
  33. package/test/NavigationStack.test.js +14 -14
  34. package/test/middlewareTestUtil.js +1 -1
  35. package/test/redux/locationReducer.test.js +1 -1
  36. package/test/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.test.js +5 -5
  37. package/test/redux/middleware/createProgrammaticNavigationBlockerMiddleware.test.js +2 -2
  38. package/test/redux/middleware/navigationOperationMiddleware.test.js +2 -2
  39. package/test/scroll-position/ScrollPositionRestoration.test.js +73 -56
  40. package/test/scroll-position/addScrollableContainer.js +5 -2
  41. package/test/scroll-position/{addScrollableContainerWithHyperlink.js → addScrollableContainerWithAnchors.js} +8 -2
  42. package/test/scroll-position/createApp.js +20 -0
  43. package/test/scroll-position/withScrollableContainerAtIndexPageWithDisabledAutomaticScrollPositionRestoration.js +72 -0
  44. package/test/session/InMemorySession.test.js +28 -28
  45. package/test/session/ServerSession.test.js +1 -1
  46. package/test/session/WebBrowserSession.test.js +17 -17
  47. package/types/index.d.ts +10 -9
  48. package/types/scroll-position/index.d.ts +3 -3
  49. package/test/scroll-position/withScrollableContainerAtIndexPage.js +0 -62
@@ -2,12 +2,12 @@ import { offset, scrollLeft, scrollTop } from 'dom-helpers';
2
2
  import sinon from 'sinon';
3
3
 
4
4
  import addScrollableContainer from './addScrollableContainer';
5
- import addScrollableContainerWithHyperlink from './addScrollableContainerWithHyperlink';
5
+ import addScrollableContainerWithAnchors from './addScrollableContainerWithAnchors';
6
6
  import createApp from './createApp';
7
7
  import delay from './delay';
8
8
  import { setEventListener, triggerEvent } from './mockPageLifecycle';
9
9
  import runApp from './runApp';
10
- import withScrollableContainerAtIndexPage from './withScrollableContainerAtIndexPage';
10
+ import withScrollableContainerAtIndexPageWithDisabledAutomaticScrollPositionRestoration from './withScrollableContainerAtIndexPageWithDisabledAutomaticScrollPositionRestoration';
11
11
  import PageLifecycle from '../../src/session/lifecycle/page-lifecycle/PageLifecycleInstance';
12
12
 
13
13
  describe('ScrollPositionRestoration', () => {
@@ -59,13 +59,14 @@ describe('ScrollPositionRestoration', () => {
59
59
 
60
60
  describe('default behavior', () => {
61
61
  it('should emulate browser scroll behavior', (done) => {
62
- const app = addScrollableContainerWithHyperlink(createApp());
62
+ const app = addScrollableContainerWithAnchors(createApp());
63
63
  const child1 = document.getElementById('child1');
64
64
  const child2 = document.getElementById('child2-id');
65
65
 
66
66
  unlisten = runApp(app, [
67
67
  () => {
68
- // This will be ignored, but will exercise the throttle logic.
68
+ // This scroll will be ignored (overwritten by a subsequent scroll),
69
+ // but it will test the "throttle scroll events" code.
69
70
  scrollTop(window, 10000);
70
71
 
71
72
  setTimeout(() => {
@@ -113,7 +114,7 @@ describe('ScrollPositionRestoration', () => {
113
114
  configurable: true,
114
115
  });
115
116
 
116
- const app = addScrollableContainerWithHyperlink(createApp());
117
+ const app = addScrollableContainerWithAnchors(createApp());
117
118
 
118
119
  unlisten = runApp(app, [
119
120
  () => {
@@ -130,7 +131,7 @@ describe('ScrollPositionRestoration', () => {
130
131
 
131
132
  describe('custom behavior', () => {
132
133
  it('should allow scroll suppression', (done) => {
133
- const app = addScrollableContainerWithHyperlink(
134
+ const app = addScrollableContainerWithAnchors(
134
135
  createApp({
135
136
  shouldUpdatePageScrollPositionForLocation: (
136
137
  location,
@@ -167,7 +168,7 @@ describe('ScrollPositionRestoration', () => {
167
168
  });
168
169
 
169
170
  it('should ignore scroll events when `disableSavingScrollPosition()` is used', (done) => {
170
- const app = addScrollableContainerWithHyperlink(createApp());
171
+ const app = addScrollableContainerWithAnchors(createApp());
171
172
 
172
173
  unlisten = runApp(app, [
173
174
  () => {
@@ -205,7 +206,7 @@ describe('ScrollPositionRestoration', () => {
205
206
  });
206
207
 
207
208
  it('should allow custom position', (done) => {
208
- const app = addScrollableContainerWithHyperlink(
209
+ const app = addScrollableContainerWithAnchors(
209
210
  createApp({
210
211
  getPageScrollPositionForLocation: () => [10, 20],
211
212
  }),
@@ -230,47 +231,59 @@ describe('ScrollPositionRestoration', () => {
230
231
  ]);
231
232
  });
232
233
 
233
- it('should save scroll position even if no scroll events are dispatched', (done) => {
234
- let customInitialPageScrollPosition;
235
-
236
- const app = addScrollableContainerWithHyperlink(
237
- createApp({
238
- // eslint-disable-next-line no-unused-vars
239
- getPageScrollPositionForLocation(location, prevLocation) {
240
- if (customInitialPageScrollPosition) {
241
- return [10, 20];
242
- }
243
- return undefined;
244
- },
245
- }),
246
- );
247
-
248
- unlisten = runApp(app, [
249
- () => {
250
- app.goTo('/detail');
251
- },
252
- () => {
253
- customInitialPageScrollPosition = [10, 20];
254
- app.goTo('/');
255
- },
256
- () => {
257
- customInitialPageScrollPosition = undefined;
258
- app.goTo('/detail');
259
- },
260
- () => {
261
- app.goBack();
262
- },
263
- () => {
264
- // Here, it said "expected 9.966666221618652 to equal 10".
265
- // Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
266
- expect(scrollLeft(window)).to.be.closeTo(10, 0.5);
267
- // Here, it said "expected 19.933332443237305 to equal 20".
268
- // Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
269
- expect(scrollTop(window)).to.be.closeTo(20, 0.5);
270
- done();
271
- },
272
- ]);
273
- });
234
+ // This test case was disabled because `ScrollPositionRestoration` doesn't save
235
+ // scroll position on page load. It only saves scroll position on actual scroll events.
236
+ // If there were no scroll events, the scroll position doesn't get saved.
237
+ // The rationale is that when there were no scroll events, the scroll position
238
+ // is gonna be either a default one or a custom one specified by passing a custom
239
+ // `getPageScrollPositionForLocation()` function. In the latter case, the custom
240
+ // `getPageScrollPositionForLocation()` function is responsible to return a correct scroll position
241
+ // every time it gets called rather than just return a correct scroll position once,
242
+ // save it immediately and then restore it when returning to the page.
243
+ //
244
+ // it('should save scroll position even if no scroll events are dispatched', (done) => {
245
+ // let customInitialPageScrollPosition;
246
+ //
247
+ // const app = addScrollableContainerWithAnchors(
248
+ // createApp({
249
+ // // eslint-disable-next-line no-unused-vars
250
+ // getPageScrollPositionForLocation(location, prevLocation) {
251
+ // // Only when navigated via `.goTo()`. Ignore `.goBack()` navigation.
252
+ // if (prevLocation && location.index > prevLocation.index) {
253
+ // return [10, 20];
254
+ // }
255
+ // return undefined;
256
+ // },
257
+ // }),
258
+ // );
259
+ //
260
+ // unlisten = runApp(app, [
261
+ // () => {
262
+ // app.goTo('/detail');
263
+ // },
264
+ // () => {
265
+ // app.goTo('/');
266
+ // },
267
+ // () => {
268
+ // app.goTo('/detail');
269
+ // },
270
+ // () => {
271
+ // if (customInitialPageScrollPosition === 123) {
272
+ // customInitialPageScrollPosition = 456;
273
+ // }
274
+ // app.goBack();
275
+ // },
276
+ // () => {
277
+ // // Here, it said "expected 9.966666221618652 to equal 10".
278
+ // // Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
279
+ // expect(scrollLeft(window)).to.be.closeTo(10, 0.5);
280
+ // // Here, it said "expected 19.933332443237305 to equal 20".
281
+ // // Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
282
+ // expect(scrollTop(window)).to.be.closeTo(20, 0.5);
283
+ // done();
284
+ // },
285
+ // ]);
286
+ // });
274
287
  });
275
288
 
276
289
  describe('scrollable container', () => {
@@ -308,12 +321,13 @@ describe('ScrollPositionRestoration', () => {
308
321
  ]);
309
322
  });
310
323
 
311
- it('should restore scroll on remount', (done) => {
312
- const { container, ...app } = withScrollableContainerAtIndexPage(
313
- createApp({
314
- shouldUpdatePageScrollPositionForLocation: () => false,
315
- }),
316
- );
324
+ it('should automatically restore a previously-saved scroll position when adding a scrollable container', (done) => {
325
+ const { container, ...app } =
326
+ withScrollableContainerAtIndexPageWithDisabledAutomaticScrollPositionRestoration(
327
+ createApp({
328
+ shouldUpdatePageScrollPositionForLocation: () => false,
329
+ }),
330
+ );
317
331
 
318
332
  unlisten = runApp(app, [
319
333
  () => {
@@ -325,6 +339,8 @@ describe('ScrollPositionRestoration', () => {
325
339
  () => {
326
340
  expect(container.scrollHeight).to.equal(100);
327
341
  expect(scrollTop(container)).to.equal(0);
342
+ // This `scrollTop()` won't trigger a "scroll" event
343
+ // because the container height is only `100` so it's not scrollable.
328
344
  scrollTop(container, 5000);
329
345
  delay(() => {
330
346
  app.goBack();
@@ -357,6 +373,7 @@ describe('ScrollPositionRestoration', () => {
357
373
 
358
374
  const app2 = addScrollableContainer(
359
375
  createApp({
376
+ // Restore the data of the session of `app1`.
360
377
  sessionKey: app1.getSessionKey(),
361
378
  shouldUpdatePageScrollPositionForLocation: () => false,
362
379
  }),
@@ -377,7 +394,7 @@ describe('ScrollPositionRestoration', () => {
377
394
 
378
395
  it('should ignore scroll events when `disableSavingScrollPosition` is used', (done) => {
379
396
  const app = addScrollableContainer(
380
- addScrollableContainerWithHyperlink(createApp()),
397
+ addScrollableContainerWithAnchors(createApp()),
381
398
  );
382
399
 
383
400
  unlisten = runApp(app, [
@@ -16,14 +16,17 @@ export default function addScrollableContainer(app) {
16
16
  // Add the scrollable container to the website.
17
17
  document.body.appendChild(container);
18
18
 
19
- // This function will only be called once, so no need to guard.
20
19
  function listen(listener) {
21
20
  const unlisten = app.listen(listener);
22
21
 
23
- app.registerScrollableContainer('container', container);
22
+ const unregisterScrollableContainer = app.registerScrollableContainer(
23
+ 'container',
24
+ container,
25
+ );
24
26
 
25
27
  return () => {
26
28
  unlisten();
29
+ unregisterScrollableContainer();
27
30
  document.body.removeChild(container);
28
31
  };
29
32
  }
@@ -7,27 +7,33 @@
7
7
  // * When the current location is "/", the scrollable container size is 20000x20000.
8
8
  // * At any other location, the scrollable container size is 10000x10000.
9
9
  //
10
- export default function withRoutes(app) {
10
+ export default function addScrollableContainerWithAnchors(app) {
11
11
  const container = document.createElement('div');
12
12
  document.body.appendChild(container);
13
13
 
14
14
  const child1 = document.createElement('div');
15
+ // In HTML, an "anchor" is matched either by `id` attribute value
16
+ // or by `name` attribute value.
15
17
  child1.id = 'child1';
16
18
  child1.style.height = '100px';
17
19
  container.appendChild(child1);
18
20
 
19
21
  const child2 = document.createElement('a');
20
22
  child2.id = 'child2-id';
23
+ // In HTML, an "anchor" is matched either by `id` attribute value
24
+ // or by `name` attribute value.
25
+ // Here, it tests the correctness of scrolling to an anchor called "child2".
26
+ // The `id` attribute value is different so that it doesn't interfere.
21
27
  child2.name = 'child2';
22
28
  child2.style.height = '100px';
23
29
  child2.appendChild(document.createTextNode('link'));
24
30
  container.appendChild(child2);
25
31
 
26
- // This function will only be called once, so no need to guard.
27
32
  function listen(listener) {
28
33
  const unlisten = app.listen((location) => {
29
34
  listener(location);
30
35
 
36
+ // Scrollable container has different height on different pages.
31
37
  if (location.pathname === '/') {
32
38
  container.style.height = '20000px';
33
39
  container.style.width = '20000px';
@@ -10,6 +10,7 @@ export default function createApp({
10
10
  } = {}) {
11
11
  let currentLocation = null;
12
12
 
13
+ let locationRenderedListeners = [];
13
14
  let listeners = [];
14
15
  let scrollPositionRestoration = null;
15
16
  let navigationStack = null;
@@ -24,6 +25,22 @@ export default function createApp({
24
25
  });
25
26
 
26
27
  scrollPositionRestoration.locationRendered(location);
28
+
29
+ for (const locationRenderedListener of locationRenderedListeners) {
30
+ locationRenderedListener(location);
31
+ }
32
+ }
33
+
34
+ // Adds a "location rendered" listener.
35
+ function whenRenderedLocation(listener) {
36
+ locationRenderedListeners.push(listener);
37
+
38
+ // Returns a "remove listener" function.
39
+ return () => {
40
+ locationRenderedListeners = locationRenderedListeners.filter(
41
+ (_) => _ !== listener,
42
+ );
43
+ };
27
44
  }
28
45
 
29
46
  // Removes a "location change" event listener.
@@ -77,6 +94,8 @@ export default function createApp({
77
94
  return scrollPositionRestoration.addScrollableContainer(key, element, {
78
95
  _shouldUpdateScrollPositionForLocation:
79
96
  options && options.shouldUpdateScrollPositionForLocation,
97
+ _getScrollPositionForLocation:
98
+ options && options.getScrollPositionForLocation,
80
99
  });
81
100
  }
82
101
 
@@ -108,5 +127,6 @@ export default function createApp({
108
127
  disableSavingScrollPosition,
109
128
  enableSavingScrollPosition,
110
129
  getSessionKey: () => session.key,
130
+ whenRenderedLocation,
111
131
  };
112
132
  }
@@ -0,0 +1,72 @@
1
+ // Adds a 100x100 scrollable container on the website.
2
+ //
3
+ // * When the current location is "/", it renders a large amount of content
4
+ // (20000x20000 to be specific) inside the container, making it scrollable.
5
+ //
6
+ // * At any other location, it doesn't render anything in the container.
7
+ //
8
+ export default function withScrollableContainerAtIndexPageWithDisabledAutomaticScrollPositionRestoration(
9
+ app,
10
+ ) {
11
+ const container = document.createElement('div');
12
+ container.style.height = '100px';
13
+ container.style.width = '100px';
14
+ container.style.overflow = 'hidden';
15
+ document.body.appendChild(container);
16
+
17
+ let scrollableContainerContentElement;
18
+ let unregisterScrollableContainer;
19
+
20
+ function listen(listener) {
21
+ function shouldUpdateScrollableContainerScrollPositionForLocation(
22
+ location,
23
+ prevLocation,
24
+ ) {
25
+ // Disable the automatic scroll position restoration on "back" navigation
26
+ // to check that it automatically restores scroll position when calling
27
+ // `ScrollPositionRestoration.addScrollableContainer()` method.
28
+ if (prevLocation && location.index < prevLocation.index) {
29
+ return false;
30
+ }
31
+ return true;
32
+ }
33
+
34
+ app.whenRenderedLocation((location) => {
35
+ if (location.pathname === '/') {
36
+ unregisterScrollableContainer = app.registerScrollableContainer(
37
+ 'container',
38
+ container,
39
+ {
40
+ shouldUpdateScrollPositionForLocation:
41
+ shouldUpdateScrollableContainerScrollPositionForLocation,
42
+ },
43
+ );
44
+ }
45
+ });
46
+
47
+ const unlisten = app.listen((location) => {
48
+ listener(location);
49
+
50
+ if (location.pathname === '/') {
51
+ scrollableContainerContentElement = document.createElement('div');
52
+ scrollableContainerContentElement.style.height = '20000px';
53
+ scrollableContainerContentElement.style.width = '20000px';
54
+ container.appendChild(scrollableContainerContentElement);
55
+ } else {
56
+ unregisterScrollableContainer();
57
+ container.removeChild(scrollableContainerContentElement);
58
+ }
59
+ });
60
+
61
+ return () => {
62
+ unlisten();
63
+ document.body.removeChild(container);
64
+ };
65
+ }
66
+
67
+ return {
68
+ ...app,
69
+ container,
70
+ listen,
71
+ };
72
+ }
@@ -13,7 +13,7 @@ describe('InMemorySession', () => {
13
13
  session.start(parseInputLocation('/initial?bar=baz#qux'));
14
14
 
15
15
  expect(location).to.deep.include({
16
- operation: 'INIT',
16
+ operation: 'init',
17
17
  pathname: '/initial',
18
18
  search: '?bar=baz',
19
19
  query: {
@@ -42,21 +42,21 @@ describe('InMemorySession', () => {
42
42
 
43
43
  expect(listener).to.have.been.calledOnce();
44
44
  expect(listener.firstCall.args[0]).to.deep.include({
45
- operation: 'INIT',
45
+ operation: 'init',
46
46
  pathname: '/initial',
47
47
  index: 0,
48
48
  delta: 0,
49
49
  });
50
50
  listener.resetHistory();
51
51
 
52
- session.navigate('PUSH', {
52
+ session.navigate('push', {
53
53
  pathname: '/new',
54
54
  });
55
55
 
56
56
  const newLocation = location;
57
57
 
58
58
  expect(newLocation).to.deep.include({
59
- operation: 'PUSH',
59
+ operation: 'push',
60
60
  pathname: '/new',
61
61
  index: 1,
62
62
  delta: 1,
@@ -65,17 +65,17 @@ describe('InMemorySession', () => {
65
65
 
66
66
  expect(listener).to.have.been.calledOnce();
67
67
  expect(listener.firstCall.args[0]).to.deep.include({
68
- operation: 'PUSH',
68
+ operation: 'push',
69
69
  pathname: '/new',
70
70
  index: 1,
71
71
  delta: 1,
72
72
  });
73
73
  listener.resetHistory();
74
74
 
75
- session.navigate('PUSH', { pathname: '/new-2' });
75
+ session.navigate('push', { pathname: '/new-2' });
76
76
 
77
77
  expect(location).to.include({
78
- operation: 'PUSH',
78
+ operation: 'push',
79
79
  pathname: '/new-2',
80
80
  index: 2,
81
81
  delta: 1,
@@ -83,17 +83,17 @@ describe('InMemorySession', () => {
83
83
 
84
84
  expect(listener).to.have.been.calledOnce();
85
85
  expect(listener.firstCall.args[0]).to.deep.include({
86
- operation: 'PUSH',
86
+ operation: 'push',
87
87
  pathname: '/new-2',
88
88
  index: 2,
89
89
  delta: 1,
90
90
  });
91
91
  listener.resetHistory();
92
92
 
93
- session.navigate('REPLACE', { pathname: '/new-3' });
93
+ session.navigate('replace', { pathname: '/new-3' });
94
94
 
95
95
  expect(location).to.include({
96
- operation: 'REPLACE',
96
+ operation: 'replace',
97
97
  pathname: '/new-3',
98
98
  index: 2,
99
99
  delta: 0,
@@ -101,7 +101,7 @@ describe('InMemorySession', () => {
101
101
 
102
102
  expect(listener).to.have.been.calledOnce();
103
103
  expect(listener.firstCall.args[0]).to.deep.include({
104
- operation: 'REPLACE',
104
+ operation: 'replace',
105
105
  pathname: '/new-3',
106
106
  index: 2,
107
107
  delta: 0,
@@ -112,7 +112,7 @@ describe('InMemorySession', () => {
112
112
 
113
113
  expect(listener).to.have.been.calledOnce();
114
114
  expect(listener.firstCall.args[0]).to.deep.include({
115
- operation: 'SHIFT',
115
+ operation: 'shift',
116
116
  pathname: '/new',
117
117
  key: newLocation.key,
118
118
  index: 1,
@@ -126,8 +126,8 @@ describe('InMemorySession', () => {
126
126
  it('should support subscribing and unsubscribing', () => {
127
127
  const session = new InMemorySession();
128
128
  session.start(parseInputLocation('/initial'));
129
- session.navigate('PUSH', { pathname: '/new' });
130
- session.navigate('PUSH', { pathname: '/new-2' });
129
+ session.navigate('push', { pathname: '/new' });
130
+ session.navigate('push', { pathname: '/new-2' });
131
131
 
132
132
  const listener = sinon.spy();
133
133
  const unsubscribe = session.subscribe(listener);
@@ -136,7 +136,7 @@ describe('InMemorySession', () => {
136
136
 
137
137
  expect(listener).to.have.been.calledOnce();
138
138
  expect(listener.firstCall.args[0]).to.include({
139
- operation: 'SHIFT',
139
+ operation: 'shift',
140
140
  pathname: '/new',
141
141
  });
142
142
  listener.resetHistory();
@@ -153,8 +153,8 @@ describe('InMemorySession', () => {
153
153
  it('should respect stack bounds', () => {
154
154
  const session = new InMemorySession();
155
155
  session.start(parseInputLocation('/initial'));
156
- session.navigate('PUSH', { pathname: '/new' });
157
- session.navigate('PUSH', { pathname: '/new-2' });
156
+ session.navigate('push', { pathname: '/new' });
157
+ session.navigate('push', { pathname: '/new-2' });
158
158
 
159
159
  const listener = sinon.spy();
160
160
  session.subscribe(listener);
@@ -169,7 +169,7 @@ describe('InMemorySession', () => {
169
169
 
170
170
  expect(listener).to.have.been.calledOnce();
171
171
  expect(listener.firstCall.args[0]).to.include({
172
- operation: 'SHIFT',
172
+ operation: 'shift',
173
173
  pathname: '/initial',
174
174
  delta: -2,
175
175
  });
@@ -189,7 +189,7 @@ describe('InMemorySession', () => {
189
189
 
190
190
  expect(listener).to.have.been.calledOnce();
191
191
  expect(listener.firstCall.args[0]).to.include({
192
- operation: 'SHIFT',
192
+ operation: 'shift',
193
193
  pathname: '/new-2',
194
194
  delta: 2,
195
195
  });
@@ -207,10 +207,10 @@ describe('InMemorySession', () => {
207
207
  it('should not reset forward entries on replace', () => {
208
208
  const session = new InMemorySession();
209
209
  session.start(parseInputLocation('/initial'));
210
- session.navigate('PUSH', { pathname: '/new' });
211
- session.navigate('PUSH', { pathname: '/new-2' });
210
+ session.navigate('push', { pathname: '/new' });
211
+ session.navigate('push', { pathname: '/new-2' });
212
212
  session.shift(-2);
213
- session.navigate('REPLACE', { pathname: '/new-3' });
213
+ session.navigate('replace', { pathname: '/new-3' });
214
214
 
215
215
  const listener = sinon.spy();
216
216
  session.subscribe(listener);
@@ -219,7 +219,7 @@ describe('InMemorySession', () => {
219
219
 
220
220
  expect(listener).to.have.been.calledOnce();
221
221
  expect(listener.firstCall.args[0]).to.include({
222
- operation: 'SHIFT',
222
+ operation: 'shift',
223
223
  pathname: '/new',
224
224
  delta: 1,
225
225
  });
@@ -231,10 +231,10 @@ describe('InMemorySession', () => {
231
231
  const session = new InMemorySession();
232
232
 
233
233
  session.start(parseInputLocation('/initial'));
234
- session.navigate('PUSH', { pathname: '/new' });
235
- session.navigate('PUSH', { pathname: '/new-2' });
234
+ session.navigate('push', { pathname: '/new' });
235
+ session.navigate('push', { pathname: '/new-2' });
236
236
  session.shift(-2);
237
- session.navigate('PUSH', { pathname: '/new-3' });
237
+ session.navigate('push', { pathname: '/new-3' });
238
238
 
239
239
  const listener = sinon.spy();
240
240
  session.subscribe(listener);
@@ -297,8 +297,8 @@ describe('InMemorySession', () => {
297
297
  // pathname: '/initial',
298
298
  // });
299
299
  //
300
- // session1._navigation.navigate('PUSH', { pathname: '/new' });
301
- // session1._navigation.navigate('PUSH', { pathname: '/new-2' });
300
+ // session1._navigation.navigate('push', { pathname: '/new' });
301
+ // session1._navigation.navigate('push', { pathname: '/new-2' });
302
302
  // session1._navigation.shift(-1);
303
303
  //
304
304
  // const session2 = new InMemorySession({ save, load });
@@ -13,7 +13,7 @@ describe('ServerSideRenderSession', () => {
13
13
  session.start(parseInputLocation('/foo?bar=baz#qux'));
14
14
 
15
15
  expect(location).to.deep.include({
16
- operation: 'INIT',
16
+ operation: 'init',
17
17
  pathname: '/foo',
18
18
  search: '?bar=baz',
19
19
  query: {