navigation-stack 0.1.3 → 0.2.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 (77) hide show
  1. package/.github/workflows/main.yml +39 -39
  2. package/README.md +128 -27
  3. package/lib/cjs/{LocationStateStorage.js → LocationDataStorage.js} +5 -5
  4. package/lib/cjs/addBeforeLocationChangeListener.js +7 -0
  5. package/lib/cjs/beforeLocationChangeListeners.js +51 -0
  6. package/lib/cjs/createMiddlewares.js +21 -17
  7. package/lib/cjs/index.js +9 -9
  8. package/lib/cjs/middleware/createBasePathMiddleware.js +2 -2
  9. package/lib/cjs/middleware/createBeforeLocationChangeListenerMiddleware.js +39 -0
  10. package/lib/cjs/middleware/{createEnvironmentMiddleware.js → createLocationMiddleware.js} +12 -14
  11. package/lib/cjs/middleware/createNavigationBlockerMiddleware.js +62 -29
  12. package/lib/cjs/middleware/createTransformLocationMiddleware.js +2 -2
  13. package/lib/cjs/navigationBlockers.js +55 -47
  14. package/lib/cjs/normalizeInputLocation.js +1 -0
  15. package/lib/cjs/parseLocationUrl.js +2 -0
  16. package/lib/cjs/parseQueryFromSearch.js +1 -1
  17. package/lib/cjs/session/BrowserSession.js +229 -0
  18. package/lib/cjs/session/MemorySession.js +223 -0
  19. package/lib/cjs/{environment/ServerEnvironment.js → session/ServerSession.js} +28 -16
  20. package/lib/esm/{LocationStateStorage.js → LocationDataStorage.js} +4 -4
  21. package/lib/esm/addBeforeLocationChangeListener.js +2 -0
  22. package/lib/esm/beforeLocationChangeListeners.js +44 -0
  23. package/lib/esm/createMiddlewares.js +21 -17
  24. package/lib/esm/index.js +4 -4
  25. package/lib/esm/middleware/createBasePathMiddleware.js +2 -2
  26. package/lib/esm/middleware/createBeforeLocationChangeListenerMiddleware.js +34 -0
  27. package/lib/esm/middleware/{createEnvironmentMiddleware.js → createLocationMiddleware.js} +11 -13
  28. package/lib/esm/middleware/createNavigationBlockerMiddleware.js +62 -29
  29. package/lib/esm/middleware/createTransformLocationMiddleware.js +2 -2
  30. package/lib/esm/navigationBlockers.js +55 -47
  31. package/lib/esm/normalizeInputLocation.js +1 -0
  32. package/lib/esm/parseLocationUrl.js +2 -0
  33. package/lib/esm/parseQueryFromSearch.js +1 -1
  34. package/lib/esm/session/BrowserSession.js +223 -0
  35. package/lib/esm/session/MemorySession.js +217 -0
  36. package/lib/esm/{environment/ServerEnvironment.js → session/ServerSession.js} +27 -15
  37. package/lib/index.d.ts +64 -59
  38. package/package.json +4 -4
  39. package/src/{LocationStateStorage.js → LocationDataStorage.js} +4 -4
  40. package/src/addBeforeLocationChangeListener.js +2 -0
  41. package/src/beforeLocationChangeListeners.js +54 -0
  42. package/src/createMiddlewares.js +21 -17
  43. package/src/index.js +4 -4
  44. package/src/middleware/createBasePathMiddleware.js +2 -2
  45. package/src/middleware/createBeforeLocationChangeListenerMiddleware.js +40 -0
  46. package/src/middleware/{createEnvironmentMiddleware.js → createLocationMiddleware.js} +12 -14
  47. package/src/middleware/createNavigationBlockerMiddleware.js +68 -28
  48. package/src/middleware/createTransformLocationMiddleware.js +2 -2
  49. package/src/navigationBlockers.js +68 -49
  50. package/src/normalizeInputLocation.js +1 -0
  51. package/src/parseLocationUrl.js +2 -0
  52. package/src/parseQueryFromSearch.js +1 -1
  53. package/src/session/BrowserSession.js +225 -0
  54. package/src/session/MemorySession.js +219 -0
  55. package/src/{environment/ServerEnvironment.js → session/ServerSession.js} +28 -15
  56. package/test/{LocationStateStorage.test.js → LocationDataStorage.test.js} +6 -6
  57. package/test/createMiddlewares.test.js +2 -2
  58. package/test/helpers.js +1 -1
  59. package/test/index.test.js +3 -3
  60. package/test/middleware/createBasePathMiddleware.test.js +7 -7
  61. package/test/middleware/createBeforeLocationChangeListenerMiddleware.test.js +141 -0
  62. package/test/middleware/createNavigationBlockerMiddleware.test.js +96 -97
  63. package/test/middleware/createTransformLocationMiddleware.test.js +1 -1
  64. package/test/normalizeInputLocation.test.js +3 -0
  65. package/test/parseLocationUrl.test.js +2 -0
  66. package/test/{environment/BrowserEnvironment.test.js → session/BrowserSession.test.js} +35 -18
  67. package/test/session/MemorySession.test.js +244 -0
  68. package/test/session/ServerSession.test.js +23 -0
  69. package/types/index.d.ts +64 -59
  70. package/lib/cjs/environment/BrowserEnvironment.js +0 -111
  71. package/lib/cjs/environment/MemoryEnvironment.js +0 -150
  72. package/lib/esm/environment/BrowserEnvironment.js +0 -104
  73. package/lib/esm/environment/MemoryEnvironment.js +0 -143
  74. package/src/environment/BrowserEnvironment.js +0 -109
  75. package/src/environment/MemoryEnvironment.js +0 -151
  76. package/test/environment/MemoryEnvironment.test.js +0 -218
  77. package/test/environment/ServerEnvironment.test.js +0 -23
@@ -0,0 +1,141 @@
1
+ import { applyMiddleware, createStore } from 'redux';
2
+
3
+ import Actions from '../../src/Actions';
4
+ import addBeforeLocationChangeListenerOriginal from '../../src/addBeforeLocationChangeListener';
5
+ import createMiddlewares from '../../src/createMiddlewares';
6
+ import locationReducer from '../../src/locationReducer';
7
+ import MemorySession from '../../src/session/MemorySession';
8
+ import { shouldWarn } from '../helpers';
9
+
10
+ describe('createBeforeLocationChangeListenerMiddleware', () => {
11
+ const sandbox = sinon.createSandbox();
12
+
13
+ let session;
14
+ let store;
15
+
16
+ function addBeforeLocationChangeListener(listener) {
17
+ return addBeforeLocationChangeListenerOriginal(session, listener);
18
+ }
19
+
20
+ beforeEach(() => {
21
+ session = new MemorySession('/foo');
22
+
23
+ store = createStore(
24
+ locationReducer,
25
+ applyMiddleware(...createMiddlewares(session)),
26
+ );
27
+ store.dispatch(Actions.init());
28
+ });
29
+
30
+ afterEach(() => {
31
+ store.dispatch(Actions.dispose());
32
+
33
+ sandbox.restore();
34
+ });
35
+
36
+ describe('PUSH navigations', () => {
37
+ it('should listen to upcoming navigation', () => {
38
+ const listener1 = sinon.stub();
39
+ const listener2 = sinon.stub();
40
+
41
+ addBeforeLocationChangeListener(listener1);
42
+ addBeforeLocationChangeListener(listener2);
43
+
44
+ store.dispatch(Actions.push('/bar'));
45
+ expect(store.getState().pathname).to.equal('/bar');
46
+
47
+ expect(listener1).to.have.been.calledOnce();
48
+
49
+ expect(listener1.firstCall.args[0]).to.include({
50
+ action: 'PUSH',
51
+ pathname: '/bar',
52
+ });
53
+
54
+ expect(listener2).to.have.been.calledOnce();
55
+
56
+ expect(listener2.firstCall.args[0]).to.include({
57
+ action: 'PUSH',
58
+ pathname: '/bar',
59
+ });
60
+ });
61
+
62
+ it('should warn on and ignore listeners that throw', () => {
63
+ shouldWarn(
64
+ 'Ignoring before location change listener `syncListener` that failed with `Error: foo`.',
65
+ );
66
+
67
+ const syncListener = () => {
68
+ throw new Error('foo');
69
+ };
70
+
71
+ addBeforeLocationChangeListener(syncListener);
72
+
73
+ store.dispatch(Actions.push('/bar'));
74
+ expect(store.getState().pathname).to.equal('/bar');
75
+ });
76
+
77
+ it('should allow removing listeners', () => {
78
+ const listener = sinon.stub();
79
+
80
+ const removeNavigationListener =
81
+ addBeforeLocationChangeListener(listener);
82
+
83
+ store.dispatch(Actions.push('/bar-1'));
84
+ expect(store.getState().pathname).to.equal('/bar-1');
85
+
86
+ expect(listener).to.have.been.calledOnce();
87
+
88
+ removeNavigationListener();
89
+
90
+ store.dispatch(Actions.push('/bar-2'));
91
+ expect(store.getState().pathname).to.equal('/bar-2');
92
+
93
+ expect(listener).to.have.been.calledOnce();
94
+ });
95
+ });
96
+
97
+ describe('POP navigations', () => {
98
+ beforeEach(() => {
99
+ store.dispatch(Actions.push('/bar'));
100
+ });
101
+
102
+ it('should listen to upcoming navigation', () => {
103
+ const listener = sinon.stub();
104
+ addBeforeLocationChangeListener(listener);
105
+
106
+ store.dispatch(Actions.shift(-1));
107
+ expect(store.getState().pathname).to.equal('/foo');
108
+
109
+ expect(listener).to.have.been.calledOnce();
110
+
111
+ expect(listener.firstCall.args[0]).to.include({
112
+ action: 'POP',
113
+ pathname: '/foo',
114
+ delta: -1,
115
+ });
116
+ });
117
+ });
118
+
119
+ describe('INIT', () => {
120
+ it('should ignore to the initial load', () => {
121
+ // Get rid of the old store. We'll replace it with a new one.
122
+ store.dispatch(Actions.dispose());
123
+
124
+ store = createStore(
125
+ locationReducer,
126
+ applyMiddleware(...createMiddlewares(new MemorySession('/foo'))),
127
+ );
128
+
129
+ const listener = sinon.stub();
130
+ addBeforeLocationChangeListener(listener);
131
+
132
+ expect(listener).to.not.have.been.called();
133
+
134
+ expect(store.getState()).to.be.undefined();
135
+ store.dispatch(Actions.init());
136
+ expect(store.getState().pathname).to.equal('/foo');
137
+
138
+ expect(listener).to.not.have.been.called();
139
+ });
140
+ });
141
+ });
@@ -5,31 +5,31 @@ import { applyMiddleware, createStore } from 'redux';
5
5
  import Actions from '../../src/Actions';
6
6
  import addNavigationBlockerOriginal from '../../src/addNavigationBlocker';
7
7
  import createMiddlewares from '../../src/createMiddlewares';
8
- import MemoryEnvironment from '../../src/environment/MemoryEnvironment';
9
8
  import locationReducer from '../../src/locationReducer';
9
+ import MemorySession from '../../src/session/MemorySession';
10
10
  import { shouldWarn } from '../helpers';
11
11
 
12
12
  describe('createNavigationBlockerMiddleware', () => {
13
13
  const sandbox = sinon.createSandbox();
14
14
 
15
- let environment;
15
+ let session;
16
16
  let store;
17
17
 
18
- function addNavigationBlocker(listener) {
19
- return addNavigationBlockerOriginal(environment, listener);
18
+ function addNavigationBlocker(blocker) {
19
+ return addNavigationBlockerOriginal(session, blocker);
20
20
  }
21
21
 
22
22
  beforeEach(() => {
23
- environment = new MemoryEnvironment('/foo');
23
+ session = new MemorySession('/foo');
24
24
 
25
25
  store = createStore(
26
26
  locationReducer,
27
- applyMiddleware(...createMiddlewares(environment)),
27
+ applyMiddleware(...createMiddlewares(session)),
28
28
  );
29
29
  store.dispatch(Actions.init());
30
30
 
31
- sinon.spy(environment, 'addBeforeDestroyListener');
32
- sinon.spy(environment, '_removeBeforeDestroyListener');
31
+ sinon.spy(session, 'addBeforeDestroyListener');
32
+ // sinon.spy(session, '_removeBeforeDestroyListener');
33
33
  });
34
34
 
35
35
  afterEach(() => {
@@ -40,13 +40,15 @@ describe('createNavigationBlockerMiddleware', () => {
40
40
 
41
41
  describe('PUSH navigations', () => {
42
42
  it('should block navigation when blocker returns `true`', () => {
43
- const listener = sinon.stub().returns(true);
44
- addNavigationBlocker(listener);
43
+ const blocker = sinon.stub().returns(true);
44
+ addNavigationBlocker(blocker);
45
45
 
46
46
  store.dispatch(Actions.push('/bar'));
47
47
  expect(store.getState().pathname).to.equal('/foo');
48
48
 
49
- expect(listener.firstCall.args[0]).to.include({
49
+ expect(blocker).to.have.been.calledOnce();
50
+
51
+ expect(blocker.firstCall.args[0]).to.include({
50
52
  action: 'PUSH',
51
53
  pathname: '/bar',
52
54
  });
@@ -60,43 +62,43 @@ describe('createNavigationBlockerMiddleware', () => {
60
62
  });
61
63
 
62
64
  it("should fall through when first blocker doesn't return `true`", () => {
63
- const listener1 = sinon.stub().returns(undefined);
64
- const listener2 = sinon.stub().returns(true);
65
+ const blocker1 = sinon.stub().returns(undefined);
66
+ const blocker2 = sinon.stub().returns(true);
65
67
 
66
- addNavigationBlocker(listener1);
67
- addNavigationBlocker(listener2);
68
+ addNavigationBlocker(blocker1);
69
+ addNavigationBlocker(blocker2);
68
70
 
69
71
  store.dispatch(Actions.push('/bar'));
70
72
  expect(store.getState().pathname).to.equal('/foo');
71
73
 
72
- expect(listener1).to.have.been.calledOnce();
73
- expect(listener2).to.have.been.calledOnce();
74
+ expect(blocker1).to.have.been.calledOnce();
75
+ expect(blocker2).to.have.been.calledOnce();
74
76
  });
75
77
 
76
78
  it('should not fall through when first blocker returns `true`', () => {
77
- const listener1 = sinon.stub().returns(true);
78
- const listener2 = sinon.stub().returns(undefined);
79
+ const blocker1 = sinon.stub().returns(true);
80
+ const blocker2 = sinon.stub().returns(undefined);
79
81
 
80
- addNavigationBlocker(listener1);
81
- addNavigationBlocker(listener2);
82
+ addNavigationBlocker(blocker1);
83
+ addNavigationBlocker(blocker2);
82
84
 
83
85
  store.dispatch(Actions.push('/bar'));
84
86
  expect(store.getState().pathname).to.equal('/foo');
85
87
 
86
- expect(listener1).to.have.been.calledOnce();
87
- expect(listener2).not.to.have.been.called();
88
+ expect(blocker1).to.have.been.calledOnce();
89
+ expect(blocker2).not.to.have.been.called();
88
90
  });
89
91
 
90
- it('should warn on and ignore listeners that throw', () => {
92
+ it('should warn on and ignore blockers that throw', () => {
91
93
  shouldWarn(
92
- 'Ignoring navigation blocker `syncListener` that failed with `Error: foo`.',
94
+ 'Ignoring navigation blocker `syncblocker` that failed with `Error: foo`.',
93
95
  );
94
96
 
95
- const syncListener = () => {
97
+ const syncblocker = () => {
96
98
  throw new Error('foo');
97
99
  };
98
100
 
99
- addNavigationBlocker(syncListener);
101
+ addNavigationBlocker(syncblocker);
100
102
 
101
103
  store.dispatch(Actions.push('/bar'));
102
104
  expect(store.getState().pathname).to.equal('/bar');
@@ -177,15 +179,15 @@ describe('createNavigationBlockerMiddleware', () => {
177
179
 
178
180
  it('should warn on and ignore async blockers that throw an error', async () => {
179
181
  shouldWarn(
180
- 'Ignoring navigation blocker `asyncListener` that failed with `Error: foo`.',
182
+ 'Ignoring navigation blocker `asyncblocker` that failed with `Error: foo`.',
181
183
  );
182
184
 
183
185
  // eslint-disable-next-line require-await
184
- const asyncListener = async () => {
186
+ const asyncblocker = async () => {
185
187
  throw new Error('foo');
186
188
  };
187
189
 
188
- addNavigationBlocker(asyncListener);
190
+ addNavigationBlocker(asyncblocker);
189
191
 
190
192
  store.dispatch(Actions.push('/bar'));
191
193
  expect(store.getState().pathname).to.equal('/foo');
@@ -195,13 +197,13 @@ describe('createNavigationBlockerMiddleware', () => {
195
197
  expect(store.getState().pathname).to.equal('/bar');
196
198
  });
197
199
 
198
- it('should allow removing listeners', () => {
199
- const removeNavigationListener = addNavigationBlocker(() => true);
200
+ it('should allow removing blockers', () => {
201
+ const removeNavigationBlocker = addNavigationBlocker(() => true);
200
202
 
201
203
  store.dispatch(Actions.push('/bar'));
202
204
  expect(store.getState().pathname).to.equal('/foo');
203
205
 
204
- removeNavigationListener();
206
+ removeNavigationBlocker();
205
207
 
206
208
  store.dispatch(Actions.push('/bar'));
207
209
  expect(store.getState().pathname).to.equal('/bar');
@@ -214,13 +216,13 @@ describe('createNavigationBlockerMiddleware', () => {
214
216
  });
215
217
 
216
218
  it('should allow navigation when blocker returns `undefined`', () => {
217
- const listener = sinon.stub().returns(undefined);
218
- addNavigationBlocker(listener);
219
+ const blocker = sinon.stub().returns(undefined);
220
+ addNavigationBlocker(blocker);
219
221
 
220
222
  store.dispatch(Actions.shift(-1));
221
223
  expect(store.getState().pathname).to.equal('/foo');
222
224
 
223
- expect(listener.firstCall.args[0]).to.include({
225
+ expect(blocker.firstCall.args[0]).to.include({
224
226
  action: 'POP',
225
227
  pathname: '/foo',
226
228
  delta: -1,
@@ -279,7 +281,7 @@ describe('createNavigationBlockerMiddleware', () => {
279
281
 
280
282
  store = createStore(
281
283
  locationReducer,
282
- applyMiddleware(...createMiddlewares(new MemoryEnvironment('/foo'))),
284
+ applyMiddleware(...createMiddlewares(new MemorySession('/foo'))),
283
285
  );
284
286
  addNavigationBlocker(() => true);
285
287
 
@@ -290,16 +292,16 @@ describe('createNavigationBlockerMiddleware', () => {
290
292
 
291
293
  it('should support async rewinding', async () => {
292
294
  // eslint-disable-next-line no-underscore-dangle
293
- const listener = environment._listener;
295
+ const blocker = session.navigation._subscriptionListener;
294
296
 
295
- let environmentDeferred;
297
+ let sessionDeferred;
296
298
 
297
299
  // eslint-disable-next-line no-underscore-dangle
298
- environment._listener = async (location) => {
299
- environmentDeferred = pDefer();
300
- await environmentDeferred.promise;
300
+ session.navigation._subscriptionListener = async (location) => {
301
+ sessionDeferred = pDefer();
302
+ await sessionDeferred.promise;
301
303
 
302
- listener(location);
304
+ blocker(location);
303
305
  };
304
306
 
305
307
  const deferred = pDefer();
@@ -307,25 +309,25 @@ describe('createNavigationBlockerMiddleware', () => {
307
309
 
308
310
  store.dispatch(Actions.shift(-1));
309
311
 
310
- // Environment popped, update to store blocked.
311
- expect(environment.init().pathname).to.equal('/foo');
312
+ // session popped, update to store blocked.
313
+ expect(session.navigation.init().pathname).to.equal('/foo');
312
314
  expect(store.getState().pathname).to.equal('/bar');
313
315
 
314
- environmentDeferred.resolve();
316
+ sessionDeferred.resolve();
315
317
  await delay(10);
316
318
 
317
- // Environment rewinded.
318
- expect(environment.init().pathname).to.equal('/bar');
319
+ // session rewinded.
320
+ expect(session.navigation.init().pathname).to.equal('/bar');
319
321
  expect(store.getState().pathname).to.equal('/bar');
320
322
 
321
323
  deferred.resolve(undefined);
322
324
  await delay(10);
323
325
 
324
- environmentDeferred.resolve();
326
+ sessionDeferred.resolve();
325
327
  await delay(10);
326
328
 
327
- // Environment re-popped, update to store delayed.
328
- expect(environment.init().pathname).to.equal('/foo');
329
+ // session re-popped, update to store delayed.
330
+ expect(session.navigation.init().pathname).to.equal('/foo');
329
331
  expect(store.getState().pathname).to.equal('/foo');
330
332
  });
331
333
 
@@ -335,16 +337,16 @@ describe('createNavigationBlockerMiddleware', () => {
335
337
 
336
338
  // Update location with a `POP` action.
337
339
  /* eslint-disable no-underscore-dangle */
338
- environment._index = 0;
339
- environment._listener(environment.init(null));
340
+ session.navigation._index = 0;
341
+ session.navigation._subscriptionListener(session.navigation.init(null));
340
342
  /* eslint-enable no-underscore-dangle */
341
343
 
342
344
  deferred.resolve(undefined);
343
345
  await delay(10);
344
346
 
345
- // Without delta, we can't rewind on the environment,
347
+ // Without delta, we can't rewind on the session,
346
348
  // so navigation is allowed without calling any blockers.
347
- expect(environment.init().pathname).to.equal('/foo');
349
+ expect(session.navigation.init().pathname).to.equal('/foo');
348
350
  expect(store.getState().pathname).to.equal('/foo');
349
351
  });
350
352
 
@@ -354,18 +356,18 @@ describe('createNavigationBlockerMiddleware', () => {
354
356
  //
355
357
  // // Update location with a `POP` action.
356
358
  // /* eslint-disable no-underscore-dangle */
357
- // environment._index = 0;
358
- // environment._listener(environment.init(null));
359
+ // session.navigation._index = 0;
360
+ // session.navigation._subscriptionListener(session.navigation.init(null));
359
361
  // /* eslint-enable no-underscore-dangle */
360
362
  //
361
- // // Without delta, we can't rewind on the environment.
362
- // expect(environment.init().pathname).to.equal('/foo');
363
+ // // Without delta, we can't rewind on the session.
364
+ // expect(session.navigation.init().pathname).to.equal('/foo');
363
365
  // expect(store.getState().pathname).to.equal('/bar');
364
366
  //
365
367
  // deferred.resolve(undefined);
366
368
  // await delay(10);
367
369
  //
368
- // expect(environment.init().pathname).to.equal('/foo');
370
+ // expect(session.navigation.init().pathname).to.equal('/foo');
369
371
  // expect(store.getState().pathname).to.equal('/foo');
370
372
  // });
371
373
 
@@ -374,18 +376,18 @@ describe('createNavigationBlockerMiddleware', () => {
374
376
  // addNavigationBlocker(() => deferred.promise);
375
377
  //
376
378
  // /* eslint-disable no-underscore-dangle */
377
- // environment._index = 0;
378
- // environment._listener(environment.init(null));
379
+ // session.navigation._index = 0;
380
+ // session.navigation._subscriptionListener(session.navigation.init(null));
379
381
  // /* eslint-enable no-underscore-dangle */
380
382
  //
381
- // expect(environment.init().pathname).to.equal('/foo');
383
+ // expect(session.navigation.init().pathname).to.equal('/foo');
382
384
  // expect(store.getState().pathname).to.equal('/bar');
383
385
  //
384
386
  // deferred.resolve(true);
385
387
  // await delay(10);
386
388
  //
387
389
  // // These are out-of-sync now, but it's the best we can do.
388
- // expect(environment.init().pathname).to.equal('/foo');
390
+ // expect(session.navigation.init().pathname).to.equal('/foo');
389
391
  // expect(store.getState().pathname).to.equal('/bar');
390
392
  // });
391
393
  });
@@ -400,73 +402,70 @@ describe('createNavigationBlockerMiddleware', () => {
400
402
 
401
403
  store = createStore(
402
404
  () => null,
403
- applyMiddleware(...createMiddlewares(environment)),
405
+ applyMiddleware(...createMiddlewares(session)),
404
406
  );
405
407
 
406
408
  store.dispatch(Actions.init());
407
409
  });
408
410
 
409
- it('should manage event listener', () => {
410
- expect(environment.addBeforeDestroyListener).not.to.have.been.called();
411
+ it('should manage event blocker', () => {
412
+ expect(session.addBeforeDestroyListener).not.to.have.been.called();
411
413
  // expect(window.addEventListener).not.to.have.been.called();
412
414
 
413
- const removeNavigationListener1 = addNavigationBlocker(() => null, {
415
+ const removeNavigationBlocker1 = addNavigationBlocker(() => null, {
414
416
  beforeUnload: true,
415
417
  });
416
- expect(environment.addBeforeDestroyListener).to.have.been.calledOnce();
418
+ expect(session.addBeforeDestroyListener).to.have.been.calledOnce();
417
419
  // expect(window.addEventListener)
418
420
  // .to.have.been.calledOnce()
419
421
  // .and.to.have.been.called.with('beforeunload');
420
422
 
421
- const removeNavigationListener2 = addNavigationBlocker(() => null, {
423
+ const removeNavigationBlocker2 = addNavigationBlocker(() => null, {
422
424
  beforeUnload: true,
423
425
  });
424
- expect(environment.addBeforeDestroyListener).to.have.been.calledOnce();
426
+ expect(session.addBeforeDestroyListener).to.have.been.calledOnce();
425
427
  // expect(window.addEventListener)
426
428
  // .to.have.been.calledOnce()
427
429
  // .and.to.have.been.called.with('beforeunload');
428
430
 
429
- removeNavigationListener1();
431
+ const removeBeforeDestroyListener = sinon.stub();
432
+ // eslint-disable-next-line no-underscore-dangle
433
+ session._removeBeforeDestroyListener = removeBeforeDestroyListener;
434
+
435
+ removeNavigationBlocker1();
430
436
  // expect(window.removeEventListener).not.to.have.been.called();
431
- expect(
432
- // eslint-disable-next-line no-underscore-dangle
433
- environment._removeBeforeDestroyListener,
434
- ).not.to.have.been.called();
437
+ expect(removeBeforeDestroyListener).not.to.have.been.called();
435
438
 
436
- removeNavigationListener2();
439
+ removeNavigationBlocker2();
437
440
  // expect(window.removeEventListener)
438
441
  // .to.have.been.calledOnce()
439
442
  // .and.to.have.been.called.with('beforeunload');
440
- expect(
441
- // eslint-disable-next-line no-underscore-dangle
442
- environment._removeBeforeDestroyListener,
443
- ).to.have.been.calledOnce();
443
+ expect(removeBeforeDestroyListener).to.have.been.calledOnce();
444
444
  });
445
445
 
446
- it('should remove event listener on dispose', () => {
446
+ it('should remove event blocker on dispose', () => {
447
447
  addNavigationBlocker(() => null, { beforeUnload: true });
448
+
449
+ const removeBeforeDestroyListener = sinon.stub();
450
+ // eslint-disable-next-line no-underscore-dangle
451
+ session._removeBeforeDestroyListener = removeBeforeDestroyListener;
452
+
448
453
  // expect(window.removeEventListener).not.to.have.been.called();
449
- expect(
450
- // eslint-disable-next-line no-underscore-dangle
451
- environment._removeBeforeDestroyListener,
452
- ).not.to.have.been.called();
454
+ expect(removeBeforeDestroyListener).not.to.have.been.called();
453
455
 
454
456
  store.dispatch(Actions.dispose());
455
457
  // expect(window.removeEventListener)
456
458
  // .to.have.been.calledOnce()
457
459
  // .and.to.have.been.called.with('beforeunload');
458
- expect(
459
- // eslint-disable-next-line no-underscore-dangle
460
- environment._removeBeforeDestroyListener,
461
- ).to.have.been.calledOnce();
460
+ expect(removeBeforeDestroyListener).to.have.been.calledOnce();
462
461
  });
463
462
 
464
- it('should not add event listener without beforeUnload', () => {
465
- const removeNavigationListener = addNavigationBlocker(() => null);
466
- expect(window.addEventListener).not.to.have.been.called();
467
-
468
- removeNavigationListener();
469
- expect(window.removeEventListener).not.to.have.been.called();
470
- });
463
+ // it('should not add a global "before destroy" listener when no `beforeDestroy` blocker has been added', () => {
464
+ // const removeNavigationBlocker = addNavigationBlocker(() => null);
465
+ // expect(window.addEventListener).not.to.have.been.called();
466
+ //
467
+ // removeNavigationBlocker();
468
+ // expect(window.removeEventListener).not.to.have.been.called();
469
+ // });
471
470
  });
472
471
  });
@@ -4,7 +4,7 @@ import createTransformLocationMiddleware from '../../src/middleware/createTransf
4
4
  describe('createTransformLocationMiddleware', () => {
5
5
  const middleware = createTransformLocationMiddleware({
6
6
  transformInputLocation: (locationInput) => ({ locationInput }),
7
- transformEnvironmentLocation: (location) => ({ location }),
7
+ transformSubscriptionLocation: (location) => ({ location }),
8
8
  });
9
9
 
10
10
  const dispatch = middleware()((action) => action.payload);
@@ -26,6 +26,7 @@ describe('normalizeInputLocation', () => {
26
26
  ).to.eql({
27
27
  pathname: '/new/pathname',
28
28
  search: '',
29
+ query: {},
29
30
  hash: '',
30
31
  });
31
32
  });
@@ -34,6 +35,7 @@ describe('normalizeInputLocation', () => {
34
35
  expect(normalizeInputLocation('/foo')).to.eql({
35
36
  pathname: '/foo',
36
37
  search: '',
38
+ query: {},
37
39
  hash: '',
38
40
  });
39
41
 
@@ -49,6 +51,7 @@ describe('normalizeInputLocation', () => {
49
51
  expect(normalizeInputLocation('/foo#qux')).to.eql({
50
52
  pathname: '/foo',
51
53
  search: '',
54
+ query: {},
52
55
  hash: '#qux',
53
56
  });
54
57
 
@@ -16,6 +16,7 @@ describe('parseLocationUrl', () => {
16
16
  expect(parseLocationUrl('/foo?#qux')).to.deep.equal({
17
17
  pathname: '/foo',
18
18
  search: '?',
19
+ query: {},
19
20
  hash: '#qux',
20
21
  });
21
22
  });
@@ -24,6 +25,7 @@ describe('parseLocationUrl', () => {
24
25
  expect(parseLocationUrl('/foo')).to.deep.equal({
25
26
  pathname: '/foo',
26
27
  search: '',
28
+ query: {},
27
29
  hash: '',
28
30
  });
29
31
  });