Skip to content

Commit

Permalink
Support history v5 (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hypnosphi authored Jul 15, 2020
1 parent 9f71de7 commit a41f668
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 40 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
57 changes: 35 additions & 22 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -45,29 +54,33 @@ const qhistory = (history, stringify, parse) => {
// the query property set on it when that listener
// is called.
history.listen((location) => {
addQuery(location)
updateProperties(history)
})

// make sure that the initial location has query support
addQuery(history.location)

const queryHistory = {
...history,
push: (location, state) => {
addSearch(location)
history.push(location, state)
},
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))
}

Object.defineProperty(queryHistory, 'location', {
get: () => addQuery(history.location),
})

return queryHistory
}

Expand Down
33 changes: 16 additions & 17 deletions tests/qhistory.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ describe('qhistory', () => {
const history = createMemoryHistory()
const q = qhistory(history, stringify, parse)

q.listen((location) => {
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')
Expand All @@ -44,7 +46,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)
})
Expand All @@ -56,41 +58,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', () => {
Expand All @@ -105,23 +107,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()
})
})

Expand Down

0 comments on commit a41f668

Please sign in to comment.