From ec71f17688426e4769ff4749fed3f58b6c48615c Mon Sep 17 00:00:00 2001 From: Filipp Riabchun Date: Mon, 13 Jul 2020 21:25:40 +0200 Subject: [PATCH 1/2] Support history v5 --- package.json | 2 +- src/index.js | 51 +++++++++++++++++++++++++++--------------- tests/qhistory.spec.js | 31 ++++++++++++------------- 3 files changed, 48 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index f8a6f73..b684ddd 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "babel-plugin-transform-object-rest-spread": "^6.22.0", "babel-preset-es2015": "^6.22.0", "cross-env": "^3.1.4", - "history": "^4.5.1", + "history": "^5.0.0", "jest": "^18.1.0", "qs": "^6.3.0", "rimraf": "^2.5.4", diff --git a/src/index.js b/src/index.js index 021fa40..76dbe18 100644 --- a/src/index.js +++ b/src/index.js @@ -16,21 +16,30 @@ const qhistory = (history, stringify, parse) => { const addSearch = (location) => { if (typeof location === 'object') { - location.search = location.query ? stringify(location.query) : location.search || '' + let search = location.search || '' + if (location.query) { + search = stringify(location.query) + // Ensure leading "?" for non-empty search + if (search.length > 0 && search.charAt(0) !== '?') { + search = `?${search}` + } + } + return {...location, search} } + + return location } const addQuery = (location) => { const { search } = location - if (search) { - location.query = parse(search.charAt(0) === '?' ? search.substring(1) : search) - } else { - location.query = {} + return { + ...location, + query: search ? parse(search.charAt(0) === '?' ? search.substring(1) : search) : {} } } const updateProperties = (history) => { - const properties = ['location', 'length', 'entries', 'index', 'action'] + const properties = ['length', 'entries', 'index', 'action'] properties.forEach(prop => { if (history.hasOwnProperty(prop)) { queryHistory[prop] = history[prop] @@ -45,7 +54,6 @@ const qhistory = (history, stringify, parse) => { // the query property set on it when that listener // is called. history.listen((location) => { - addQuery(location) updateProperties(history) }) @@ -54,18 +62,25 @@ const qhistory = (history, stringify, parse) => { const queryHistory = { ...history, - push: (location, state) => { - addSearch(location) - history.push(location, state) + get location() { + return addQuery(history.location) }, - replace: (location, state) => { - addSearch(location) - history.replace(location, state) - }, - createHref: (location) => { - addSearch(location) - return history.createHref(location) - } + listen: (listener) => + history.listen((location, action) => { + const isV5 = location.location != null + if (isV5) { + action = location.action + location = location.location + } + const queryLocation = addQuery(location) + isV5 ? listener({location: queryLocation, action}) : listener(queryLocation, action) + }), + push: (location, state) => + history.push(addSearch(location), state), + replace: (location, state) => + history.replace(addSearch(location), state), + createHref: (location) => + history.createHref(addSearch(location)) } return queryHistory diff --git a/tests/qhistory.spec.js b/tests/qhistory.spec.js index b5bc0d9..4214ec5 100644 --- a/tests/qhistory.spec.js +++ b/tests/qhistory.spec.js @@ -32,7 +32,7 @@ describe('qhistory', () => { const history = createMemoryHistory() const q = qhistory(history, stringify, parse) - q.listen((location) => { + q.listen(({location}) => { expect(location.query).toEqual({ tooGoodToBe: 'true' }) expect(location.search).toBe('?tooGoodToBe=true') }) @@ -44,7 +44,7 @@ describe('qhistory', () => { const history = createMemoryHistory() const q = qhistory(history, stringify, parse) - q.listen((location) => { + q.listen(({location}) => { expect(location.query).toBeInstanceOf(Object) expect(Object.keys(location.query).length).toBe(0) }) @@ -56,41 +56,41 @@ describe('qhistory', () => { describe('search', () => { it('will prefer query object over search string', () => { const history = createMemoryHistory() + history.push = jest.fn(); const q = qhistory(history, stringify, parse) q.push({ pathname: '/somewhere', search: '?overRainbow=false', query: { overRainbow: true } }) - const mostRecentLocation = q.entries[q.entries.length-1] - expect(mostRecentLocation.search).toBe('?overRainbow=true') + expect(history.push).toHaveBeenCalledWith(expect.objectContaining({search: '?overRainbow=true'}), undefined) }) it('uses search if no query provided', () => { const history = createMemoryHistory() + history.push = jest.fn(); const q = qhistory(history, stringify, parse) q.push({ pathname: '/somewhere', search: '?overRainbow=false' }) - const mostRecentLocation = q.entries[q.entries.length-1] - expect(mostRecentLocation.search).toBe('?overRainbow=false') + expect(history.push).toHaveBeenCalledWith(expect.objectContaining({search: '?overRainbow=false'}), undefined) }) it('sets search to empty string if no query/search', () => { const history = createMemoryHistory() + history.push = jest.fn(); const q = qhistory(history, stringify, parse) q.push({ pathname: '/somewhere' }) - const mostRecentLocation = q.entries[q.entries.length-1] - expect(mostRecentLocation.search).toBe('') + expect(history.push).toHaveBeenCalledWith(expect.objectContaining({search: ''}), undefined) }) }) describe('push', () => { it('will set search string for location passed to actual history', () => { const history = createMemoryHistory() + history.push = jest.fn(); const q = qhistory(history, stringify, parse) q.push({ pathname: '/somewhere', query: { overRainbow: true }}) - const mostRecentLocation = q.entries[q.entries.length-1] - expect(mostRecentLocation.search).toBe('?overRainbow=true') + expect(history.push).toHaveBeenCalledWith(expect.objectContaining({search: '?overRainbow=true'}), undefined) }) it('will call the history instance\'s push method', () => { @@ -105,23 +105,20 @@ describe('qhistory', () => { describe('replace', () => { it('will set search string for location passed to actual history', () => { const history = createMemoryHistory() + history.replace = jest.fn(); const q = qhistory(history, stringify, parse) - expect(q.length).toBe(1) q.replace({ pathname: '/somewhere', query: { overRainbow: true }}) - const mostRecentLocation = q.entries[q.entries.length-1] - expect(mostRecentLocation.search).toBe('?overRainbow=true') + expect(history.replace).toHaveBeenCalledWith(expect.objectContaining({search: '?overRainbow=true'}), undefined) }) it('will call the history instance\'s replace method', () => { const history = createMemoryHistory() + history.replace = jest.fn(); const q = qhistory(history, stringify, parse) - expect(q.length).toBe(1) q.replace({ pathname: '/somewhere', query: { overRainbow: true }}) - // test length to ensure replace was called - expect(q.length).toBe(1) - expect(q.action).toBe('REPLACE') + expect(history.replace).toHaveBeenCalled() }) }) From e5a398194748eb64625e3cbb16ca162ebc6155b4 Mon Sep 17 00:00:00 2001 From: Filipp Riabchun Date: Tue, 14 Jul 2020 18:36:14 +0200 Subject: [PATCH 2/2] Fix location getter definition --- src/index.js | 10 ++++------ tests/qhistory.spec.js | 2 ++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index 76dbe18..dc46549 100644 --- a/src/index.js +++ b/src/index.js @@ -57,14 +57,8 @@ const qhistory = (history, stringify, parse) => { updateProperties(history) }) - // make sure that the initial location has query support - addQuery(history.location) - const queryHistory = { ...history, - get location() { - return addQuery(history.location) - }, listen: (listener) => history.listen((location, action) => { const isV5 = location.location != null @@ -83,6 +77,10 @@ const qhistory = (history, stringify, parse) => { history.createHref(addSearch(location)) } + Object.defineProperty(queryHistory, 'location', { + get: () => addQuery(history.location), + }) + return queryHistory } diff --git a/tests/qhistory.spec.js b/tests/qhistory.spec.js index 4214ec5..fcae8f3 100644 --- a/tests/qhistory.spec.js +++ b/tests/qhistory.spec.js @@ -34,7 +34,9 @@ describe('qhistory', () => { q.listen(({location}) => { expect(location.query).toEqual({ tooGoodToBe: 'true' }) + expect(q.location.query).toEqual({ tooGoodToBe: 'true' }) expect(location.search).toBe('?tooGoodToBe=true') + expect(q.location.search).toBe('?tooGoodToBe=true') }) q.push('/test?tooGoodToBe=true')