Skip to content

Commit eae8f41

Browse files
authored
Merge pull request rails#49267 from JoeDupuis/integration-test-save-and-open-page
Add `save_and_open_page` helper to IntegrationTest
2 parents fd3a7a2 + 7f9ce6f commit eae8f41

File tree

6 files changed

+132
-0
lines changed

6 files changed

+132
-0
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,4 @@ gem "wdm", ">= 0.1.0", platforms: [:windows]
196196
if RUBY_VERSION < "3.2"
197197
gem "error_highlight", ">= 0.4.0", platforms: [:ruby]
198198
end
199+
gem "launchy"

Gemfile.lock

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ GEM
305305
kramdown-parser-gfm (1.1.0)
306306
kramdown (~> 2.0)
307307
language_server-protocol (3.17.0.3)
308+
launchy (2.5.2)
309+
addressable (~> 2.8)
308310
libxml-ruby (5.0.3)
309311
listen (3.8.0)
310312
rb-fsevent (~> 0.10, >= 0.10.3)
@@ -613,6 +615,7 @@ DEPENDENCIES
613615
jbuilder
614616
jsbundling-rails
615617
json (>= 2.0.0, != 2.7.0)
618+
launchy
616619
libxml-ruby
617620
listen (~> 3.3)
618621
mdl (!= 0.13.0)

actionpack/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
* Add `save_and_open_page` helper to IntegrationTest
2+
`save_and_open_page` is a helpful helper to keep a short feedback loop when working on system tests.
3+
A similar helper with matching signature has been added to integration tests.
4+
5+
*Joé Dupuis*
6+
17
* Fix a regression in 7.1.3 passing a `to:` option without a controller when the controller is already defined by a scope.
28

39
```ruby

actionpack/lib/action_dispatch/testing/integration.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
require "active_support/test_case"
99

1010
require "action_dispatch/testing/request_encoder"
11+
require "action_dispatch/testing/test_helpers/page_dump_helper"
1112

1213
module ActionDispatch
1314
module Integration # :nodoc:
@@ -651,6 +652,7 @@ module Behavior
651652

652653
include Integration::Runner
653654
include ActionController::TemplateAssertions
655+
include TestHelpers::PageDumpHelper
654656

655657
included do
656658
include ActionDispatch::Routing::UrlFor
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
module ActionDispatch
4+
module TestHelpers
5+
module PageDumpHelper
6+
class InvalidResponse < StandardError; end
7+
8+
# Saves the content of response body to a file and tries to open it in your browser.
9+
# Launchy must be present in your Gemfile for the page to open automatically.
10+
def save_and_open_page(path = html_dump_defaul_path)
11+
save_page(path).tap { |s_path| open_file(s_path) }
12+
end
13+
14+
private
15+
def save_page(path = html_dump_defaul_path)
16+
raise InvalidResponse.new("Response is a redirection!") if response.redirection?
17+
path = Pathname.new(path)
18+
path.dirname.mkpath
19+
File.write(path, response.body)
20+
path
21+
end
22+
23+
def open_file(path)
24+
require "launchy"
25+
Launchy.open(path)
26+
rescue LoadError
27+
warn "File saved to #{path}.\nPlease install the launchy gem to open the file automatically."
28+
end
29+
30+
def html_dump_defaul_path
31+
Rails.root.join("tmp/html_dump", "#{method_name}_#{DateTime.current.to_i}.html").to_s
32+
end
33+
end
34+
end
35+
end

actionpack/test/controller/integration_test.rb

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require "abstract_unit"
44
require "controller/fake_controllers"
55
require "rails/engine"
6+
require "launchy"
67

78
class SessionTest < ActiveSupport::TestCase
89
StubApp = lambda { |env|
@@ -1307,3 +1308,87 @@ def test_fixture_file_upload
13071308
assert_equal "45142", @response.body
13081309
end
13091310
end
1311+
1312+
class PageDumpIntegrationTest < ActionDispatch::IntegrationTest
1313+
class FooController < ActionController::Base
1314+
def index
1315+
render plain: "Hello world"
1316+
end
1317+
1318+
def redirect
1319+
redirect_to action: :index
1320+
end
1321+
end
1322+
1323+
def with_root(&block)
1324+
Rails.stub(:root, Pathname.getwd.join("test"), &block)
1325+
end
1326+
1327+
def setup
1328+
with_root do
1329+
remove_dumps
1330+
end
1331+
end
1332+
1333+
def teardown
1334+
with_root do
1335+
remove_dumps
1336+
end
1337+
end
1338+
1339+
def self.routes
1340+
@routes ||= ActionDispatch::Routing::RouteSet.new
1341+
end
1342+
1343+
def self.call(env)
1344+
routes.call(env)
1345+
end
1346+
1347+
def app
1348+
self.class
1349+
end
1350+
1351+
def dump_path
1352+
Pathname.new(Dir["#{Rails.root}/tmp/html_dump/#{method_name}*"].sole)
1353+
end
1354+
1355+
def remove_dumps
1356+
Dir["#{Rails.root}/tmp/html_dump/#{method_name}*"].each(&File.method(:delete))
1357+
end
1358+
1359+
routes.draw do
1360+
get "/" => "page_dump_integration_test/foo#index"
1361+
get "/redirect" => "page_dump_integration_test/foo#redirect"
1362+
end
1363+
1364+
test "save_and_open_page saves a copy of the page and call to Launchy" do
1365+
launchy_called = false
1366+
get "/"
1367+
with_root do
1368+
Launchy.stub(:open, ->(path) { launchy_called = (path == dump_path) }) do
1369+
save_and_open_page
1370+
end
1371+
assert launchy_called
1372+
assert_equal File.read(dump_path), response.body
1373+
end
1374+
end
1375+
1376+
test "prints a warning to install launchy if it can't be loaded" do
1377+
get "/"
1378+
with_root do
1379+
Launchy.stub(:open, ->(path) { raise LoadError.new }) do
1380+
self.stub(:warn, ->(warning) { warning.include?("Please install the launchy gem to open the file automatically.") }) do
1381+
save_and_open_page
1382+
end
1383+
end
1384+
assert_equal File.read(dump_path), response.body
1385+
end
1386+
end
1387+
1388+
test "raises when called after a redirect" do
1389+
with_root do
1390+
get "/redirect"
1391+
assert_raise(InvalidResponse) { save_and_open_page }
1392+
end
1393+
end
1394+
end

0 commit comments

Comments
 (0)