From 63ec66b25fd406dab72e79df5f88bc1793f009a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Fern=C3=A1ndez-Capel?= Date: Mon, 29 Jan 2024 11:14:21 +0000 Subject: [PATCH] Don't include Turbo-Frame header in promoted frame navigations This commit changes the behavior of frame navigations promoted with the `[data-turbo-action]` attribute so that they don't include the `Turbo-Frame` header in their requests. This mimics the existing behavior of frame navigations promoted with `[data-turbo-target=_top]`. If we don't do this turbo-rails will see the `Turbo-Frame` header and render the response as a frame update, with a minimal layout that doesn't include any assets. When Turbo receives the response it believes it's a full page response in which the assets have gone stale and it issues a full page reload with `tracked_element_mismatch` as the reason. Fixes https://github.com/hotwired/turbo/issues/1047 This is similar to https://github.com/hotwired/turbo/pull/1138 --- src/core/frames/frame_controller.js | 4 ++- .../functional/frame_navigation_tests.js | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/core/frames/frame_controller.js b/src/core/frames/frame_controller.js index 02358d123..4664f4e45 100644 --- a/src/core/frames/frame_controller.js +++ b/src/core/frames/frame_controller.js @@ -192,7 +192,9 @@ export class FrameController { // Fetch request delegate prepareRequest(request) { - request.headers["Turbo-Frame"] = this.id + if (!this.action) { + request.headers["Turbo-Frame"] = this.id + } if (this.currentNavigationElement?.hasAttribute("data-turbo-stream")) { request.acceptResponseType(StreamMessage.contentType) diff --git a/src/tests/functional/frame_navigation_tests.js b/src/tests/functional/frame_navigation_tests.js index 77442d5a3..6f9fcc359 100644 --- a/src/tests/functional/frame_navigation_tests.js +++ b/src/tests/functional/frame_navigation_tests.js @@ -49,6 +49,30 @@ test("lazy-loaded frame promotes navigation", async ({ page }) => { assert.equal(pathname(page.url()), "/src/tests/fixtures/frames/frame_for_eager.html") }) +test("frame navigation sets the Turbo-Frame header", async ({ page }) => { + await page.goto("/src/tests/fixtures/frame_navigation.html") + assertNextRequesTurboFrameHeader(page, "frame") + + await page.click("#inside") + await nextEventNamed(page, "turbo:load") +}) + +test("frame navigation promoted with data-turbo-target=_top doesn't set the Turbo-Frame header", async ({ page }) => { + await page.goto("/src/tests/fixtures/frame_navigation.html") + assertNextRequesTurboFrameHeader(page, undefined) + + await page.click("#top") + await nextEventNamed(page, "turbo:load") +}) + +test("frame navigation promoted with data-turbo-action doesn't set the Turbo-Frame header", async ({ page }) => { + await page.goto("/src/tests/fixtures/tabs.html") + assertNextRequesTurboFrameHeader(page, undefined) + + await page.click("#tab-1") + await nextEventNamed(page, "turbo:frame-render") +}) + test("promoted frame navigation updates the URL before rendering", async ({ page }) => { await page.goto("/src/tests/fixtures/tabs.html") @@ -104,3 +128,10 @@ test("promoted frame navigations are cached", async ({ page }) => { assert.equal(await page.getAttribute("#tab-frame", "src"), null, "caches one.html without #tab-frame[src]") assert.equal(await page.getAttribute("#tab-frame", "complete"), null, "caches one.html without [complete]") }) + +function assertNextRequesTurboFrameHeader(page, expected) { + page.on("request", (request) => { + assert.equal(request.headers()["turbo-frame"], expected) + }) +} +