From a29d8c9eaf693f6022ef4b0584fa3bc51fb57dfc Mon Sep 17 00:00:00 2001 From: Kyle Marshall Date: Wed, 21 Apr 2021 23:06:26 -0400 Subject: [PATCH 1/2] Ensure locale key not duplicated when navigating back to root path with a query or hash value (#24323) This ensures that a duplicate locale key is not prepended to the path when navigating back (using browsers back button) to the root path containing query parameters or a hash value. Current behaviour: * `/fr?value=1` -> `/fr/another` -> click browser back button -> `/fr/fr?value=1` * `/fr?value=1` -> `/fr?value=2` -> click browser back button -> `/fr/fr?value=1` * `/fr#section` -> `/fr/another` -> click browser back button -> `/fr/fr#section` * `/fr#section` -> `/fr#another` -> click browser back button -> `/fr/fr#section` Fix: Remove query string or hash value from path before determining whether to add the locale to the path in `addLocale` function. ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added Fixes: #24287 --- .../next/next-server/lib/router/router.ts | 3 +- test/integration/i18n-support/test/shared.js | 78 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/packages/next/next-server/lib/router/router.ts b/packages/next/next-server/lib/router/router.ts index 785cbf0bbaf8b..45379d17937d0 100644 --- a/packages/next/next-server/lib/router/router.ts +++ b/packages/next/next-server/lib/router/router.ts @@ -113,7 +113,8 @@ export function addLocale( defaultLocale?: string ) { if (process.env.__NEXT_I18N_SUPPORT) { - const pathLower = path.toLowerCase() + const pathname = pathNoQueryHash(path) + const pathLower = pathname.toLowerCase() const localeLower = locale && locale.toLowerCase() return locale && diff --git a/test/integration/i18n-support/test/shared.js b/test/integration/i18n-support/test/shared.js index f183ee1b9dc0b..f0dac7dafbad3 100644 --- a/test/integration/i18n-support/test/shared.js +++ b/test/integration/i18n-support/test/shared.js @@ -53,6 +53,84 @@ export function runTests(ctx) { expect(await res.text()).toContain('index page') }) + it('should not add duplicate locale key when navigating back to root path with query params', async () => { + const basePath = ctx.basePath || '' + const queryKey = 'query' + const queryValue = '1' + const browser = await webdriver( + ctx.appPort, + `${basePath}/fr?${queryKey}=${queryValue}` + ) + + expect(await browser.eval(() => document.location.pathname)).toBe( + `${basePath}/fr` + ) + expect(await browser.elementByCss('#router-pathname').text()).toBe('/') + expect( + JSON.parse(await browser.elementByCss('#router-query').text()) + ).toEqual({ [queryKey]: queryValue }) + expect(await browser.elementByCss('#router-locale').text()).toBe('fr') + + await browser + .elementByCss('#to-another') + .click() + .waitForElementByCss('#another') + + expect(await browser.eval(() => document.location.pathname)).toBe( + `${basePath}/fr/another` + ) + expect(await browser.elementByCss('#router-pathname').text()).toBe( + '/another' + ) + expect(await browser.elementByCss('#router-locale').text()).toBe('fr') + + await browser.back().waitForElementByCss('#index') + + expect(await browser.eval(() => document.location.pathname)).toBe( + `${basePath}/fr` + ) + expect(await browser.elementByCss('#router-pathname').text()).toBe('/') + expect( + JSON.parse(await browser.elementByCss('#router-query').text()) + ).toEqual({ [queryKey]: queryValue }) + expect(await browser.elementByCss('#router-locale').text()).toBe('fr') + }) + + it('should not add duplicate locale key when navigating back to root path with hash', async () => { + const basePath = ctx.basePath || '' + const hashValue = '#anchor-1' + const browser = await webdriver(ctx.appPort, `${basePath}/fr${hashValue}`) + + expect(await browser.eval(() => document.location.pathname)).toBe( + `${basePath}/fr` + ) + expect(await browser.eval(() => document.location.hash)).toBe(hashValue) + expect(await browser.elementByCss('#router-pathname').text()).toBe('/') + expect(await browser.elementByCss('#router-locale').text()).toBe('fr') + + await browser + .elementByCss('#to-another') + .click() + .waitForElementByCss('#another') + + expect(await browser.eval(() => document.location.pathname)).toBe( + `${basePath}/fr/another` + ) + expect(await browser.elementByCss('#router-pathname').text()).toBe( + '/another' + ) + expect(await browser.elementByCss('#router-locale').text()).toBe('fr') + + await browser.back().waitForElementByCss('#index') + + expect(await browser.eval(() => document.location.pathname)).toBe( + `${basePath}/fr` + ) + expect(await browser.eval(() => document.location.hash)).toBe(hashValue) + expect(await browser.elementByCss('#router-pathname').text()).toBe('/') + expect(await browser.elementByCss('#router-locale').text()).toBe('fr') + }) + it('should handle navigating back to different casing of locale', async () => { const browser = await webdriver( ctx.appPort, From 9edb1ef16d55f1de694a050eac396335cc260f48 Mon Sep 17 00:00:00 2001 From: Janicklas Ralph Date: Wed, 21 Apr 2021 20:35:38 -0700 Subject: [PATCH 2/2] Adding script loader files to package.json (#24326) Adding script loader files to package.json --- packages/next/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/next/package.json b/packages/next/package.json index 23e3436d1c1b2..366c470a826e9 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -28,6 +28,8 @@ "dynamic.d.ts", "error.js", "error.d.ts", + "experimental-script.js", + "experimental-script.d.ts", "head.js", "head.d.ts", "image.js",