diff --git a/src/core/drive/morph_renderer.js b/src/core/drive/morph_renderer.js
index 48d9ef1ef..80bb7d8e6 100644
--- a/src/core/drive/morph_renderer.js
+++ b/src/core/drive/morph_renderer.js
@@ -87,6 +87,8 @@ export class MorphRenderer extends Renderer {
}
#remoteFrames() {
- return document.querySelectorAll("turbo-frame[src]")
+ return Array.from(document.querySelectorAll('turbo-frame[src]')).filter(frame => {
+ return !frame.closest('[data-turbo-permanent]')
+ })
}
}
diff --git a/src/tests/fixtures/page_refresh.html b/src/tests/fixtures/page_refresh.html
index cd3d4b4bd..d49c97d77 100644
--- a/src/tests/fixtures/page_refresh.html
+++ b/src/tests/fixtures/page_refresh.html
@@ -30,6 +30,10 @@
Frame to be morphed
Preserve me!
+
+
+ Frame to be preserved
+
diff --git a/src/tests/fixtures/remote_permanent_frame.html b/src/tests/fixtures/remote_permanent_frame.html
new file mode 100644
index 000000000..a1be6c573
--- /dev/null
+++ b/src/tests/fixtures/remote_permanent_frame.html
@@ -0,0 +1,3 @@
+
+ Loaded permanent frame
+
diff --git a/src/tests/functional/page_refresh_tests.js b/src/tests/functional/page_refresh_tests.js
index 24d830d1f..e267d68c9 100644
--- a/src/tests/functional/page_refresh_tests.js
+++ b/src/tests/functional/page_refresh_tests.js
@@ -4,6 +4,7 @@ import {
nextBeat,
nextEventNamed,
nextEventOnTarget,
+ noNextEventOnTarget,
noNextEventNamed
} from "../helpers/page"
@@ -30,7 +31,7 @@ test("doesn't morph when the navigation doesn't go to the same URL", async ({ pa
expect(await noNextEventNamed(page, "turbo:render", { renderMethod: "morph" })).toBeTruthy()
})
-test("uses morphing to update remote frames marked", async ({ page }) => {
+test("uses morphing to update remote frames", async ({ page }) => {
await page.goto("/src/tests/fixtures/page_refresh.html")
await page.click("#form-submit")
@@ -42,6 +43,17 @@ test("uses morphing to update remote frames marked", async ({ page }) => {
await expect(page.locator("#remote-frame")).toHaveText("Loaded morphed frame")
})
+test("don't refresh frames contained in [data-turbo-permanent] elements", async ({ page }) => {
+ await page.goto("/src/tests/fixtures/page_refresh.html")
+
+ await page.click("#form-submit")
+ await nextEventNamed(page, "turbo:render", { renderMethod: "morph" })
+ await nextBeat()
+
+ // Only the frame marked with refresh="morph" uses morphing
+ expect(await noNextEventOnTarget(page, "refresh-reload", "turbo:before-frame-morph")).toBeTruthy()
+})
+
test("frames marked with refresh='morph' are excluded from full page morphing", async ({ page }) => {
await page.goto("/src/tests/fixtures/page_refresh.html")