From c2da56e1941e8dc09bf3c1352474ecd0ce973d04 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Fri, 19 May 2023 01:33:58 +0200 Subject: [PATCH] Fix going back to page after applying hash link (#50006) ## What? @steven-tey noticed that on upstash.com that scrolling to hash keeps happening regardless of the hash being set: - Open site - Click `Pricing` which adds `#pricing` and scrolls to the `id="pricing"` - Click `About` - Click on the logo You'll notice that navigating back to the homepage ends up scrolling to the `id="pricing` instead of to the top of the page. ## How? This happened because we didn't reset the `hashFragment` and `segmentPaths` for scrolling when scroll was applied, which means it would keep that value in the state and would be applied as such on navigation. This PR ensures that besides setting `apply` to `false` we also reset the `hashFragment` and `segmentPaths`. Fixes NEXT-1205 --------- Co-authored-by: JJ Kasper --- .../src/client/components/layout-router.tsx | 2 + .../hash-link-back-to-same-page/other/page.js | 12 +++++ .../app/hash-link-back-to-same-page/page.js | 50 +++++++++++++++++++ .../e2e/app-dir/navigation/navigation.test.ts | 50 ++++++++++++++++++- 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 test/e2e/app-dir/navigation/app/hash-link-back-to-same-page/other/page.js create mode 100644 test/e2e/app-dir/navigation/app/hash-link-back-to-same-page/page.js diff --git a/packages/next/src/client/components/layout-router.tsx b/packages/next/src/client/components/layout-router.tsx index c7cba3ae2e5ed..4c079f704a36c 100644 --- a/packages/next/src/client/components/layout-router.tsx +++ b/packages/next/src/client/components/layout-router.tsx @@ -211,6 +211,8 @@ class InnerScrollAndFocusHandler extends React.Component { diff --git a/test/e2e/app-dir/navigation/app/hash-link-back-to-same-page/other/page.js b/test/e2e/app-dir/navigation/app/hash-link-back-to-same-page/other/page.js new file mode 100644 index 0000000000000..f7a5fec235d39 --- /dev/null +++ b/test/e2e/app-dir/navigation/app/hash-link-back-to-same-page/other/page.js @@ -0,0 +1,12 @@ +import Link from 'next/link' + +export default function Page() { + return ( + <> +

Other Page

+ + Back to test home + + + ) +} diff --git a/test/e2e/app-dir/navigation/app/hash-link-back-to-same-page/page.js b/test/e2e/app-dir/navigation/app/hash-link-back-to-same-page/page.js new file mode 100644 index 0000000000000..43a7699957145 --- /dev/null +++ b/test/e2e/app-dir/navigation/app/hash-link-back-to-same-page/page.js @@ -0,0 +1,50 @@ +import Link from 'next/link' +import '../hash/global.css' + +export default function HashPage() { + // Create list of 5000 items that all have unique id + const items = Array.from({ length: 5000 }, (_, i) => ({ id: i })) + + return ( +
+

Hash Page

+ + To 6 + + + To 50 + + + To 160 + +
+ {items.map((item) => { + if (item.id === 160) { + return ( + <> +
+
{item.id}
+
+
+
+ + To other page + +
+
+ + ) + } + return ( +
+
{item.id}
+
+ ) + })} +
+
+ ) +} diff --git a/test/e2e/app-dir/navigation/navigation.test.ts b/test/e2e/app-dir/navigation/navigation.test.ts index c4d8918cf0d7c..7c73faea088a1 100644 --- a/test/e2e/app-dir/navigation/navigation.test.ts +++ b/test/e2e/app-dir/navigation/navigation.test.ts @@ -39,7 +39,6 @@ createNextDescribe( await check( async () => { const val = await browser.eval('window.pageYOffset') - require('console').error({ val }) return val.toString() }, expectedScroll.toString(), @@ -58,6 +57,55 @@ createNextDescribe( }) }) + describe('hash-link-back-to-same-page', () => { + it('should scroll to the specified hash', async () => { + const browser = await next.browser('/hash-link-back-to-same-page') + + const checkLink = async ( + val: number | string, + expectedScroll: number + ) => { + await browser.elementByCss(`#link-to-${val.toString()}`).click() + await check( + async () => { + const val = await browser.eval('window.pageYOffset') + return val.toString() + }, + expectedScroll.toString(), + true, + // Try maximum of 15 seconds + 15 + ) + } + + await checkLink(6, 114) + await checkLink(50, 730) + await checkLink(160, 2270) + + await browser + .elementByCss('#to-other-page') + // Navigate to other + .click() + // Wait for other ot load + .waitForElementByCss('#link-to-home') + // Navigate back to hash-link-back-to-same-page + .click() + // Wait for hash-link-back-to-same-page to load + .waitForElementByCss('#to-other-page') + + await check( + async () => { + const val = await browser.eval('window.pageYOffset') + return val.toString() + }, + (0).toString(), + true, + // Try maximum of 15 seconds + 15 + ) + }) + }) + describe('not-found', () => { it('should trigger not-found in a server component', async () => { const browser = await next.browser('/not-found/servercomponent')