Skip to content

Commit

Permalink
Add test coverage for turbo-frame[busy]
Browse files Browse the repository at this point in the history
During the request lifecycle, `<turbo-frame>` elements will toggle the
`[busy]` boolean attribute to true when the request starts, and then
remove it when the request ends.

This commit adds functional test coverage for that behavior.
  • Loading branch information
seanpdoyle committed Feb 6, 2021
1 parent 57a118e commit c0970f5
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 6 deletions.
6 changes: 4 additions & 2 deletions src/core/frames/frame_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ export class FrameController implements AppearanceObserverDelegate, FetchRequest
// Form submission delegate

formSubmissionStarted(formSubmission: FormSubmission) {

const frame = this.findFrameElement(formSubmission.formElement)
frame.setAttribute("busy", "")
}

formSubmissionSucceededWithResponse(formSubmission: FormSubmission, response: FetchResponse) {
Expand All @@ -175,7 +176,8 @@ export class FrameController implements AppearanceObserverDelegate, FetchRequest
}

formSubmissionFinished(formSubmission: FormSubmission) {

const frame = this.findFrameElement(formSubmission.formElement)
frame.removeAttribute("busy")
}

// View delegate
Expand Down
7 changes: 6 additions & 1 deletion src/tests/fixtures/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,15 @@
</div>
<hr>
<div id="targets-frame">
<form action="/__turbo/redirect" method="post" data-turbo-frame="frame">
<form action="/__turbo/redirect" method="post" data-turbo-frame="frame" class="one">
<input type="hidden" name="path" value="/src/tests/fixtures/one.html">
<button type="submit">Submit</button>
</form>

<form action="/__turbo/redirect" method="post" data-turbo-frame="frame" class="frame">
<input type="hidden" name="path" value="/src/tests/fixtures/frames/frame.html">
<button type="submit">Submit</button>
</form>
</div>
<turbo-frame id="frame">
<h2>Frame: Form</h2>
Expand Down
1 change: 1 addition & 0 deletions src/tests/fixtures/frames.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<meta charset="utf-8">
<title>Frame</title>
<script src="/dist/turbo.es2017-umd.js" data-turbo-track="reload"></script>
<script src="/src/tests/fixtures/test.js"></script>
</head>
<body>
<h1>Frames</h1>
Expand Down
9 changes: 9 additions & 0 deletions src/tests/fixtures/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
eventLogs.push([event.type, event.detail])
}

window.mutationLogs = []

new MutationObserver((mutations) => {
for (const { attributeName, oldValue, target } of mutations.filter(({ type }) => type == "attributes")) {
if (target instanceof HTMLElement) {
mutationLogs.push([attributeName, target.id, target.getAttribute(attributeName)])
}
}
}).observe(document, { subtree: true, childList: true, attributes: true })
})([
"turbo:before-cache",
"turbo:before-render",
Expand Down
19 changes: 18 additions & 1 deletion src/tests/functional/form_submission_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,23 @@ export class FormSubmissionTests extends TurboDriveTestCase {
this.assert.equal(await this.pathname, "/src/tests/fixtures/form.html")
}

async "test frame form submission toggles the ancestor frame's [busy] attribute"() {
await this.clickSelector("#frame form.redirect input[type=submit]")

this.assert.equal(await this.nextAttributeMutationNamed("frame", "busy"), "", "sets [busy] on the #frame")
this.assert.equal(await this.nextAttributeMutationNamed("frame", "busy"), null, "removes [busy] from the #frame")
}

async "test frame form submission toggles the target frame's [busy] attribute"() {
await this.clickSelector('#targets-frame form.frame [type="submit"]')

this.assert.equal(await this.nextAttributeMutationNamed("frame", "busy"), "", "sets [busy] on the #frame")

const title = await this.querySelector("#frame h2")
this.assert.equal(await title.getVisibleText(), "Frame: Loaded")
this.assert.equal(await this.nextAttributeMutationNamed("frame", "busy"), null, "removes [busy] from the #frame")
}

async "test frame form submission with empty created response"() {
const htmlBefore = await this.outerHTMLForSelector("#frame")
const button = await this.querySelector("#frame form.created input[type=submit]")
Expand Down Expand Up @@ -254,7 +271,7 @@ export class FormSubmissionTests extends TurboDriveTestCase {

async "test form submission targets disabled frame"() {
this.remote.execute(() => document.getElementById("frame")?.setAttribute("disabled", ""))
await this.clickSelector('#targets-frame [type="submit"]')
await this.clickSelector('#targets-frame form.one [type="submit"]')
await this.nextBody

this.assert.equal(await this.pathname, "/src/tests/fixtures/one.html")
Expand Down
11 changes: 9 additions & 2 deletions src/tests/functional/frame_tests.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { FunctionalTestCase } from "../helpers/functional_test_case"
import { TurboDriveTestCase } from "../helpers/turbo_drive_test_case"

export class FrameTests extends FunctionalTestCase {
export class FrameTests extends TurboDriveTestCase {
async setup() {
await this.goToLocation("/src/tests/fixtures/frames.html")
}

async "test following a link driving a frame toggles the [busy] attribute"() {
await this.clickSelector("#hello a")

this.assert.equal(await this.nextAttributeMutationNamed("frame", "busy"), "", "sets [busy] on the #frame")
this.assert.equal(await this.nextAttributeMutationNamed("frame", "busy"), null, "removes [busy] from the #frame")
}

async "test following a link to a page without a matching frame results in an empty frame"() {
await this.clickSelector("#missing a")
await this.nextBeat
Expand Down
11 changes: 11 additions & 0 deletions src/tests/helpers/turbo_drive_test_case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { RemoteChannel } from "./remote_channel"
import { Element } from "@theintern/leadfoot"

type EventLog = [string, any]
type MutationLog = [string, string, string | null]

export class TurboDriveTestCase extends FunctionalTestCase {
eventLogChannel: RemoteChannel<EventLog> = new RemoteChannel(this.remote, "eventLogs")
mutationLogChannel: RemoteChannel<MutationLog> = new RemoteChannel(this.remote, "mutationLogs")
lastBody?: Element

async beforeTest() {
Expand Down Expand Up @@ -33,6 +35,15 @@ export class TurboDriveTestCase extends FunctionalTestCase {
return record[1]
}

async nextAttributeMutationNamed(elementId: string, attributeName: string): Promise<string | null> {
let record: MutationLog | undefined
while (!record) {
const records = await this.mutationLogChannel.read(1)
record = records.find(([attribute, id]) => id == elementId && attribute == attributeName)
}
return record[2]
}

get nextBody(): Promise<Element> {
return (async () => {
let body
Expand Down

0 comments on commit c0970f5

Please sign in to comment.