Skip to content

Commit

Permalink
fix(react-router): decode search keys (#2227)
Browse files Browse the repository at this point in the history
* fix: Decode search keys

* chore: Add a few more tests for search param key decoding

* ci: apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
kshramt and autofix-ci[bot] committed Aug 31, 2024
1 parent e945089 commit d39d0fd
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/react-router/src/qss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export function decode(str: any, pfx?: string) {
const equalIndex = tmp.indexOf('=')
if (equalIndex !== -1) {
k = tmp.slice(0, equalIndex)
k = decodeURIComponent(k)
const value = tmp.slice(equalIndex + 1)
if (out[k] !== void 0) {
// @ts-expect-error
Expand All @@ -77,6 +78,7 @@ export function decode(str: any, pfx?: string) {
}
} else {
k = tmp
k = decodeURIComponent(k)
out[k] = ''
}
}
Expand Down
27 changes: 27 additions & 0 deletions packages/react-router/tests/navigate.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ function createTestRouter(initialHistory?: RouterHistory) {
getParentRoute: () => gLayoutRoute,
path: '$username',
})
const searchRoute = createRoute({
getParentRoute: () => rootRoute,
path: 'search',
validateSearch: (search: Record<string, unknown>) => {
return {
['foo=bar']: Number(search['foo=bar'] ?? 1),
}
},
})

const projectTree = projectRoute.addChildren([
projectIdRoute.addChildren([
Expand Down Expand Up @@ -460,4 +469,22 @@ describe('router.navigate navigation using layout routes resolves correctly', as

expect(router.state.location.pathname).toBe('/g/tkdodo')
})

it('should handle search params with special characters', async () => {
const { router } = createTestRouter(
createMemoryHistory({ initialEntries: ['/search?foo%3Dbar=2'] }),
)

await router.load()

expect(router.state.location.pathname).toBe('/search')
expect(router.state.location.search).toStrictEqual({ 'foo=bar': 2 })

await router.navigate({
search: { 'foo=bar': 3 },
})
await router.invalidate()

expect(router.state.location.search).toStrictEqual({ 'foo=bar': 3 })
})
})
24 changes: 24 additions & 0 deletions packages/react-router/tests/qss.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ describe('encode function', () => {
const queryString = encode(obj)
expect(queryString).toEqual('token=foo%3F&key=value%3D')
})

it('should handle encoding a top-level key with a special character', () => {
const obj = { 'foo=bar': 1 }
const queryString = encode(obj)
expect(queryString).toEqual('foo%3Dbar=1')
})
})

describe('decode function', () => {
Expand Down Expand Up @@ -64,4 +70,22 @@ describe('decode function', () => {
const decodedObj = decode(queryString)
expect(decodedObj).toEqual({ token: 'foo?', key: 'value=' })
})

it('should handle decoding a top-level key with a special character', () => {
const queryString = 'foo%3Dbar=1'
const decodedObj = decode(queryString)
expect(decodedObj).toEqual({ 'foo=bar': 1 })
})

it('should handle decoding a top-level key with a special character and without a value', () => {
const queryString = 'foo%3Dbar='
const decodedObj = decode(queryString)
expect(decodedObj).toEqual({ 'foo=bar': '' })
})

it('should handle decoding a value-less top-level key with a special character', () => {
const queryString = 'foo%3Dbar'
const decodedObj = decode(queryString)
expect(decodedObj).toEqual({ 'foo=bar': '' })
})
})

0 comments on commit d39d0fd

Please sign in to comment.