From a16da81efdd7c5fdfea9ef47954a7e0c051480d8 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Mon, 8 Jan 2024 23:59:43 +0000 Subject: [PATCH 1/5] Fix hashchange events firing twice during every restoration visit --- src/core/drive/visit.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/drive/visit.js b/src/core/drive/visit.js index 132819507..0669a6909 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(this.view.lastRenderedLocation, this.location) + } } this.scrolled = true From 9b338f2e94a2de9643155fe2d4678e33107fd158 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 9 Jan 2024 00:00:35 +0000 Subject: [PATCH 2/5] Fix incorrect url passed in hashchange event oldURL detail --- src/core/drive/visit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/drive/visit.js b/src/core/drive/visit.js index 0669a6909..7b68f1d53 100644 --- a/src/core/drive/visit.js +++ b/src/core/drive/visit.js @@ -349,7 +349,7 @@ export class Visit { } else { this.scrollToAnchor() || this.view.scrollToTop() if (this.isSamePage) { - this.delegate.visitScrolledToSamePageLocation(this.view.lastRenderedLocation, this.location) + this.delegate.visitScrolledToSamePageLocation(window.location.href, this.location) } } From 9313bc0a80dac3406780c8f85122ff0a3746c584 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 9 Jan 2024 00:05:49 +0000 Subject: [PATCH 3/5] Fix visits sometimes triggered when using anchor links on same page --- src/core/drive/navigator.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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) ) } From a8b27c7203fc875a93f9cc1be691a1845023e51b Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 9 Jan 2024 03:37:01 +0000 Subject: [PATCH 4/5] Add test coverage for same-page anchor hashchange events --- src/tests/fixtures/one.html | 2 + src/tests/functional/navigation_tests.js | 65 +++++++++++++++++++++++- src/tests/helpers/page.js | 5 ++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/tests/fixtures/one.html b/src/tests/fixtures/one.html index 3434d3601..7f5dc5083 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

+ Named1 + Named2 Replaced only the frame diff --git a/src/tests/functional/navigation_tests.js b/src/tests/functional/navigation_tests.js index cdbc90e22..34e249e52 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("#named-anchor") + await nextBeat() + + await page.click("#named-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) + "#named-anchor-two", newURL: baseURL(page) + "#named-anchor" }] + ) +}) + +test("moving between multiple same-page anchors", async ({ page }) => { + await page.click("#same-origin-anchored-link-named") + 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("#named-anchor-two") + await nextBeat() + + assert.deepEqual( + await page.evaluate("window.hashchangeEvents"), + [{ oldURL: baseURL(page) + "#named-anchor", newURL: baseURL(page) + "#named-anchor-two" }] + ) + await page.evaluate("window.hashchangeEvents = []") + + await page.click("#named-anchor") + await nextBeat() + + assert.deepEqual( + await page.evaluate("window.hashchangeEvents"), + [{ oldURL: baseURL(page) + "#named-anchor-two", newURL: baseURL(page) + "#named-anchor" }] + ) + 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()) } From 222afbdfd7756d10a09e6993c0960dabb0a90f3b Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Wed, 10 Jan 2024 02:30:05 +0000 Subject: [PATCH 5/5] Clarify/simplify test scenario --- src/tests/fixtures/one.html | 4 ++-- src/tests/functional/navigation_tests.js | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/tests/fixtures/one.html b/src/tests/fixtures/one.html index 7f5dc5083..e268f8cd2 100644 --- a/src/tests/fixtures/one.html +++ b/src/tests/fixtures/one.html @@ -14,8 +14,8 @@

One

An element with an ID

Redirection link

- Named1 - Named2 + 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 34e249e52..767b9990a 100644 --- a/src/tests/functional/navigation_tests.js +++ b/src/tests/functional/navigation_tests.js @@ -411,10 +411,10 @@ test("hashchange events on restoration visits between same-page anchors", async await page.goto("/src/tests/fixtures/one.html") await page.waitForLoadState() - await page.click("#named-anchor") + await page.click("#anchor-one") await nextBeat() - await page.click("#named-anchor-two") + await page.click("#anchor-two") await nextBeat() await page.evaluate(() => { @@ -430,12 +430,12 @@ test("hashchange events on restoration visits between same-page anchors", async assert.deepEqual( await page.evaluate("window.hashchangeEvents"), - [{ oldURL: baseURL(page) + "#named-anchor-two", newURL: baseURL(page) + "#named-anchor" }] + [{ oldURL: baseURL(page) + "#anchor-two", newURL: baseURL(page) + "#anchor-one" }] ) }) test("moving between multiple same-page anchors", async ({ page }) => { - await page.click("#same-origin-anchored-link-named") + await page.goto("/src/tests/fixtures/one.html#anchor-one") await page.waitForLoadState() await page.evaluate(() => { @@ -450,21 +450,21 @@ test("moving between multiple same-page anchors", async ({ page }) => { }) }) - await page.click("#named-anchor-two") + await page.click("#anchor-two") await nextBeat() assert.deepEqual( await page.evaluate("window.hashchangeEvents"), - [{ oldURL: baseURL(page) + "#named-anchor", newURL: baseURL(page) + "#named-anchor-two" }] + [{ oldURL: baseURL(page) + "#anchor-one", newURL: baseURL(page) + "#anchor-two" }] ) await page.evaluate("window.hashchangeEvents = []") - await page.click("#named-anchor") + await page.click("#anchor-one") await nextBeat() assert.deepEqual( await page.evaluate("window.hashchangeEvents"), - [{ oldURL: baseURL(page) + "#named-anchor-two", newURL: baseURL(page) + "#named-anchor" }] + [{ oldURL: baseURL(page) + "#anchor-two", newURL: baseURL(page) + "#anchor-one" }] ) assert.deepEqual(await page.evaluate("window.visitEvents"), []) })