diff --git a/src/core/frames/frame_controller.ts b/src/core/frames/frame_controller.ts index cc1e40f57..86fa98aa8 100644 --- a/src/core/frames/frame_controller.ts +++ b/src/core/frames/frame_controller.ts @@ -38,7 +38,7 @@ export type TurboFrameMissingEvent = CustomEvent<{ response: Response; visit: Vi export class FrameController implements - AppearanceObserverDelegate, + AppearanceObserverDelegate, FetchRequestDelegate, FormSubmitObserverDelegate, FormSubmissionDelegate, @@ -49,7 +49,7 @@ export class FrameController { readonly element: FrameElement readonly view: FrameView - readonly appearanceObserver: AppearanceObserver + readonly appearanceObserver: AppearanceObserver readonly formLinkClickObserver: FormLinkClickObserver readonly linkInterceptor: LinkInterceptor readonly formSubmitObserver: FormSubmitObserver @@ -198,7 +198,9 @@ export class FrameController // Appearance observer delegate - elementAppearedInViewport(_element: Element) { + elementAppearedInViewport(element: FrameElement) { + this.pageSnapshot = PageSnapshot.fromElement(element).clone() + this.proposeVisitIfNavigatedWithAction(element, element) this.loadSourceURL() } diff --git a/src/observers/appearance_observer.ts b/src/observers/appearance_observer.ts index 65518429f..7a622a481 100644 --- a/src/observers/appearance_observer.ts +++ b/src/observers/appearance_observer.ts @@ -1,14 +1,14 @@ -export interface AppearanceObserverDelegate { - elementAppearedInViewport(element: Element): void +export interface AppearanceObserverDelegate { + elementAppearedInViewport(element: T): void } -export class AppearanceObserver { - readonly delegate: AppearanceObserverDelegate - readonly element: Element +export class AppearanceObserver { + readonly delegate: AppearanceObserverDelegate + readonly element: T readonly intersectionObserver: IntersectionObserver started = false - constructor(delegate: AppearanceObserverDelegate, element: Element) { + constructor(delegate: AppearanceObserverDelegate, element: T) { this.delegate = delegate this.element = element this.intersectionObserver = new IntersectionObserver(this.intersect) diff --git a/src/tests/fixtures/frame_navigation.html b/src/tests/fixtures/frame_navigation.html index 11cdc37ff..50020cb79 100644 --- a/src/tests/fixtures/frame_navigation.html +++ b/src/tests/fixtures/frame_navigation.html @@ -17,6 +17,13 @@

Frame Navigation

Self Frame Top + +
+ + +

Eager-loaded frame: Not Loaded

+
diff --git a/src/tests/functional/frame_navigation_tests.ts b/src/tests/functional/frame_navigation_tests.ts index fbdac2a51..3a2fadde1 100644 --- a/src/tests/functional/frame_navigation_tests.ts +++ b/src/tests/functional/frame_navigation_tests.ts @@ -1,5 +1,5 @@ import { test } from "@playwright/test" -import { getFromLocalStorage, nextEventNamed, nextEventOnTarget, pathname } from "../helpers/page" +import { getFromLocalStorage, nextEventNamed, nextEventOnTarget, pathname, scrollToSelector } from "../helpers/page" import { assert } from "chai" test("test frame navigation with descendant link", async ({ page }) => { @@ -30,6 +30,18 @@ test("test frame navigation emits fetch-request-error event when offline", async await nextEventOnTarget(page, "tab-frame", "turbo:fetch-request-error") }) +test("test lazy-loaded frame promotes navigation", async ({ page }) => { + await page.goto("/src/tests/fixtures/frame_navigation.html") + + assert.equal(await page.textContent("#eager-loaded-frame h2"), "Eager-loaded frame: Not Loaded") + + await scrollToSelector(page, "#eager-loaded-frame") + await nextEventOnTarget(page, "eager-loaded-frame", "turbo:frame-load") + + assert.equal(await page.textContent("#eager-loaded-frame h2"), "Eager-loaded frame: Loaded") + assert.equal(pathname(page.url()), "/src/tests/fixtures/frames/frame_for_eager.html") +}) + test("test promoted frame navigation updates the URL before rendering", async ({ page }) => { await page.goto("/src/tests/fixtures/tabs.html")