Skip to content

Commit e8ebfc0

Browse files
authored
Ensure compatibility with history@5 #111 (#113)
Ensure compatibility with history@5
1 parent 31c358e commit e8ebfc0

File tree

13 files changed

+24608
-117
lines changed

13 files changed

+24608
-117
lines changed

package-lock.json

Lines changed: 24356 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868
"preversion": "npm run lint -s && npm run lint:types -s && npm run lint:deps -s && npm run test -s"
6969
},
7070
"dependencies": {
71-
"history": "4.10.1",
7271
"lodash.debounce": "^4.0.8",
7372
"lodash.noop": "^3.0.1",
7473
"path-to-regexp": "^1.7.0",
@@ -120,6 +119,8 @@
120119
"eslint-plugin-react-hooks": "^4.0.2",
121120
"flow-bin": "^0.135.0",
122121
"flow-copy-source": "^2.0.7",
122+
"history": "4.10.1",
123+
"history-5": "npm:history@^5.2.0",
123124
"jest": "^26.0.1",
124125
"madge": "^4.0.1",
125126
"prettier": "^2.0.5",
@@ -131,6 +132,7 @@
131132
"webpack-dev-server": "^3.11.0"
132133
},
133134
"peerDependencies": {
135+
"history": "^4 || ^5",
134136
"react": "^16.8.0",
135137
"react-dom": "^16.8.0",
136138
"typescript": "^3.7.2"
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { parsePath } from '../../../../../common/utils/create-location/parse-path';
2+
3+
describe.each([
4+
{
5+
input: '/a/b?c=d#e',
6+
description: 'full path',
7+
pathname: '/a/b',
8+
search: '?c=d',
9+
hash: '#e',
10+
},
11+
{
12+
input: 'a/b?c=d#e',
13+
description: 'relative path',
14+
pathname: 'a/b',
15+
search: '?c=d',
16+
hash: '#e',
17+
},
18+
{
19+
input: '?a=b#c',
20+
description: 'no pathname',
21+
pathname: '/',
22+
search: '?a=b',
23+
hash: '#c',
24+
},
25+
{
26+
input: '/a/b#c',
27+
description: 'no search',
28+
pathname: '/a/b',
29+
search: '',
30+
hash: '#c',
31+
},
32+
{
33+
input: '/a/b?c=d',
34+
description: 'no hash',
35+
pathname: '/a/b',
36+
search: '?c=d',
37+
hash: '',
38+
},
39+
{
40+
input: '/a/b#c?d=e',
41+
description: 'search in hash',
42+
pathname: '/a/b',
43+
search: '',
44+
hash: '#c?d=e',
45+
},
46+
])(
47+
'parsePath($input): { pathname, search, hash }',
48+
({ input, description, pathname, search, hash }) => {
49+
test(description, () => {
50+
expect(parsePath(input)).toMatchObject({
51+
pathname,
52+
search,
53+
hash,
54+
});
55+
});
56+
}
57+
);

src/__tests__/unit/common/utils/location/test.ts

Lines changed: 0 additions & 33 deletions
This file was deleted.

src/__tests__/unit/controllers/router-store/test.tsx

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22

33
import { mount, render } from 'enzyme';
44
import * as historyHelper from 'history';
5+
import * as historyHelper5 from 'history-5';
56
import { defaultRegistry } from 'react-sweet-state';
67
import { act } from 'react-dom/test-utils';
78

@@ -156,7 +157,7 @@ describe('SPA Router store', () => {
156157
});
157158
});
158159

159-
describe('listening for real history changes', () => {
160+
describe('listening for real history changes on history@4', () => {
160161
let children: any;
161162

162163
beforeEach(() => {
@@ -243,6 +244,98 @@ describe('SPA Router store', () => {
243244
});
244245
});
245246

247+
describe('listening for real history changes on history@5', () => {
248+
let children: any;
249+
250+
beforeEach(() => {
251+
children = jest.fn().mockReturnValue(null);
252+
253+
jest
254+
.spyOn(historyHelper, 'createMemoryHistory')
255+
// @ts-ignore
256+
.mockImplementation(historyHelper5.createMemoryHistory);
257+
});
258+
259+
it('should send location with route change', async () => {
260+
mount(
261+
<MemoryRouter routes={mockRoutes} location={mockRoutes[0].path}>
262+
<RouterSubscriber>{children}</RouterSubscriber>
263+
</MemoryRouter>
264+
);
265+
const { history } = children.mock.calls[0][0];
266+
267+
await nextTick();
268+
269+
expect(children.mock.calls[0]).toEqual([
270+
expect.objectContaining({
271+
routes: mockRoutes,
272+
route: mockRoutes[0],
273+
action: DEFAULT_ACTION,
274+
history: expect.any(Object),
275+
}),
276+
expect.any(Object),
277+
]);
278+
279+
const newLocation = {
280+
pathname: '/blah',
281+
search: '?somequery=value',
282+
hash: '#bing',
283+
};
284+
285+
history.push(Object.values(newLocation).join(''));
286+
287+
await nextTick();
288+
289+
expect(children.mock.calls[1]).toEqual([
290+
expect.objectContaining({
291+
routes: mockRoutes,
292+
route: mockRoutes[1],
293+
action: 'PUSH',
294+
history: expect.any(Object),
295+
}),
296+
expect.any(Object),
297+
]);
298+
});
299+
300+
it('should send correct action key for route changes', async () => {
301+
mount(
302+
<MemoryRouter routes={mockRoutes}>
303+
<RouterSubscriber>{children}</RouterSubscriber>
304+
</MemoryRouter>
305+
);
306+
const { history } = children.mock.calls[0][0];
307+
308+
expect(children.mock.calls[0]).toEqual([
309+
expect.objectContaining({
310+
action: DEFAULT_ACTION,
311+
}),
312+
expect.any(Object),
313+
]);
314+
315+
history.push('/pathname');
316+
317+
await nextTick();
318+
319+
expect(children.mock.calls[1]).toEqual([
320+
expect.objectContaining({
321+
action: 'PUSH',
322+
}),
323+
expect.any(Object),
324+
]);
325+
326+
history.replace('/blah');
327+
328+
await nextTick();
329+
330+
expect(children.mock.calls[2]).toEqual([
331+
expect.objectContaining({
332+
action: 'REPLACE',
333+
}),
334+
expect.any(Object),
335+
]);
336+
});
337+
});
338+
246339
describe('store actions', () => {
247340
const currentLocation = 'http://localhost/';
248341

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { decodePath } from './decode-path';
2+
import { parsePath } from './parse-path';
3+
4+
export function createLocation(path = '') {
5+
const location = parsePath(path);
6+
location.pathname = decodePath(location.pathname);
7+
8+
return location;
9+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class DecodeUriError extends URIError {
2+
constructor(path: string) {
3+
super(
4+
`Pathname ${path} could not be decoded. This is likely caused by an invalid percent-encoding.`
5+
);
6+
}
7+
}
8+
9+
export function decodePath(path: string) {
10+
try {
11+
return decodeURI(path);
12+
} catch (e) {
13+
if (e instanceof URIError) {
14+
throw new DecodeUriError(path);
15+
} else {
16+
throw e;
17+
}
18+
}
19+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { createLocation } from './create-location';
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export function parsePath(path: string) {
2+
const url = new URL(path, 'ws://a.a');
3+
const isAbsolute = path.startsWith('/');
4+
5+
const pathname =
6+
isAbsolute || url.pathname === '/' ? url.pathname : url.pathname.slice(1);
7+
8+
return {
9+
pathname,
10+
search: url.search,
11+
hash: url.hash,
12+
};
13+
}

src/common/utils/location/index.ts

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)