Skip to content

Commit

Permalink
Respect morphing and scroll preservation settings when handling form …
Browse files Browse the repository at this point in the history
…errors

Turbo will render 422 responses to allow handling form errors. A common scenario
in Rails is to render those setting the satus like:

```
render "edit", status: :unprocessable_entity
```

This change will consider such operations a "page refresh" and will also consider
the scroll directive.
  • Loading branch information
jorgemanrubia committed Nov 9, 2023
1 parent 9944490 commit b77d283
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 3 deletions.
4 changes: 3 additions & 1 deletion src/core/drive/navigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ export class Navigator {
} else {
await this.view.renderPage(snapshot, false, true, this.currentVisit)
}
this.view.scrollToTop()
if(!snapshot.shouldPreserveScrollPosition) {
this.view.scrollToTop()
}
this.view.clearSnapshotCache()
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/drive/page_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class PageView extends View {
}

isPageRefresh(visit) {
return visit && this.lastRenderedLocation.href === visit.location.href
return !visit || this.lastRenderedLocation.href === visit.location.href
}

get snapshot() {
Expand Down
7 changes: 7 additions & 0 deletions src/tests/fixtures/page_refresh.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ <h3>Element with Stimulus controller</h3>
<input id="form-submit" type="submit" value="form[method=post]">
</form>

<div id="reject">
<form class="unprocessable_entity" action="/__turbo/reject" method="post" style="margin-top:100vh">
<input type="hidden" name="status" value="422">
<input type="submit">
</form>
</div>

<div id="container">
</div>
</body>
Expand Down
17 changes: 16 additions & 1 deletion src/tests/functional/page_refresh_tests.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { test, expect } from "@playwright/test"
import { assert } from "chai"
import {
hasSelector,
nextBeat,
nextBody,
nextEventNamed,
nextEventOnTarget,
noNextEventOnTarget,
Expand Down Expand Up @@ -53,7 +56,7 @@ test("don't refresh frames contained in [data-turbo-permanent] elements", async
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 }) => {
test("remote frames excluded from full page morphing", async ({ page }) => {
await page.goto("/src/tests/fixtures/page_refresh.html")

await page.evaluate(() => document.getElementById("remote-frame").setAttribute("data-modified", "true"))
Expand Down Expand Up @@ -126,6 +129,18 @@ test("it preserves data-turbo-permanent elements that don't match when their ids
await expect(page.locator("#preserve-me")).toHaveText("Preserve me, I have a family!")
})

test("renders unprocessable entity responses with morphing", async ({ page }) => {
await page.goto("/src/tests/fixtures/page_refresh.html")

await page.click("#reject form.unprocessable_entity input[type=submit]")
await nextEventNamed(page, "turbo:render", { renderMethod: "morph" })
await nextBody(page)

const title = await page.locator("h1")
assert.equal(await title.textContent(), "Unprocessable Entity", "renders the response HTML")
assert.notOk(await hasSelector(page, "#frame form.reject"), "replaces entire page")
})

async function assertPageScroll(page, top, left) {
const [scrollTop, scrollLeft] = await page.evaluate(() => {
return [
Expand Down

0 comments on commit b77d283

Please sign in to comment.