From c5147b7d8df6def1c39d35c3bb9eff71fcc21f87 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 7 Feb 2026 20:05:15 -0500 Subject: [PATCH] Fix prefetch for links with data-turbo-frame=_self Prefetching a link `` sends a request with a header `Turbo-Frame: _self`. This is incorrect as `_self` should be resolved to the current frame's id. This change resolves `_self` to the current turbo frame id before setting the header. When outside of a turbo frame the header is not set. Fixes #1349 --- src/observers/link_prefetch_observer.js | 6 +++++- src/tests/fixtures/hover_to_prefetch.html | 5 +++++ .../functional/link_prefetch_observer_tests.js | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/observers/link_prefetch_observer.js b/src/observers/link_prefetch_observer.js index 5f5f66d43..e4dfe864a 100644 --- a/src/observers/link_prefetch_observer.js +++ b/src/observers/link_prefetch_observer.js @@ -113,7 +113,11 @@ export class LinkPrefetchObserver { request.headers["X-Sec-Purpose"] = "prefetch" const turboFrame = link.closest("turbo-frame") - const turboFrameTarget = link.getAttribute("data-turbo-frame") || turboFrame?.getAttribute("target") || turboFrame?.id + let turboFrameTarget = link.getAttribute("data-turbo-frame") || turboFrame?.getAttribute("target") || turboFrame?.id + + if (turboFrameTarget === "_self") { + turboFrameTarget = turboFrame?.id + } if (turboFrameTarget && turboFrameTarget !== "_top") { request.headers["Turbo-Frame"] = turboFrameTarget diff --git a/src/tests/fixtures/hover_to_prefetch.html b/src/tests/fixtures/hover_to_prefetch.html index bd0f6f944..4ba7017ba 100644 --- a/src/tests/fixtures/hover_to_prefetch.html +++ b/src/tests/fixtures/hover_to_prefetch.html @@ -56,5 +56,10 @@ Hover to prefetch me + + Hover to prefetch me + + Hover to prefetch me + diff --git a/src/tests/functional/link_prefetch_observer_tests.js b/src/tests/functional/link_prefetch_observer_tests.js index a40ea16dc..eae2b83a4 100644 --- a/src/tests/functional/link_prefetch_observer_tests.js +++ b/src/tests/functional/link_prefetch_observer_tests.js @@ -205,6 +205,24 @@ test("doesn't include a turbo-frame header when the link is inside a turbo frame }}) }) +test("includes turbo-frame header when the link with a data-turbo-frame=_self is inside a turbo frame", async ({ page}) => { + await goTo({ page, path: "/hover_to_prefetch.html" }) + + await assertPrefetchedOnHover({ page, selector: "#anchor_for_prefetch_in_frame_target_self", callback: (request) => { + const turboFrameHeader = request.headers()["turbo-frame"] + expect(turboFrameHeader).toEqual("frame_for_prefetch_self") + }}) +}) + +test("doesn't include turbo-frame header when the link with a data-turbo-frame=_self is outside of a turbo frame", async ({ page}) => { + await goTo({ page, path: "/hover_to_prefetch.html" }) + + await assertPrefetchedOnHover({ page, selector: "#anchor_for_prefetch_out_of_frame_target_self", callback: (request) => { + const turboFrameHeader = request.headers()["turbo-frame"] + expect(turboFrameHeader).toEqual(undefined) + }}) +}) + test("it prefetches links with a delay", async ({ page }) => { await goTo({ page, path: "/hover_to_prefetch.html" })