diff --git a/src/core/drive/navigator.js b/src/core/drive/navigator.js index 8d8d3e0be..0cc643d83 100644 --- a/src/core/drive/navigator.js +++ b/src/core/drive/navigator.js @@ -129,13 +129,12 @@ export class Navigator { locationWithActionIsSamePage(location, action) { const anchor = getAnchor(location) - const currentAnchor = getAnchor(this.view.lastRenderedLocation) const isRestorationToTop = action === "restore" && typeof anchor === "undefined" return ( action !== "replace" && getRequestURL(location) === getRequestURL(this.view.lastRenderedLocation) && - (isRestorationToTop || (anchor != null && anchor !== currentAnchor)) + (isRestorationToTop || anchor != null) ) } diff --git a/src/core/drive/visit.js b/src/core/drive/visit.js index 132819507..7b68f1d53 100644 --- a/src/core/drive/visit.js +++ b/src/core/drive/visit.js @@ -348,9 +348,9 @@ export class Visit { this.scrollToRestoredPosition() || this.scrollToAnchor() || this.view.scrollToTop() } else { this.scrollToAnchor() || this.view.scrollToTop() - } - if (this.isSamePage) { - this.delegate.visitScrolledToSamePageLocation(this.view.lastRenderedLocation, this.location) + if (this.isSamePage) { + this.delegate.visitScrolledToSamePageLocation(window.location.href, this.location) + } } this.scrolled = true diff --git a/src/tests/fixtures/one.html b/src/tests/fixtures/one.html index 3434d3601..e268f8cd2 100644 --- a/src/tests/fixtures/one.html +++ b/src/tests/fixtures/one.html @@ -14,6 +14,8 @@

One

An element with an ID

Redirection link

+ Anchor 1 + Anchor 2 Replaced only the frame diff --git a/src/tests/functional/navigation_tests.js b/src/tests/functional/navigation_tests.js index cdbc90e22..767b9990a 100644 --- a/src/tests/functional/navigation_tests.js +++ b/src/tests/functional/navigation_tests.js @@ -19,7 +19,8 @@ import { visitAction, waitUntilSelector, waitUntilNoSelector, - willChangeBody + willChangeBody, + baseURL } from "../helpers/page" test.beforeEach(async ({ page }) => { @@ -406,6 +407,68 @@ test("same-page anchor visits do not trigger visit events", async ({ page }) => } }) +test("hashchange events on restoration visits between same-page anchors", async ({ page }) => { + await page.goto("/src/tests/fixtures/one.html") + await page.waitForLoadState() + + await page.click("#anchor-one") + await nextBeat() + + await page.click("#anchor-two") + await nextBeat() + + await page.evaluate(() => { + window.hashchangeEvents = [] + + window.addEventListener("hashchange", (event) => { + window.hashchangeEvents.push({ oldURL: event.oldURL, newURL: event.newURL }) + }) + }) + + await page.goBack() + await nextBeat() + + assert.deepEqual( + await page.evaluate("window.hashchangeEvents"), + [{ oldURL: baseURL(page) + "#anchor-two", newURL: baseURL(page) + "#anchor-one" }] + ) +}) + +test("moving between multiple same-page anchors", async ({ page }) => { + await page.goto("/src/tests/fixtures/one.html#anchor-one") + await page.waitForLoadState() + + await page.evaluate(() => { + window.hashchangeEvents = [] + window.visitEvents = [] + + window.addEventListener("hashchange", (event) => { + window.hashchangeEvents.push({ oldURL: event.oldURL, newURL: event.newURL }) + }) + window.addEventListener("turbo:visit", (event) => { + window.visitEvents.push(event.detail) + }) + }) + + await page.click("#anchor-two") + await nextBeat() + + assert.deepEqual( + await page.evaluate("window.hashchangeEvents"), + [{ oldURL: baseURL(page) + "#anchor-one", newURL: baseURL(page) + "#anchor-two" }] + ) + await page.evaluate("window.hashchangeEvents = []") + + await page.click("#anchor-one") + await nextBeat() + + assert.deepEqual( + await page.evaluate("window.hashchangeEvents"), + [{ oldURL: baseURL(page) + "#anchor-two", newURL: baseURL(page) + "#anchor-one" }] + ) + assert.deepEqual(await page.evaluate("window.visitEvents"), []) +}) + test("correct referrer header", async ({ page }) => { page.click("#headers-link") await nextBody(page) diff --git a/src/tests/helpers/page.js b/src/tests/helpers/page.js index 886941e6a..ed9554768 100644 --- a/src/tests/helpers/page.js +++ b/src/tests/helpers/page.js @@ -37,6 +37,11 @@ export function hash(url) { return hash } +export function baseURL(page) { + const url = new URL(page.url()) + return url.origin + url.pathname +} + export async function hasSelector(page, selector) { return !!(await page.locator(selector).count()) }