Skip to content

Commit

Permalink
Rely on eventLog channel in Functional Tests
Browse files Browse the repository at this point in the history
Replace the in-HTML test tracking of events with the existent
`eventLogs` remote channel.

In the `src/tests/fixtures/test.js` module, special case occurrences of
`event.detail.newFrame`, since it encodes a `<turbo-frame>` element that
consistently results in a StaleElementRefernce.
  • Loading branch information
seanpdoyle committed Feb 6, 2021
1 parent d65f931 commit 1a8a719
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 102 deletions.
2 changes: 1 addition & 1 deletion src/core/frames/frame_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export class FrameController implements AppearanceObserverDelegate, FetchRequest

viewWillRenderSnapshot(snapshot: Snapshot, isPreview: boolean) {
dispatch("turbo:before-frame-cache", { target: this.element })
dispatch("turbo:before-frame-render", { target: this.element, detail: { newBody: snapshot.element } })
dispatch("turbo:before-frame-render", { target: this.element, detail: { newFrame: snapshot.element } })
}

viewRenderedSnapshot(snapshot: Snapshot, isPreview: boolean) {
Expand Down
1 change: 1 addition & 0 deletions src/tests/fixtures/frame_navigation.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<meta charset="utf-8">
<title>Turbo</title>
<script src="/dist/turbo.es2017-umd.js" data-turbo-track="reload"></script>
<script src="/src/tests/fixtures/test.js"></script>
</head>
<body>
<div id="container">
Expand Down
15 changes: 11 additions & 4 deletions src/tests/fixtures/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,22 @@
}

function eventListener(event) {
eventLogs.push([event.type, event.detail])
if (event && event.detail && "newFrame" in event.detail) {
event.detail.newFrame = event.detail.newFrame.outerHTML
}
eventLogs.push([event.type, event.target.id, event.detail])
}

})([
"turbo:before-cache",
"turbo:before-render",
"turbo:before-visit",
"turbo:load",
"turbo:render",
"turbo:request-end",
"turbo:visit"
"turbo:visit",
"turbo:before-frame-cache",
"turbo:before-frame-render",
"turbo:before-frame-visit",
"turbo:frame-load",
"turbo:frame-render",
"turbo:frame-visit",
])
124 changes: 29 additions & 95 deletions src/tests/functional/frame_navigation_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,124 +3,58 @@ import { TurboDriveTestCase } from "../helpers/turbo_drive_test_case"
export class FrameNavigationTests extends TurboDriveTestCase {
async setup() {
await this.goToLocation("/src/tests/fixtures/frame_navigation.html")
await this.trackFrameEvents()
}

async "test frame navigation with descendant link"() {
await this.clickSelector("#inside")
await this.nextBeat
const link = await this.querySelector("#inside")
const href = await link.getAttribute("href")
await link.click()

const disptachedFrameEvents = await this.readDispatchedFrameEvents()
const [
[ beforeVisit, beforeVisitTarget, { url } ],
[ visit, visitTarget ],
[ beforeCache, beforeCacheTarget ],
[ beforeRender, beforeRenderTarget, { newBody } ],
[ render, renderTarget ],
[ load, loadTarget, { timing } ],
] = disptachedFrameEvents
const { url } = await this.nextEventOnTarget("frame", "turbo:before-frame-visit")
this.assert.ok(url.includes(href))
await this.nextEventOnTarget("frame", "turbo:frame-visit")
await this.nextEventOnTarget("frame", "turbo:before-frame-cache")

this.assert.equal(beforeVisit, "turbo:before-frame-visit")
this.assert.equal(beforeVisitTarget, "frame")
this.assert.ok(url.includes("/src/tests/fixtures/frame_navigation.html"))
const beforeFrameRender = await this.nextEventOnTarget("frame", "turbo:before-frame-render")
this.assert.ok("newFrame" in beforeFrameRender, "reference the new snapshot")
await this.nextEventOnTarget("frame", "turbo:frame-render")

this.assert.equal(visit, "turbo:frame-visit")
this.assert.equal(visitTarget, "frame")

this.assert.equal(beforeCache, "turbo:before-frame-cache")
this.assert.equal(beforeCacheTarget, "frame")

this.assert.equal(beforeRender, "turbo:before-frame-render")
this.assert.equal(beforeRenderTarget, "frame")
this.assert.ok(newBody)

this.assert.equal(render, "turbo:frame-render")
this.assert.equal(renderTarget, "frame")

this.assert.equal(load, "turbo:frame-load")
this.assert.equal(loadTarget, "frame")
const { timing } = await this.nextEventOnTarget("frame", "turbo:frame-load")
this.assert.ok(Object.keys(timing).length)
}

async "test frame navigation with exterior link"() {
await this.clickSelector("#outside")
await this.nextBeat

const disptachedFrameEvents = await this.readDispatchedFrameEvents()
const [
[ beforeVisit, beforeVisitTarget, { url } ],
[ visit, visitTarget ],
[ beforeCache, beforeCacheTarget ],
[ beforeRender, beforeRenderTarget, { newBody } ],
[ render, renderTarget ],
[ load, loadTarget, { timing } ],
] = disptachedFrameEvents

this.assert.equal(beforeVisit, "turbo:before-frame-visit")
this.assert.equal(beforeVisitTarget, "frame")
this.assert.ok(url.includes("/src/tests/fixtures/frame_navigation.html"))

this.assert.equal(visit, "turbo:frame-visit")
this.assert.equal(visitTarget, "frame")
const link = await this.querySelector("#outside")
const href = await link.getAttribute("href")
await link.click()

this.assert.equal(beforeCache, "turbo:before-frame-cache")
this.assert.equal(beforeCacheTarget, "frame")
const { url } = await this.nextEventOnTarget("frame", "turbo:before-frame-visit")
this.assert.ok(url.includes(href))
await this.nextEventOnTarget("frame", "turbo:frame-visit")
await this.nextEventOnTarget("frame", "turbo:before-frame-cache")

this.assert.equal(beforeRender, "turbo:before-frame-render")
this.assert.equal(beforeRenderTarget, "frame")
this.assert.ok(newBody)
const beforeFrameRender = await this.nextEventOnTarget("frame", "turbo:before-frame-render")
this.assert.ok("newFrame" in beforeFrameRender, "reference the new snapshot")
await this.nextEventOnTarget("frame", "turbo:frame-render")

this.assert.equal(render, "turbo:frame-render")
this.assert.equal(renderTarget, "frame")

this.assert.equal(load, "turbo:frame-load")
this.assert.equal(loadTarget, "frame")
const { timing } = await this.nextEventOnTarget("frame", "turbo:frame-load")
this.assert.ok(Object.keys(timing).length)
}

async "test frame navigation with cancelled visit"() {
const link = await this.querySelector("#inside")
const href= await link.getAttribute("href")
await this.remote.execute(() => addEventListener("turbo:before-frame-visit", (event) => event.preventDefault(), { once: true }))
await this.clickSelector("#inside")
await this.nextBeat

const disptachedFrameEvents = await this.readDispatchedFrameEvents()
const [
[ beforeVisit, beforeVisitTarget, { url } ],
...others
] = disptachedFrameEvents
await link.click()

this.assert.equal(beforeVisit, "turbo:before-frame-visit")
this.assert.equal(beforeVisitTarget, "frame")
this.assert.ok(url.includes("/src/tests/fixtures/frame_navigation.html"))
const { url } = await this.nextEventOnTarget("frame", "turbo:before-frame-visit")
this.assert.ok(url.includes(href))

this.assert.equal(others.length, 0, "prevents subsequent events")
const otherEvents = await this.eventLogChannel.read()
this.assert.equal(otherEvents.length, 0, "cancels subsequent events")
this.assert.ok(await this.hasSelector("#inside"), "does not navigate the frame")
}

async readDispatchedFrameEvents() {
const html = await this.querySelector("html")
const json = await html.getAttribute("data-events")

return JSON.parse(json || "[]")
}

async trackFrameEvents() {
this.remote.execute((eventNames: string[]) => {
const html = document.documentElement
const element = document.getElementById("frame")?.parentNode

if (element) {
eventNames.forEach(eventName => element.addEventListener(eventName, (event) => {
if (event instanceof CustomEvent && event.target instanceof HTMLElement) {
const dispatchedEvents = JSON.parse(html.getAttribute("data-events") || "[]")
const detail = event.detail || {}
dispatchedEvents.push([event.type, event.target.id, { ...detail, newBody: !!detail.newBody }])
html.setAttribute("data-events", JSON.stringify(dispatchedEvents))
}
}))
}
}, ["turbo:before-frame-visit turbo:frame-visit turbo:before-frame-cache turbo:before-frame-render turbo:frame-render turbo:frame-load".split(/\s+/)])
}
}

FrameNavigationTests.registerSuite()
13 changes: 11 additions & 2 deletions src/tests/helpers/turbo_drive_test_case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FunctionalTestCase } from "./functional_test_case"
import { RemoteChannel } from "./remote_channel"
import { Element } from "@theintern/leadfoot"

type EventLog = [string, any]
type EventLog = [string, string, any]

export class TurboDriveTestCase extends FunctionalTestCase {
eventLogChannel: RemoteChannel<EventLog> = new RemoteChannel(this.remote, "eventLogs")
Expand Down Expand Up @@ -30,7 +30,16 @@ export class TurboDriveTestCase extends FunctionalTestCase {
const records = await this.eventLogChannel.read(1)
record = records.find(([name]) => name == eventName)
}
return record[1]
return record[2]
}

async nextEventOnTarget(elementId: string, eventName: string): Promise<any> {
let record: EventLog | undefined
while (!record) {
const records = await this.eventLogChannel.read(1)
record = records.find(([name, id]) => name == eventName && id == elementId)
}
return record[2]
}

get nextBody(): Promise<Element> {
Expand Down

0 comments on commit 1a8a719

Please sign in to comment.