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())
}