From f52a47f49567bd1b2aca637d41d8f7eba5850c88 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Sat, 16 Jul 2022 12:37:34 -0400 Subject: [PATCH 1/2] Introduce `FormLinkInterceptor` In an effort to match the patterns established by `LinkInterceptor` and `FormInterceptor`, this commit introduces a `FormLinkInterceptor` and `FormLinkInterceptorDelegate`. Behind the scenes, the `FormLinkInterceptor` relies on an instance of the `LinkInterceptor` to intervene in `` element clicks when `[data-turbo-method]` or `[data-turbo-stream]` are present. When those clicks are detected, it creates a `Turbo method post to targeted frame
diff --git a/src/tests/functional/form_submission_tests.ts b/src/tests/functional/form_submission_tests.ts index cc713df85..fcbd8eaea 100644 --- a/src/tests/functional/form_submission_tests.ts +++ b/src/tests/functional/form_submission_tests.ts @@ -976,6 +976,16 @@ test("test POST to external action targetting frame ignored", async ({ page }) = assert.equal(page.url(), "https://httpbin.org/post") }) +test("test following a link with data-turbo-method set and a target set navigates the target frame", async ({ + page, +}) => { + await page.click("#turbo-method-post-to-targeted-frame") + await nextBeat() + + const frameText = await page.locator("#hello h2") + assert.equal(await frameText.textContent(), "Hello from a frame") +}) + function formSubmitStarted(page: Page) { return getFromLocalStorage(page, "formSubmitStarted") } From 2777608f12b41869596b02237c51adf211b003f0 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Sat, 16 Jul 2022 17:25:56 -0400 Subject: [PATCH 2/2] Account for `[data-turbo="false"]` and `Turbo.session.drive = false` Closes https://github.com/hotwired/turbo/pull/500 --- src/observers/form_link_interceptor.ts | 3 +- src/tests/functional/form_submission_tests.ts | 65 +++++++++++++++---- 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/observers/form_link_interceptor.ts b/src/observers/form_link_interceptor.ts index 8bc7b720d..c7623fe44 100644 --- a/src/observers/form_link_interceptor.ts +++ b/src/observers/form_link_interceptor.ts @@ -31,8 +31,9 @@ export class FormLinkInterceptor implements LinkInterceptorDelegate { linkClickIntercepted(link: Element, action: string): void { const form = document.createElement("form") + form.setAttribute("data-turbo", "true") form.setAttribute("action", action) - form.hidden = true + form.setAttribute("hidden", "") const method = link.getAttribute("data-turbo-method") if (method) form.setAttribute("method", method) diff --git a/src/tests/functional/form_submission_tests.ts b/src/tests/functional/form_submission_tests.ts index fcbd8eaea..eabaa2ccd 100644 --- a/src/tests/functional/form_submission_tests.ts +++ b/src/tests/functional/form_submission_tests.ts @@ -803,7 +803,7 @@ test("test link method form submission inside frame", async ({ page }) => { await page.click("#link-method-inside-frame") await nextBeat() - assert.equal(await await page.textContent("#frame h2"), "Frame: Loaded") + assert.equal(await page.textContent("#frame h2"), "Frame: Loaded") assert.notOk(await hasSelector(page, "#nested-child")) }) @@ -898,6 +898,59 @@ test("test link method form submission outside frame", async ({ page }) => { assert.equal(await title.textContent(), "Hello") }) +test("test following a link with [data-turbo-method] set and a target set navigates the target frame", async ({ + page, +}) => { + await page.click("#turbo-method-post-to-targeted-frame") + + assert.equal(await page.textContent("#hello h2"), "Hello from a frame", "drives the turbo-frame") +}) + +test("test following a link with [data-turbo-method] and [data-turbo=true] set when html[data-turbo=false]", async ({ + page, +}) => { + const html = await page.locator("html") + await html.evaluate((html) => html.setAttribute("data-turbo", "false")) + + const link = await page.locator("#turbo-method-post-to-targeted-frame") + await link.evaluate((link) => link.setAttribute("data-turbo", "true")) + + await link.click() + + assert.equal(await page.textContent("h1"), "Form", "does not navigate the full page") + assert.equal(await page.textContent("#hello h2"), "Hello from a frame", "drives the turbo-frame") +}) + +test("test following a link with [data-turbo-method] and [data-turbo=true] set when Turbo.session.drive = false", async ({ + page, +}) => { + await page.evaluate(() => (window.Turbo.session.drive = false)) + + const link = await page.locator("#turbo-method-post-to-targeted-frame") + await link.evaluate((link) => link.setAttribute("data-turbo", "true")) + + await link.click() + + assert.equal(await page.textContent("h1"), "Form", "does not navigate the full page") + assert.equal(await page.textContent("#hello h2"), "Hello from a frame", "drives the turbo-frame") +}) + +test("test following a link with [data-turbo-method] set when html[data-turbo=false]", async ({ page }) => { + const html = await page.locator("html") + await html.evaluate((html) => html.setAttribute("data-turbo", "false")) + + await page.click("#turbo-method-post-to-targeted-frame") + + assert.equal(await page.textContent("h1"), "Hello", "treats link as a full-page navigation") +}) + +test("test following a link with [data-turbo-method] set when Turbo.session.drive = false", async ({ page }) => { + await page.evaluate(() => (window.Turbo.session.drive = false)) + await page.click("#turbo-method-post-to-targeted-frame") + + assert.equal(await page.textContent("h1"), "Hello", "treats link as a full-page navigation") +}) + test("test stream link method form submission outside frame", async ({ page }) => { await page.click("#stream-link-method-outside-frame") await nextBeat() @@ -976,16 +1029,6 @@ test("test POST to external action targetting frame ignored", async ({ page }) = assert.equal(page.url(), "https://httpbin.org/post") }) -test("test following a link with data-turbo-method set and a target set navigates the target frame", async ({ - page, -}) => { - await page.click("#turbo-method-post-to-targeted-frame") - await nextBeat() - - const frameText = await page.locator("#hello h2") - assert.equal(await frameText.textContent(), "Hello from a frame") -}) - function formSubmitStarted(page: Page) { return getFromLocalStorage(page, "formSubmitStarted") }