From 78c544af4fb78132dde7a893bc18bde38b5a9109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A9=20Dupuis?= Date: Wed, 13 Sep 2023 12:21:19 -0700 Subject: [PATCH] Add `save_and_open_page` helper to IntegrationTest `save_and_open_page` is a capybara helper that lets developers inspect the status of the page at any given point in their test. This is helpful when trying to keep a short feedback loop while working on a test. This change adds a similar helper with matching signature to integration tests. --- Gemfile | 1 + Gemfile.lock | 3 + actionpack/CHANGELOG.md | 6 ++ .../action_dispatch/testing/integration.rb | 2 + .../testing/test_helpers/page_dump_helper.rb | 35 ++++++++ .../test/controller/integration_test.rb | 85 +++++++++++++++++++ 6 files changed, 132 insertions(+) create mode 100644 actionpack/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb diff --git a/Gemfile b/Gemfile index f6fc8c1bc91b4..445b2c4838063 100644 --- a/Gemfile +++ b/Gemfile @@ -196,3 +196,4 @@ gem "wdm", ">= 0.1.0", platforms: [:windows] if RUBY_VERSION < "3.2" gem "error_highlight", ">= 0.4.0", platforms: [:ruby] end +gem "launchy" diff --git a/Gemfile.lock b/Gemfile.lock index 8a78c4e034efc..9dbc277f7839e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -305,6 +305,8 @@ GEM kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) language_server-protocol (3.17.0.3) + launchy (2.5.2) + addressable (~> 2.8) libxml-ruby (5.0.0) listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) @@ -613,6 +615,7 @@ DEPENDENCIES jbuilder jsbundling-rails json (>= 2.0.0, != 2.7.0) + launchy libxml-ruby listen (~> 3.3) mdl (!= 0.13.0) diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index f86b51e6393e5..18572a89dc664 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -6,6 +6,12 @@ *DHH* +* Add `save_and_open_page` helper to IntegrationTest + `save_and_open_page` is a helpful helper to keep a short feedback loop when working on system tests. + A similar helper with matching signature has been added to integration tests. + + *JoƩ Dupuis* + * Add `allow_browser` to set minimum browser versions for the application. A browser that's blocked will by default be served the file in `public/426.html` with a HTTP status code of "426 Upgrade Required". diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 1acec055f7fe4..8cd6992ccb477 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -8,6 +8,7 @@ require "active_support/test_case" require "action_dispatch/testing/request_encoder" +require "action_dispatch/testing/test_helpers/page_dump_helper" module ActionDispatch module Integration # :nodoc: @@ -651,6 +652,7 @@ module Behavior include Integration::Runner include ActionController::TemplateAssertions + include TestHelpers::PageDumpHelper included do include ActionDispatch::Routing::UrlFor diff --git a/actionpack/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb b/actionpack/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb new file mode 100644 index 0000000000000..f9309adb1f15b --- /dev/null +++ b/actionpack/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module ActionDispatch + module TestHelpers + module PageDumpHelper + class InvalidResponse < StandardError; end + + # Saves the content of response body to a file and tries to open it in your browser. + # Launchy must be present in your Gemfile for the page to open automatically. + def save_and_open_page(path = html_dump_defaul_path) + save_page(path).tap { |s_path| open_file(s_path) } + end + + private + def save_page(path = html_dump_defaul_path) + raise InvalidResponse.new("Response is a redirection!") if response.redirection? + path = Pathname.new(path) + path.dirname.mkpath + File.write(path, response.body) + path + end + + def open_file(path) + require "launchy" + Launchy.open(path) + rescue LoadError + warn "File saved to #{path}.\nPlease install the launchy gem to open the file automatically." + end + + def html_dump_defaul_path + Rails.root.join("tmp/html_dump", "#{method_name}_#{DateTime.current.to_i}.html").to_s + end + end + end +end diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 4925135d31a5a..43d8f85fe171f 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -3,6 +3,7 @@ require "abstract_unit" require "controller/fake_controllers" require "rails/engine" +require "launchy" class SessionTest < ActiveSupport::TestCase StubApp = lambda { |env| @@ -1307,3 +1308,87 @@ def test_fixture_file_upload assert_equal "45142", @response.body end end + +class PageDumpIntegrationTest < ActionDispatch::IntegrationTest + class FooController < ActionController::Base + def index + render plain: "Hello world" + end + + def redirect + redirect_to action: :index + end + end + + def with_root(&block) + Rails.stub(:root, Pathname.getwd.join("test"), &block) + end + + def setup + with_root do + remove_dumps + end + end + + def teardown + with_root do + remove_dumps + end + end + + def self.routes + @routes ||= ActionDispatch::Routing::RouteSet.new + end + + def self.call(env) + routes.call(env) + end + + def app + self.class + end + + def dump_path + Pathname.new(Dir["#{Rails.root}/tmp/html_dump/#{method_name}*"].sole) + end + + def remove_dumps + Dir["#{Rails.root}/tmp/html_dump/#{method_name}*"].each(&File.method(:delete)) + end + + routes.draw do + get "/" => "page_dump_integration_test/foo#index" + get "/redirect" => "page_dump_integration_test/foo#redirect" + end + + test "save_and_open_page saves a copy of the page and call to Launchy" do + launchy_called = false + get "/" + with_root do + Launchy.stub(:open, ->(path) { launchy_called = (path == dump_path) }) do + save_and_open_page + end + assert launchy_called + assert_equal File.read(dump_path), response.body + end + end + + test "prints a warning to install launchy if it can't be loaded" do + get "/" + with_root do + Launchy.stub(:open, ->(path) { raise LoadError.new }) do + self.stub(:warn, ->(warning) { warning.include?("Please install the launchy gem to open the file automatically.") }) do + save_and_open_page + end + end + assert_equal File.read(dump_path), response.body + end + end + + test "raises when called after a redirect" do + with_root do + get "/redirect" + assert_raise(InvalidResponse) { save_and_open_page } + end + end +end