navigation-stack 0.1.2 → 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 +66 -61
  38. package/package.json +5 -5
  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,225 @@
1
+ /* eslint-disable max-classes-per-file */
2
+
3
+ import getLocationUrl from '../getLocationUrl';
4
+ import parseQueryFromSearch from '../parseQueryFromSearch';
5
+
6
+ const INITIAL_KEY_INDEX = -1;
7
+ const INITIAL_INDEX = -1;
8
+
9
+ const INIT_LOCATION_DELTA = 0;
10
+
11
+ // A web browser has a notion of a "navigation history".
12
+ // A "navigation history" exists within a given web browser's tab.
13
+ // The user can click "Back" or "Forward" buttons in the web browser and it will automatically load
14
+ // "previous" or "next" page from scratch.
15
+ //
16
+ // Later, web browsers added a `window.history` object that the application can,
17
+ // but isn't required to, interact with. That `window.history` object allows the application
18
+ // to programmatically control the URL in the address bar of the web browser, as well as
19
+ // the "navigation history" by programmatically adding new entries to it or reading the current entry,
20
+ // and it also allows the application to override the default web browser's behavior
21
+ // when the user clicks "Back" or "Forward" buttons in the web browser.
22
+ //
23
+ // Specifically, the `window.history` object has a method called `.pushState()` which programmatically adds
24
+ // a new entry in the "navigation history" and updates the URL in the address bar and also
25
+ // tells the web browser that starting from the entry before this new entry in the "navigation history",
26
+ // the application would prefer to manually handle any "Back"/"Forward" transition when the user clicks
27
+ // those "Back" or "Forward" buttons in the web browser, and this behavior should persist for any future
28
+ // "navigation history" entries programmatically added by the application via `window.history.pushState()`,
29
+ // and will only stop if the user navigates from the page by the means of conventional navigation,
30
+ // that is by clicking a standard hyperlink, at which point the current page gets "destroyed".
31
+ //
32
+ // So for manually "pushed" entries of the "navigation history", the web browser won't load those pages
33
+ // from scratch after a user-initiated "Back" or "Forward" transition. In fact, it won't do anything and
34
+ // it will just step aside and let the application itself do those transitions. The web browser will only
35
+ // update the URL in the address bar and that's it.
36
+ //
37
+ // This whole thing allows the application to:
38
+ //
39
+ // * Load the "previous" or "next" page much faster than when using the default "from scratch" approach
40
+ // because it doesn't have to destroy the current page, then send a new HTTP request to the server,
41
+ // then parse the HTML response and initialize a new page, re-download all those images, etc.
42
+ //
43
+ // * Optionally render a snapshotted verison of the "previous" page thereby "restoring" the "previous" page
44
+ // rather than reloading it from scratch, i.e. the state of the "previous" page could be fully restored.
45
+ //
46
+ class BrowserNavigation {
47
+ constructor() {
48
+ // `this._keyPrefix` exists to avoid `this._keyIndex` collision after a page refresh.
49
+ // After a page refresh, `this._keyIndex` is reset to `0` while the previous navigation history
50
+ // still exists because web browser navigation history survives a page reload.
51
+ this._keyPrefix = Date.now().toString(36);
52
+ // `this._keyIndex` is incremented every time the current location changes.
53
+ this._keyIndex = INITIAL_KEY_INDEX;
54
+
55
+ // `this._index` is the index of the top element in the navigation stack.
56
+ // I.e. it's the index of the "current" location in the navigation stack.
57
+ this._index = INITIAL_INDEX;
58
+ }
59
+
60
+ init() {
61
+ return this._createEntryFromCurrentLocation();
62
+ }
63
+
64
+ _createEntryFromCurrentLocation() {
65
+ const { pathname, search, hash } = window.location;
66
+
67
+ const isSettingInitialLocation = this._index === INITIAL_INDEX;
68
+
69
+ const { key, index, delta, state } = isSettingInitialLocation
70
+ ? this._createAdditionalPropertiesForNewLocation({
71
+ delta: 1,
72
+ state: undefined,
73
+ })
74
+ : this._restoreAdditionalPropertiesForCurrentLocation();
75
+
76
+ return {
77
+ action: isSettingInitialLocation ? 'INIT' : 'POP',
78
+ pathname,
79
+ search,
80
+ query: parseQueryFromSearch(search),
81
+ hash,
82
+ key,
83
+ index,
84
+ delta: isSettingInitialLocation ? INIT_LOCATION_DELTA : delta,
85
+ state,
86
+ };
87
+ }
88
+
89
+ // Subscribes to changes in location,
90
+ // excluding ones that happened as a result of calling `.navigate()`.
91
+ subscribe(listener) {
92
+ const onPopState = () => {
93
+ listener(this._createEntryFromCurrentLocation());
94
+ };
95
+
96
+ window.addEventListener('popstate', onPopState);
97
+ return () => {
98
+ window.removeEventListener('popstate', onPopState);
99
+ };
100
+ }
101
+
102
+ navigate(location) {
103
+ const { action, state } = location;
104
+
105
+ if (action !== 'PUSH' && action !== 'REPLACE') {
106
+ throw Error(`Unrecognized browser session action: ${action}`);
107
+ }
108
+
109
+ if (this._index === INITIAL_INDEX) {
110
+ throw Error('Browser session must be initialized before navigation');
111
+ }
112
+
113
+ const delta = action === 'PUSH' ? 1 : 0;
114
+
115
+ const additionalProperties =
116
+ this._createAdditionalPropertiesForNewLocation({ delta, state });
117
+
118
+ this._storeAdditionalPropertiesForLocation(location, additionalProperties);
119
+
120
+ return { ...location, ...additionalProperties };
121
+ }
122
+
123
+ shift(delta) {
124
+ window.history.go(delta);
125
+ }
126
+
127
+ _createKeyForKeyIndex(keyIndex) {
128
+ return `${this._keyPrefix}.${keyIndex.toString(36)}`;
129
+ }
130
+
131
+ _createAdditionalPropertiesForNewLocation({ delta, state }) {
132
+ this._keyIndex++;
133
+ this._index += delta;
134
+
135
+ return {
136
+ key: this._createKeyForKeyIndex(this._keyIndex),
137
+ index: this._index,
138
+ delta,
139
+ state,
140
+ };
141
+ }
142
+
143
+ _restoreAdditionalPropertiesForCurrentLocation() {
144
+ // Initial location doesn't have any `window.history.state` assigned to it
145
+ // because it wasn't navigated to via a `window.history.pushState()` method.
146
+ // Because of that, the additional properties for the initial location can't be read
147
+ // from `window.history.state` and have to be reconstructed manually.
148
+ const { key, index, state } =
149
+ window.history.state ||
150
+ this._getAdditionalPropertiesForInitialLocation();
151
+ const delta = index - this._index;
152
+ this._index = index;
153
+ return { key, index, delta, state };
154
+ }
155
+
156
+ _storeAdditionalPropertiesForLocation(location, additionalProperties) {
157
+ const url = getLocationUrl(location);
158
+ // `delta` property is not stored in `window.history.state`
159
+ // because it is supposed to be recalculated every time when reading from `window.history.state`.
160
+ const { delta, ...restProperties } = additionalProperties;
161
+ if (delta === 1) {
162
+ window.history.pushState(restProperties, null, url);
163
+ } else if (delta === 0) {
164
+ window.history.replaceState(restProperties, null, url);
165
+ } else {
166
+ throw new Error(
167
+ `Unexpected \`delta\` when storing additional properties for location: ${delta}`,
168
+ );
169
+ }
170
+ }
171
+
172
+ // Initial location doesn't have any `window.history.state` assigned to it
173
+ // because it wasn't navigated to via a `window.history.pushState()` method.
174
+ // Because of that, the additional properties for the initial location can't be read
175
+ // from `window.history.state` and have to be reconstructed manually.
176
+ _getAdditionalPropertiesForInitialLocation() {
177
+ return {
178
+ key: this._createKeyForKeyIndex(INITIAL_KEY_INDEX + 1),
179
+ index: INITIAL_INDEX + 1,
180
+ delta: INIT_LOCATION_DELTA,
181
+ state: undefined,
182
+ };
183
+ }
184
+ }
185
+
186
+ class BrowserDataStorage {
187
+ // Returns either a `string` value or `null` if the key doesn't exist.
188
+ get(key) {
189
+ // `sessionStorage` persists across page reloads, and so does web browser navigation history.
190
+ return window.sessionStorage.getItem(key);
191
+ }
192
+
193
+ remove(key) {
194
+ // `sessionStorage` persists across page reloads, and so does web browser navigation history.
195
+ window.sessionStorage.removeItem(key);
196
+ }
197
+
198
+ set(key, value) {
199
+ // `sessionStorage` persists across page reloads, and so does web browser navigation history.
200
+ window.sessionStorage.setItem(key, value);
201
+ }
202
+ }
203
+
204
+ export default class BrowserSession {
205
+ constructor() {
206
+ this.navigation = new BrowserNavigation();
207
+ this.dataStorage = new BrowserDataStorage();
208
+ }
209
+
210
+ addBeforeDestroyListener(onBeforeDestroy) {
211
+ const onBeforeUnload = (event) => {
212
+ if (onBeforeDestroy()) {
213
+ // Calling `event.preventDefault()` will cause a web browser
214
+ // to show a generic "Ok"/"Cancel" modal with some generic text:
215
+ // "Are you sure to leave the current page?".
216
+ event.preventDefault();
217
+ }
218
+ };
219
+
220
+ window.addEventListener('beforeunload', onBeforeUnload);
221
+ return () => {
222
+ window.removeEventListener('beforeunload', onBeforeUnload);
223
+ };
224
+ }
225
+ }
@@ -0,0 +1,219 @@
1
+ /* eslint-disable max-classes-per-file */
2
+
3
+ import normalizeInputLocation from '../normalizeInputLocation';
4
+
5
+ // eslint-disable-next-line no-underscore-dangle
6
+ function _loadState(load, isValidLoadedData) {
7
+ try {
8
+ const data = JSON.parse(load());
9
+
10
+ // Check that the stack and index at least seem reasonable before using
11
+ // them as state. This isn't foolproof, but it might prevent mistakes.
12
+ // Also perform a basic validation of `state`.
13
+ if (isValidLoadedData(data)) {
14
+ return data;
15
+ }
16
+ } catch (error) {} // eslint-disable-line no-empty
17
+
18
+ return null;
19
+ }
20
+
21
+ // eslint-disable-next-line no-underscore-dangle
22
+ function _saveState(save, data) {
23
+ try {
24
+ save(JSON.stringify(data));
25
+ } catch (error) {} // eslint-disable-line no-empty
26
+ }
27
+
28
+ class MemoryNavigation {
29
+ constructor(initialLocation, { save, load } = {}) {
30
+ this._save = save;
31
+
32
+ this._keyPrefix = Date.now().toString(36);
33
+ this._keyIndex = 0;
34
+
35
+ this._subscriptionListener = null;
36
+
37
+ const initialState = load
38
+ ? _loadState(load, this._isValidLoadedData)
39
+ : null;
40
+ if (initialState) {
41
+ this._stack = initialState.stack;
42
+ this._index = initialState.index;
43
+ } else {
44
+ this._stack = [
45
+ {
46
+ ...normalizeInputLocation(initialLocation),
47
+ key: this._getNextKey(),
48
+ },
49
+ ];
50
+ this._index = 0;
51
+ }
52
+ }
53
+
54
+ _isValidLoadedData({ stack, index }) {
55
+ // Check that the `stack` and `index` at least seem reasonable before using them.
56
+ // This isn't foolproof, but it might prevent mistakes.
57
+ return Array.isArray(stack) && typeof index === 'number' && stack[index];
58
+ }
59
+
60
+ init() {
61
+ return this._createLocationObject({ action: 'INIT', delta: 0 });
62
+ }
63
+
64
+ subscribe(listener) {
65
+ this._subscriptionListener = listener;
66
+
67
+ return () => {
68
+ this._subscriptionListener = null;
69
+ };
70
+ }
71
+
72
+ navigate(location) {
73
+ const { action, pathname, search, query, hash, state } = location;
74
+
75
+ if (action !== 'PUSH' && action !== 'REPLACE') {
76
+ throw Error(`Unrecognized browser session action: ${action}`);
77
+ }
78
+
79
+ const delta = action === 'PUSH' ? 1 : 0;
80
+ this._index += delta;
81
+
82
+ const key = this._getNextKey();
83
+
84
+ this._stack[this._index] = { pathname, search, query, hash, state, key };
85
+ if (action === 'PUSH') {
86
+ this._stack.length = this._index + 1;
87
+ }
88
+
89
+ if (this._save) {
90
+ _saveState(this._save, {
91
+ stack: this._stack,
92
+ index: this._index,
93
+ });
94
+ }
95
+
96
+ return { ...location, key, index: this._index, delta };
97
+ }
98
+
99
+ shift(delta) {
100
+ const prevIndex = this._index;
101
+
102
+ this._index = Math.min(
103
+ Math.max(this._index + delta, 0),
104
+ this._stack.length - 1,
105
+ );
106
+
107
+ if (this._index === prevIndex) {
108
+ return;
109
+ }
110
+
111
+ if (this._save) {
112
+ _saveState(this._save, {
113
+ stack: this._stack,
114
+ index: this._index,
115
+ });
116
+ }
117
+
118
+ if (this._subscriptionListener) {
119
+ this._subscriptionListener(
120
+ this._createLocationObject({
121
+ action: 'POP',
122
+ delta: this._index - prevIndex,
123
+ }),
124
+ );
125
+ }
126
+ }
127
+
128
+ _getNextKey() {
129
+ const key = `${this._keyPrefix}.${this._keyIndex.toString(36)}`;
130
+ this._keyIndex++;
131
+ return key;
132
+ }
133
+
134
+ _createLocationObject({ action, delta }) {
135
+ return {
136
+ ...this._stack[this._index],
137
+ action,
138
+ index: this._index,
139
+ delta,
140
+ };
141
+ }
142
+ }
143
+
144
+ class MemoryDataStorage {
145
+ constructor({ load, save } = {}) {
146
+ this._save = save;
147
+
148
+ const initialState = load
149
+ ? _loadState(load, this._isValidLoadedData)
150
+ : null;
151
+ if (initialState) {
152
+ this._state = initialState.state;
153
+ } else {
154
+ this._state = {};
155
+ }
156
+ }
157
+
158
+ // Returns either a `string` value or `null` if the key doesn't exist.
159
+ get(key) {
160
+ if (key in this._state) {
161
+ return this._state[key];
162
+ }
163
+ return null;
164
+ }
165
+
166
+ remove(key) {
167
+ if (key in this._state) {
168
+ delete this._state[key];
169
+ }
170
+
171
+ if (this._save) {
172
+ _saveState(this._save, {
173
+ state: this._state,
174
+ });
175
+ }
176
+ }
177
+
178
+ set(key, value) {
179
+ this._state[key] = value;
180
+
181
+ if (this._save) {
182
+ _saveState(this._save, {
183
+ state: this._state,
184
+ });
185
+ }
186
+ }
187
+
188
+ _isValidLoadedData({ state }) {
189
+ // Perform a basic validation of `state`.
190
+ return typeof state === 'object' && state !== null;
191
+ }
192
+ }
193
+
194
+ function createNestedStateSaveLoadFunctions({ save, load }, key) {
195
+ return {
196
+ save: save ? (data) => save(key, data) : undefined,
197
+ load: load ? () => load(key) : undefined,
198
+ };
199
+ }
200
+
201
+ export default class MemorySession {
202
+ constructor(initialLocation, { save, load } = {}) {
203
+ this.navigation = new MemoryNavigation(
204
+ initialLocation,
205
+ createNestedStateSaveLoadFunctions({ save, load }, 'navigation'),
206
+ );
207
+ this.dataStorage = new MemoryDataStorage(
208
+ createNestedStateSaveLoadFunctions({ save, load }, 'dataStorage'),
209
+ );
210
+ }
211
+
212
+ // "Before destroy" listeners are currently ignored.
213
+ // If required, one could implement a `_destroy()` method
214
+ // and there check that the listeners actually do get called.
215
+ // eslint-disable-next-line no-unused-vars
216
+ addBeforeDestroyListener(listener) {
217
+ return () => {};
218
+ }
219
+ }
@@ -1,3 +1,5 @@
1
+ /* eslint-disable max-classes-per-file */
2
+
1
3
  import normalizeInputLocation from '../normalizeInputLocation';
2
4
 
3
5
  function noop() {}
@@ -6,49 +8,60 @@ function serverSideNavigationNotPossible() {
6
8
  throw new Error('Server-side navigation is not possible');
7
9
  }
8
10
 
9
- export default class ServerEnvironment {
11
+ class ServerNavigation {
10
12
  constructor(initialLocation) {
11
13
  this._location = normalizeInputLocation(initialLocation);
12
14
  }
13
15
 
14
16
  init() {
15
17
  return {
16
- action: 'POP',
18
+ action: 'INIT',
17
19
  ...this._location,
20
+ index: 0,
21
+ key: '0',
18
22
  };
19
23
  }
20
24
 
21
25
  subscribe() {
22
- // Server environment emits no location events.
26
+ // Server-side environment emits no location subscription events.
23
27
  return noop;
24
28
  }
25
29
 
26
- // Navigation methods are not implemented, because `ServerPEnvironment` instances
30
+ // Navigation methods are not implemented, because `ServerSession` instances
27
31
  // cannot navigate.
28
32
  navigate() {
29
33
  serverSideNavigationNotPossible();
30
34
  }
31
35
 
32
- // Navigation methods are not implemented, because `ServerEnvironment` instances
36
+ // Navigation methods are not implemented, because `ServerSession` instances
33
37
  // cannot navigate.
34
38
  shift() {
35
39
  serverSideNavigationNotPossible();
36
40
  }
41
+ }
37
42
 
38
- // "Before destroy" listeners are currently ignored.
39
- // If required, one could implement a `_destroy()` method
40
- // and there check that the listeners actually do get called.
41
- addBeforeDestroyListener() {
42
- return () => {};
43
- }
44
-
43
+ class ServerDataStorage {
45
44
  // It doesn't seem to make any sense to store anything on server side.
46
45
  // Hence, state management methods are "no op" stubs.
47
- getState() {
46
+ get() {
48
47
  return null;
49
48
  }
50
49
 
51
- removeState() {}
50
+ remove() {}
51
+
52
+ set() {}
53
+ }
52
54
 
53
- setState() {}
55
+ export default class ServerSession {
56
+ constructor(initialLocation) {
57
+ this.navigation = new ServerNavigation(initialLocation);
58
+ this.dataStorage = new ServerDataStorage();
59
+ }
60
+
61
+ // "Before destroy" listeners are currently ignored.
62
+ // If required, one could implement a `_destroy()` method
63
+ // and there check that the listeners actually do get called.
64
+ addBeforeDestroyListener() {
65
+ return noop;
66
+ }
54
67
  }
@@ -1,8 +1,8 @@
1
- import LocationStateStorage from '../src/LocationStateStorage';
2
- import MemoryEnvironment from '../src/environment/MemoryEnvironment';
1
+ import LocationDataStorage from '../src/LocationDataStorage';
2
+ import MemorySession from '../src/session/MemorySession';
3
3
 
4
- describe('LocationStateStorage', () => {
5
- let environment;
4
+ describe('LocationDataStorage', () => {
5
+ let session;
6
6
  let stateStorage;
7
7
 
8
8
  const location = {
@@ -12,8 +12,8 @@ describe('LocationStateStorage', () => {
12
12
  beforeEach(() => {
13
13
  window.sessionStorage.clear();
14
14
 
15
- environment = new MemoryEnvironment('/initial-location');
16
- stateStorage = new LocationStateStorage(environment, {
15
+ session = new MemorySession('/initial-location');
16
+ stateStorage = new LocationDataStorage(session, {
17
17
  namespace: 'test',
18
18
  });
19
19
  });
@@ -2,8 +2,8 @@ import { applyMiddleware, createStore } from 'redux';
2
2
 
3
3
  import Actions from '../src/Actions';
4
4
  import createMiddlewares from '../src/createMiddlewares';
5
- import MemoryEnvironment from '../src/environment/MemoryEnvironment';
6
5
  import locationReducer from '../src/locationReducer';
6
+ import MemorySession from '../src/session/MemorySession';
7
7
 
8
8
  describe('createMiddlewares', () => {
9
9
  let store;
@@ -11,7 +11,7 @@ describe('createMiddlewares', () => {
11
11
  beforeEach(() => {
12
12
  store = createStore(
13
13
  locationReducer,
14
- applyMiddleware(...createMiddlewares(new MemoryEnvironment('/foo'))),
14
+ applyMiddleware(...createMiddlewares(new MemorySession('/foo'))),
15
15
  );
16
16
  store.dispatch(Actions.init());
17
17
  });
package/test/helpers.js CHANGED
@@ -23,7 +23,7 @@ export function transformInputLocationUsingMiddleware(middleware, location) {
23
23
  }).payload;
24
24
  }
25
25
 
26
- export function transformEnvironmentLocationUsingMiddleware(
26
+ export function transformSubscriptionLocationUsingMiddleware(
27
27
  middleware,
28
28
  location,
29
29
  ) {
@@ -13,8 +13,8 @@ describe('index', () => {
13
13
  expect(exports.parseLocationUrl).to.exist();
14
14
  expect(exports.createMiddlewares).to.exist();
15
15
  expect(exports.locationReducer).to.exist();
16
- expect(exports.BrowserEnvironment).to.exist();
17
- expect(exports.MemoryEnvironment).to.exist();
18
- expect(exports.ServerEnvironment).to.exist();
16
+ expect(exports.BrowserSession).to.exist();
17
+ expect(exports.MemorySession).to.exist();
18
+ expect(exports.ServerSession).to.exist();
19
19
  });
20
20
  });
@@ -1,7 +1,7 @@
1
1
  import createBasePathMiddleware from '../../src/middleware/createBasePathMiddleware';
2
2
  import {
3
- transformEnvironmentLocationUsingMiddleware,
4
3
  transformInputLocationUsingMiddleware,
4
+ transformSubscriptionLocationUsingMiddleware,
5
5
  } from '../helpers';
6
6
 
7
7
  describe('createBasePathMiddleware', () => {
@@ -22,9 +22,9 @@ describe('createBasePathMiddleware', () => {
22
22
  });
23
23
  });
24
24
 
25
- it('should strip `basePath` from `location.pathname` on environment locations', () => {
25
+ it('should strip `basePath` from `location.pathname` on subscription locations', () => {
26
26
  expect(
27
- transformEnvironmentLocationUsingMiddleware(basePathMiddleware, {
27
+ transformSubscriptionLocationUsingMiddleware(basePathMiddleware, {
28
28
  pathname: '/foo/path',
29
29
  }),
30
30
  ).to.eql({
@@ -32,9 +32,9 @@ describe('createBasePathMiddleware', () => {
32
32
  });
33
33
  });
34
34
 
35
- it('should handle unrecognized paths on environment locations', () => {
35
+ it('should handle unrecognized paths on subscription locations', () => {
36
36
  expect(
37
- transformEnvironmentLocationUsingMiddleware(basePathMiddleware, {
37
+ transformSubscriptionLocationUsingMiddleware(basePathMiddleware, {
38
38
  pathname: '/bar/path',
39
39
  }),
40
40
  ).to.eql({
@@ -54,10 +54,10 @@ describe('createBasePathMiddleware', () => {
54
54
  ).to.equal(location);
55
55
  });
56
56
 
57
- it('should not modify `location.pathname` of environment locations', () => {
57
+ it('should not modify `location.pathname` of subscription locations', () => {
58
58
  const location = { pathname: '/path' };
59
59
  expect(
60
- transformEnvironmentLocationUsingMiddleware(
60
+ transformSubscriptionLocationUsingMiddleware(
61
61
  basePathMiddleware,
62
62
  location,
63
63
  ),