diff --git a/src/core/streams/stream_actions.js b/src/core/streams/stream_actions.js index 48ad92da5..a038add0d 100644 --- a/src/core/streams/stream_actions.js +++ b/src/core/streams/stream_actions.js @@ -25,25 +25,31 @@ export const StreamActions = { }, replace() { - this.targetElements.forEach((e) => e.replaceWith(this.templateContent)) + const method = this.getAttribute("method") + + this.targetElements.forEach((targetElement) => { + if (method === "morph") { + morphElements(targetElement, this.templateContent) + } else { + targetElement.replaceWith(this.templateContent) + } + }) }, update() { + const method = this.getAttribute("method") + this.targetElements.forEach((targetElement) => { - targetElement.innerHTML = "" - targetElement.append(this.templateContent) + if (method === "morph") { + morphChildren(targetElement, this.templateContent) + } else { + targetElement.innerHTML = "" + targetElement.append(this.templateContent) + } }) }, refresh() { session.refresh(this.baseURI, this.requestId) - }, - - morph() { - const morph = this.hasAttribute("children-only") ? - morphChildren : - morphElements - - this.targetElements.forEach((targetElement) => morph(targetElement, this.templateContent)) } } diff --git a/src/tests/fixtures/morph_stream_action.html b/src/tests/fixtures/morph_stream_action.html deleted file mode 100644 index df91274f5..000000000 --- a/src/tests/fixtures/morph_stream_action.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Morph Stream Action - - - - - - -
-
Morph me
-
- - diff --git a/src/tests/fixtures/stream.html b/src/tests/fixtures/stream.html index 85e8c94e4..a2b78907d 100644 --- a/src/tests/fixtures/stream.html +++ b/src/tests/fixtures/stream.html @@ -39,5 +39,9 @@
+ +
+
Morph me
+
diff --git a/src/tests/functional/morph_stream_action_tests.js b/src/tests/functional/morph_stream_action_tests.js deleted file mode 100644 index b4f04c9d7..000000000 --- a/src/tests/functional/morph_stream_action_tests.js +++ /dev/null @@ -1,48 +0,0 @@ -import { test, expect } from "@playwright/test" -import { nextEventOnTarget, noNextEventOnTarget } from "../helpers/page" - -test("dispatches a turbo:before-morph-element & turbo:morph-element for each morph stream action", async ({ page }) => { - await page.goto("/src/tests/fixtures/morph_stream_action.html") - - await page.evaluate(() => { - window.Turbo.renderStreamMessage(` - - - - `) - }) - - await nextEventOnTarget(page, "message_1", "turbo:before-morph-element") - await nextEventOnTarget(page, "message_1", "turbo:morph-element") - await expect(page.locator("#message_1")).toHaveText("Morphed") -}) - -test("preventing a turbo:before-morph-element prevents the morph", async ({ page }) => { - await page.goto("/src/tests/fixtures/morph_stream_action.html") - - await page.evaluate(() => { - addEventListener("turbo:before-morph-element", (event) => { - event.preventDefault() - }) - }) - - await page.evaluate(() => { - window.Turbo.renderStreamMessage(` - - - - `) - }) - - await nextEventOnTarget(page, "message_1", "turbo:before-morph-element") - await noNextEventOnTarget(page, "message_1", "turbo:morph-element") - await expect(page.locator("#message_1")).toHaveText("Morph me") -}) diff --git a/src/tests/functional/stream_tests.js b/src/tests/functional/stream_tests.js index 40f464d21..5c77016d8 100644 --- a/src/tests/functional/stream_tests.js +++ b/src/tests/functional/stream_tests.js @@ -1,9 +1,11 @@ -import { test } from "@playwright/test" +import { expect, test } from "@playwright/test" import { assert } from "chai" import { hasSelector, nextBeat, nextEventNamed, + nextEventOnTarget, + noNextEventOnTarget, readEventLogs, waitUntilNoSelector, waitUntilText @@ -182,6 +184,48 @@ test("receiving a remove stream message preserves focus blurs the activeElement" assert.notOk(await hasSelector(page, ":focus")) }) +test("dispatches a turbo:before-morph-element & turbo:morph-element for each morph stream action", async ({ page }) => { + await page.evaluate(() => { + window.Turbo.renderStreamMessage(` + + + + `) + }) + + await nextEventOnTarget(page, "message_1", "turbo:before-morph-element") + await nextEventOnTarget(page, "message_1", "turbo:morph-element") + await expect(page.locator("#message_1")).toHaveText("Morphed") +}) + +test("preventing a turbo:before-morph-element prevents the morph", async ({ page }) => { + await page.evaluate(() => { + addEventListener("turbo:before-morph-element", (event) => { + event.preventDefault() + }) + }) + + await page.evaluate(() => { + window.Turbo.renderStreamMessage(` + + + + `) + }) + + await nextEventOnTarget(page, "message_1", "turbo:before-morph-element") + await noNextEventOnTarget(page, "message_1", "turbo:morph-element") + await expect(page.locator("#message_1")).toHaveText("Morph me") +}) + async function getReadyState(page, id) { return page.evaluate((id) => { const element = document.getElementById(id) diff --git a/src/tests/unit/stream_element_tests.js b/src/tests/unit/stream_element_tests.js index 0d3e04b61..455581607 100644 --- a/src/tests/unit/stream_element_tests.js +++ b/src/tests/unit/stream_element_tests.js @@ -5,11 +5,12 @@ import { assert } from "@open-wc/testing" import { sleep } from "../helpers/page" import * as Turbo from "../../index" -function createStreamElement(action, target, templateElement) { +function createStreamElement(action, target, templateElement, attributes = {}) { const element = new StreamElement() if (action) element.setAttribute("action", action) if (target) element.setAttribute("target", target) if (templateElement) element.appendChild(templateElement) + Object.entries(attributes).forEach((attribute) => element.setAttribute(...attribute)) return element } @@ -197,9 +198,9 @@ test("test action=refresh discarded when matching request id", async () => { assert.ok(document.body.hasAttribute("data-modified")) }) -test("action=morph", async () => { +test("action=replace method=morph", async () => { const templateElement = createTemplateElement(`

Hello Turbo Morphed

`) - const element = createStreamElement("morph", "hello", templateElement) + const element = createStreamElement("replace", "hello", templateElement, { method: "morph" }) assert.equal(subject.find("div#hello")?.textContent, "Hello Turbo") @@ -210,9 +211,9 @@ test("action=morph", async () => { assert.equal(subject.find("h1#hello")?.textContent, "Hello Turbo Morphed") }) -test("action=morph with text content change", async () => { +test("action=replace method=morph with text content change", async () => { const templateElement = createTemplateElement(`
Hello Turbo Morphed
`) - const element = createStreamElement("morph", "hello", templateElement) + const element = createStreamElement("replace", "hello", templateElement, { method: "morph" }) assert.equal(subject.find("div#hello")?.textContent, "Hello Turbo") @@ -223,9 +224,9 @@ test("action=morph with text content change", async () => { assert.equal(subject.find("div#hello")?.textContent, "Hello Turbo Morphed") }) -test("action=morph children-only", async () => { +test("action=update method=morph", async () => { const templateElement = createTemplateElement(`

Hello Turbo Morphed

`) - const element = createStreamElement("morph", "hello", templateElement) + const element = createStreamElement("update", "hello", templateElement, { method: "morph" }) const target = subject.find("div#hello") assert.equal(target?.textContent, "Hello Turbo") element.setAttribute("children-only", true)