diff --git a/__tests__/urlEncoding.spec.ts b/__tests__/urlEncoding.spec.ts index 3e4ca5e5c..e9653af9a 100644 --- a/__tests__/urlEncoding.spec.ts +++ b/__tests__/urlEncoding.spec.ts @@ -12,6 +12,7 @@ const routes: RouteRecordRaw[] = [ { path: '/to-p/:p', redirect: to => `/p/${to.params.p}` }, { path: '/p/:p', component: components.Bar, name: 'params' }, { path: '/p/:p+', component: components.Bar, name: 'repeat' }, + { path: '/optional/:a/:b?', component: components.Bar, name: 'optional' }, ] function createRouter() { @@ -42,7 +43,8 @@ describe('URL Encoding', () => { const router = createRouter() await router.push('/p/bar') await router.push({ params: { p: 'foo' } }) - expect(encoding.encodeParam).toHaveBeenCalledTimes(1) + expect(encoding.encodeParam).toHaveBeenCalledTimes(2) + expect(encoding.encodeParam).toHaveBeenCalledWith('bar') expect(encoding.encodeParam).toHaveBeenCalledWith('foo') }) @@ -75,16 +77,17 @@ describe('URL Encoding', () => { expect(encoding.decode).toHaveBeenNthCalledWith(2, 'bar', 1, ['foo', 'bar']) }) - it('keeps decoded values in params', async () => { + it('decodes values in params', async () => { // @ts-ignore: override to make the difference encoding.decode = () => 'd' // @ts-ignore encoding.encodeParam = () => 'e' const router = createRouter() - await router.push({ name: 'params', params: { p: '%' } }) + await router.push({ name: 'optional', params: { a: 'a%' } }) + await router.push({ params: { b: 'b%' } }) expect(router.currentRoute.value).toMatchObject({ - fullPath: '/p/e', - params: { p: '%' }, + fullPath: '/optional/e/e', + params: { b: 'd', a: 'd' }, }) }) diff --git a/src/router.ts b/src/router.ts index c8a4a58bb..f10f04a6f 100644 --- a/src/router.ts +++ b/src/router.ts @@ -239,10 +239,11 @@ export function createRouter(options: RouterOptions): Router { function resolve( rawLocation: Readonly, - currentLocation?: Readonly + currentLocation?: RouteLocationNormalizedLoaded ): RouteLocation & { href: string } { // const objectLocation = routerLocationAsObject(rawLocation) - currentLocation = currentLocation || currentRoute.value + // we create a copy to modify it later + currentLocation = { ...(currentLocation || currentRoute.value) } if (typeof rawLocation === 'string') { let locationNormalized = parseURL( parseQuery, @@ -293,9 +294,13 @@ export function createRouter(options: RouterOptions): Router { path: parseURL(parseQuery, rawLocation.path, currentLocation.path).path, }) } else { + // pass encoded values to the matcher so it can produce encoded path and fullPath matcherLocation = assign({}, rawLocation, { params: encodeParams(rawLocation.params), }) + // current location params are decoded, we need to encode them in case the + // matcher merges the params + currentLocation.params = encodeParams(currentLocation.params) } let matchedRoute = matcher.resolve(matcherLocation, currentLocation) @@ -307,11 +312,9 @@ export function createRouter(options: RouterOptions): Router { ) } - // put back the unencoded params as given by the user (avoid the cost of decoding them) - matchedRoute.params = - 'params' in rawLocation - ? normalizeParams(rawLocation.params) - : decodeParams(matchedRoute.params) + // decoding them) the matcher might have merged current location params so + // we need to run the decoding again + matchedRoute.params = normalizeParams(decodeParams(matchedRoute.params)) const fullPath = stringifyURL( stringifyQuery,