Skip to content

Commit a4f3a90

Browse files
Merge pull request #1240 from seanpdoyle/rename-morph-stream-action
Re-structure `turbo-stream[action=morph]` support
2 parents 2ef50c9 + 9369eb9 commit a4f3a90

File tree

6 files changed

+74
-83
lines changed

6 files changed

+74
-83
lines changed

src/core/streams/stream_actions.js

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,31 @@ export const StreamActions = {
2525
},
2626

2727
replace() {
28-
this.targetElements.forEach((e) => e.replaceWith(this.templateContent))
28+
const method = this.getAttribute("method")
29+
30+
this.targetElements.forEach((targetElement) => {
31+
if (method === "morph") {
32+
morphElements(targetElement, this.templateContent)
33+
} else {
34+
targetElement.replaceWith(this.templateContent)
35+
}
36+
})
2937
},
3038

3139
update() {
40+
const method = this.getAttribute("method")
41+
3242
this.targetElements.forEach((targetElement) => {
33-
targetElement.innerHTML = ""
34-
targetElement.append(this.templateContent)
43+
if (method === "morph") {
44+
morphChildren(targetElement, this.templateContent)
45+
} else {
46+
targetElement.innerHTML = ""
47+
targetElement.append(this.templateContent)
48+
}
3549
})
3650
},
3751

3852
refresh() {
3953
session.refresh(this.baseURI, this.requestId)
40-
},
41-
42-
morph() {
43-
const morph = this.hasAttribute("children-only") ?
44-
morphChildren :
45-
morphElements
46-
47-
this.targetElements.forEach((targetElement) => morph(targetElement, this.templateContent))
4854
}
4955
}

src/tests/fixtures/morph_stream_action.html

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/tests/fixtures/stream.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,9 @@
3939
<div id="container">
4040
<input id="container-element">
4141
</div>
42+
43+
<div id="message_1">
44+
<div>Morph me</div>
45+
</div>
4246
</body>
4347
</html>

src/tests/functional/morph_stream_action_tests.js

Lines changed: 0 additions & 48 deletions
This file was deleted.

src/tests/functional/stream_tests.js

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import { test } from "@playwright/test"
1+
import { expect, test } from "@playwright/test"
22
import { assert } from "chai"
33
import {
44
hasSelector,
55
nextBeat,
66
nextEventNamed,
7+
nextEventOnTarget,
8+
noNextEventOnTarget,
79
readEventLogs,
810
waitUntilNoSelector,
911
waitUntilText
@@ -182,6 +184,48 @@ test("receiving a remove stream message preserves focus blurs the activeElement"
182184
assert.notOk(await hasSelector(page, ":focus"))
183185
})
184186

187+
test("dispatches a turbo:before-morph-element & turbo:morph-element for each morph stream action", async ({ page }) => {
188+
await page.evaluate(() => {
189+
window.Turbo.renderStreamMessage(`
190+
<turbo-stream action="replace" method="morph" target="message_1">
191+
<template>
192+
<div id="message_1">
193+
<h1>Morphed</h1>
194+
</div>
195+
</template>
196+
</turbo-stream>
197+
`)
198+
})
199+
200+
await nextEventOnTarget(page, "message_1", "turbo:before-morph-element")
201+
await nextEventOnTarget(page, "message_1", "turbo:morph-element")
202+
await expect(page.locator("#message_1")).toHaveText("Morphed")
203+
})
204+
205+
test("preventing a turbo:before-morph-element prevents the morph", async ({ page }) => {
206+
await page.evaluate(() => {
207+
addEventListener("turbo:before-morph-element", (event) => {
208+
event.preventDefault()
209+
})
210+
})
211+
212+
await page.evaluate(() => {
213+
window.Turbo.renderStreamMessage(`
214+
<turbo-stream action="replace" method="morph" target="message_1">
215+
<template>
216+
<div id="message_1">
217+
<h1>Morphed</h1>
218+
</div>
219+
</template>
220+
</turbo-stream>
221+
`)
222+
})
223+
224+
await nextEventOnTarget(page, "message_1", "turbo:before-morph-element")
225+
await noNextEventOnTarget(page, "message_1", "turbo:morph-element")
226+
await expect(page.locator("#message_1")).toHaveText("Morph me")
227+
})
228+
185229
async function getReadyState(page, id) {
186230
return page.evaluate((id) => {
187231
const element = document.getElementById(id)

src/tests/unit/stream_element_tests.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import { assert } from "@open-wc/testing"
55
import { sleep } from "../helpers/page"
66
import * as Turbo from "../../index"
77

8-
function createStreamElement(action, target, templateElement) {
8+
function createStreamElement(action, target, templateElement, attributes = {}) {
99
const element = new StreamElement()
1010
if (action) element.setAttribute("action", action)
1111
if (target) element.setAttribute("target", target)
1212
if (templateElement) element.appendChild(templateElement)
13+
Object.entries(attributes).forEach((attribute) => element.setAttribute(...attribute))
1314
return element
1415
}
1516

@@ -197,9 +198,9 @@ test("test action=refresh discarded when matching request id", async () => {
197198
assert.ok(document.body.hasAttribute("data-modified"))
198199
})
199200

200-
test("action=morph", async () => {
201+
test("action=replace method=morph", async () => {
201202
const templateElement = createTemplateElement(`<h1 id="hello">Hello Turbo Morphed</h1>`)
202-
const element = createStreamElement("morph", "hello", templateElement)
203+
const element = createStreamElement("replace", "hello", templateElement, { method: "morph" })
203204

204205
assert.equal(subject.find("div#hello")?.textContent, "Hello Turbo")
205206

@@ -210,9 +211,9 @@ test("action=morph", async () => {
210211
assert.equal(subject.find("h1#hello")?.textContent, "Hello Turbo Morphed")
211212
})
212213

213-
test("action=morph with text content change", async () => {
214+
test("action=replace method=morph with text content change", async () => {
214215
const templateElement = createTemplateElement(`<div id="hello">Hello Turbo Morphed</div>`)
215-
const element = createStreamElement("morph", "hello", templateElement)
216+
const element = createStreamElement("replace", "hello", templateElement, { method: "morph" })
216217

217218
assert.equal(subject.find("div#hello")?.textContent, "Hello Turbo")
218219

@@ -223,9 +224,9 @@ test("action=morph with text content change", async () => {
223224
assert.equal(subject.find("div#hello")?.textContent, "Hello Turbo Morphed")
224225
})
225226

226-
test("action=morph children-only", async () => {
227+
test("action=update method=morph", async () => {
227228
const templateElement = createTemplateElement(`<h1 id="hello-child-element">Hello Turbo Morphed</h1>`)
228-
const element = createStreamElement("morph", "hello", templateElement)
229+
const element = createStreamElement("update", "hello", templateElement, { method: "morph" })
229230
const target = subject.find("div#hello")
230231
assert.equal(target?.textContent, "Hello Turbo")
231232
element.setAttribute("children-only", true)

0 commit comments

Comments
 (0)