Skip to content

Commit

Permalink
Add turbo:fetch-request-error event on frame and form network errors (#…
Browse files Browse the repository at this point in the history
…640)

* Add turbo:fetch-error event on frame and form network errors

closes #462

This PR adds a new event called `turbo:fetch-error` that dispatches
when a form or frame fetch request errors.

This event will let developers respond appropriately when a fetch request
fails due network errors (such as on flaky wifi).

At the moment, if a frame navigation fetch request fails due to a network
error an error is thrown so https://github.com/hotwired/turbo/blob/2d5cdda4c030658da21965cb20d2885ca7c3e127/src/http/fetch_request.ts#L107 never runs
and therefore the `turbo:before-fetch-response` event is not dispatched.

* Update src/core/frames/frame_controller.ts

Co-authored-by: Keith Cirkel <keithamus@users.noreply.github.com>

* Update src/core/drive/form_submission.ts

Co-authored-by: Keith Cirkel <keithamus@users.noreply.github.com>

* Add spec

* Get browser name right

* Fetch project name properly

* Use page.context()

* remove timeout on offline

* Use first page to reduce go to calls

* Use tabs again since behavior is different when using turbo-action

* use broader event assertion

* Update event name and export type

* add new event to test helper

* Limit recursion in the test helper

* skip the details obj instead of limiting recursion

Co-authored-by: Keith Cirkel <keithamus@users.noreply.github.com>
  • Loading branch information
srt32 and keithamus authored Aug 3, 2022
1 parent 60c6463 commit 14ae828
Show file tree
Hide file tree
Showing 7 changed files with 22 additions and 2 deletions.
5 changes: 5 additions & 0 deletions src/core/drive/form_submission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FetchResponse } from "../../http/fetch_response"
import { expandURL } from "../url"
import { dispatch, getMetaContent } from "../../util"
import { StreamMessage } from "../streams/stream_message"
import { TurboFetchRequestErrorEvent } from "../session"

export interface FormSubmissionDelegate {
formSubmissionStarted(formSubmission: FormSubmission): void
Expand Down Expand Up @@ -199,6 +200,10 @@ export class FormSubmission {

requestErrored(request: FetchRequest, error: Error) {
this.result = { success: false, error }
dispatch<TurboFetchRequestErrorEvent>("turbo:fetch-request-error", {
target: this.formElement,
detail: { request, error },
})
this.delegate.formSubmissionErrored(this, error)
}

Expand Down
6 changes: 5 additions & 1 deletion src/core/frames/frame_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { FrameRenderer } from "./frame_renderer"
import { session } from "../index"
import { isAction, Action } from "../types"
import { VisitOptions } from "../drive/visit"
import { TurboBeforeFrameRenderEvent } from "../session"
import { TurboBeforeFrameRenderEvent, TurboFetchRequestErrorEvent } from "../session"
import { StreamMessage } from "../streams/stream_message"

export class FrameController
Expand Down Expand Up @@ -247,6 +247,10 @@ export class FrameController

requestErrored(request: FetchRequest, error: Error) {
console.error(error)
dispatch<TurboFetchRequestErrorEvent>("turbo:fetch-request-error", {
target: this.element,
detail: { request, error },
})
this.resolveVisitPromise()
}

Expand Down
1 change: 1 addition & 0 deletions src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export {
TurboBeforeRenderEvent,
TurboBeforeVisitEvent,
TurboClickEvent,
TurboFetchRequestErrorEvent,
TurboFrameLoadEvent,
TurboFrameRenderEvent,
TurboLoadEvent,
Expand Down
2 changes: 2 additions & 0 deletions src/core/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { FrameElement } from "../elements/frame_element"
import { FrameViewRenderOptions } from "./frames/frame_view"
import { FetchResponse } from "../http/fetch_response"
import { Preloader, PreloaderDelegate } from "./drive/preloader"
import { FetchRequest } from "../http/fetch_request"

export type FormMode = "on" | "off" | "optin"
export type TimingData = unknown
Expand All @@ -30,6 +31,7 @@ export type TurboBeforeVisitEvent = CustomEvent<{ url: string }>
export type TurboClickEvent = CustomEvent<{ url: string; originalEvent: MouseEvent }>
export type TurboFrameLoadEvent = CustomEvent
export type TurboBeforeFrameRenderEvent = CustomEvent<{ newFrame: FrameElement } & FrameViewRenderOptions>
export type TurboFetchRequestErrorEvent = CustomEvent<{ request: FetchRequest; error: Error }>
export type TurboFrameRenderEvent = CustomEvent<{ fetchResponse: FetchResponse }>
export type TurboLoadEvent = CustomEvent<{ url: string; timing: TimingData }>
export type TurboRenderEvent = CustomEvent
Expand Down
2 changes: 1 addition & 1 deletion src/tests/fixtures/tabs.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html data-skip-event-details="turbo:fetch-request-error">
<head>
<meta charset="utf-8">
<title>Tabs</title>
Expand Down
1 change: 1 addition & 0 deletions src/tests/fixtures/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"turbo:before-fetch-response",
"turbo:visit",
"turbo:before-frame-render",
"turbo:fetch-request-error",
"turbo:frame-load",
"turbo:frame-render",
"turbo:reload"
Expand Down
7 changes: 7 additions & 0 deletions src/tests/functional/frame_navigation_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ test("test frame navigation with exterior link", async ({ page }) => {
await nextEventOnTarget(page, "frame", "turbo:frame-load")
})

test("test frame navigation emits fetch-request-error event when offline", async ({ page }) => {
await page.goto("/src/tests/fixtures/tabs.html")
await page.context().setOffline(true)
await page.click("#tab-2")
await nextEventNamed(page, "turbo:fetch-request-error")
})

test("test promoted frame navigation updates the URL before rendering", async ({ page }) => {
await page.goto("/src/tests/fixtures/tabs.html")

Expand Down

0 comments on commit 14ae828

Please sign in to comment.