Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Turbo Morph with Dialog causes issues #1239

Open
htcarr3 opened this issue Apr 4, 2024 · 1 comment
Open

Turbo Morph with Dialog causes issues #1239

htcarr3 opened this issue Apr 4, 2024 · 1 comment

Comments

@htcarr3
Copy link

htcarr3 commented Apr 4, 2024

When a <dialog> element is opened modally with .showModal(), the browser moves it into the top layer. Morphing seems to reload the content on the page, but does not reset the top layer. From the user's perspective, nothing on the page is interactive because everything is stuck underneath the top layer (even though the top layer is empty). I'm not sure what the solution to this is given there is no api to interact directly with the top layer. Maybe this can be solved with event listeners to either skip or .close() these sorts of elements.

@seanpdoyle
Copy link
Contributor

@htcarr3 thank you for opening this issue. I test this locally by making the following changes to Turbo's test suite:

diff --git a/src/tests/fixtures/page_refresh.html b/src/tests/fixtures/page_refresh.html
index c058667..1ba8e92 100644
--- a/src/tests/fixtures/page_refresh.html
+++ b/src/tests/fixtures/page_refresh.html
@@ -82,6 +82,11 @@
 
     <a href="/src/tests/fixtures/page_refresh.html" id="reload-link">Reload</a>
 
+    <dialog id="modal">
+      Opened
+      <a href="/src/tests/fixtures/page_refresh.html">Reload</a>
+    </dialog>
+
     <turbo-frame id="refresh-morph" src="/src/tests/fixtures/frame_refresh_morph.html" refresh="morph">
       <h2>Frame to be morphed</h2>
     </turbo-frame>
diff --git a/src/tests/functional/page_refresh_tests.js b/src/tests/functional/page_refresh_tests.js
index c5c116c..a2bce0b 100644
--- a/src/tests/functional/page_refresh_tests.js
+++ b/src/tests/functional/page_refresh_tests.js
@@ -337,6 +337,18 @@ test("doesn't render previews when morphing", async ({ page }) => {
   assert.equal(await title.textContent(), "Page to be refreshed")
 })
 
+test("closes modal dialogs when morphing", async ({ page }) => {
+  await page.goto("/src/tests/fixtures/page_refresh.html")
+  const dialog = page.locator("dialog#modal")
+  const input = page.locator("input[name=query]")
+
+  await dialog.evaluate((dialog) => dialog.showModal())
+  await page.click("dialog#modal a")
+  await input.fill("element is interactive")
+
+  await expect(input).toBeFocused()
+})
+
 async function assertPageScroll(page, top, left) {
   const [scrollTop, scrollLeft] = await page.evaluate(() => {
     return [

Unfortunately, the test passed without any implementation changes, so I wasn't able to reproduce the unexpected behavior.

Could you share a reproducible test case? I've shared a Rails bug script template below. Could you modify it so that it mimics the behavior your application is exhibiting?

Copy-paste this into a `bug.rb` file, then execute `ruby bug.rb`
require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  git_source(:github) { |repo| "https://github.com/#{repo}.git" }

  gem "rails"
  gem "propshaft"
  gem "puma"
  gem "sqlite3"
  gem "turbo-rails"

  gem "capybara"
  gem "cuprite", "~> 0.9", require: "capybara/cuprite"
end

ENV["DATABASE_URL"] = "sqlite3::memory:"
ENV["RAILS_ENV"] = "test"

require "active_record/railtie"
# require "active_storage/engine"
require "action_controller/railtie"
require "action_view/railtie"
# require "action_mailer/railtie"
# require "active_job/railtie"
require "action_cable/engine"
# require "action_mailbox/engine"
# require "action_text/engine"
require "rails/test_unit/railtie"

class App < Rails::Application
  config.load_defaults Rails::VERSION::STRING.to_f

  config.root = __dir__
  config.hosts << "example.org"
  config.eager_load = false
  config.session_store :cookie_store, key: "cookie_store_key"
  config.secret_key_base = "secret_key_base"
  config.consider_all_requests_local = true
  config.action_cable.cable = {"adapter" => "async"}
  config.turbo.draw_routes = false

  Rails.logger = config.logger = Logger.new($stdout)

  routes.append do
    root to: "application#index"
  end
end

Rails.application.initialize!

ActiveRecord::Schema.define do
  create_table :messages, force: true do |t|
    t.text :body, null: false
  end
end

class Message < ActiveRecord::Base
end

class ApplicationController < ActionController::Base
  include Rails.application.routes.url_helpers

  class_attribute :template, default: DATA.read

  def index
    render inline: template, formats: :html
  end
end

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  driven_by :cuprite, using: :chrome, screen_size: [1400, 1400], options: { js_errors: true }
end

Capybara.configure do |config|
  config.server = :puma, {Silent: true}
  config.default_normalize_ws = true
end

require "rails/test_help"

class TurboSystemTest < ApplicationSystemTestCase
  test "reproduces bug" do
    visit root_path

    assert_text "Loaded with Turbo"
  end
end

__END__

<!DOCTYPE html>
<html>
  <head>
    <%= csrf_meta_tags %>

    <script type="importmap">
      {
        "imports": {
          "@hotwired/turbo-rails": "<%= asset_path("turbo.js") %>"
        }
      }
    </script>

    <script type="module">
      import "@hotwired/turbo-rails"

      addEventListener("turbo:load", () => document.body.innerHTML = "Loaded with Turbo")
    </script>
  </head>

  <body>Loaded without Turbo</body>
</html>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants