aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md11
-rw-r--r--actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb52
-rw-r--r--actionpack/test/dispatch/system_testing/screenshot_helper_test.rb79
-rw-r--r--activerecord/CHANGELOG.md4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/errors.rb2
-rw-r--r--activerecord/lib/active_record/fixture_set/file.rb6
-rw-r--r--activerecord/lib/active_record/fixtures.rb45
-rw-r--r--activerecord/test/cases/database_configurations_test.rb2
-rw-r--r--activerecord/test/cases/fixtures_test.rb27
-rw-r--r--activerecord/test/fixtures/other_books.yml26
-rw-r--r--activerecord/test/fixtures/parrots.yml8
-rw-r--r--activestorage/test/fixtures/files/racecar.tifbin33705838 -> 729182 bytes
-rw-r--r--activesupport/lib/active_support/core_ext/string/access.rb24
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb32
15 files changed, 247 insertions, 73 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 8bb2c73e52..90217755bc 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,12 @@
+* Allow system test screen shots to be taken more than once in
+ a test by prefixing the file name with an incrementing counter.
+
+ Add an environment variable `RAILS_SYSTEM_TESTING_SCREENSHOT_HTML` to
+ enable saving of HTML during a screenshot in addition to the image.
+ This uses the same image name, with the extension replaced with `.html`
+
+ *Tom Fakes*
+
* Add `Vary: Accept` header when using `Accept` header for response
For some requests like `/users/1`, Rails uses requests' `Accept`
@@ -80,7 +89,7 @@
*Gustavo Gutierrez*
-* Calling `ActionController::Parameters#transform_keys/!` without a block now returns
+* Calling `ActionController::Parameters#transform_keys`/`!` without a block now returns
an enumerator for the parameters instead of the underlying hash.
*Eugene Kenny*
diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb
index 056ce51a61..cba053ee4c 100644
--- a/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb
+++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb
@@ -9,10 +9,16 @@ module ActionDispatch
#
# +take_screenshot+ can be used at any point in your system tests to take
# a screenshot of the current state. This can be useful for debugging or
- # automating visual testing.
+ # automating visual testing. You can take multiple screenshots per test
+ # to investigate changes at different points during your test. These will be
+ # named with a sequential prefix (or 'failed' for failing tests)
#
# The screenshot will be displayed in your console, if supported.
#
+ # You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT_HTML+ environment variable to
+ # save the HTML from the page that is being screenhoted so you can investigate the
+ # elements on the page at the time of the screenshot
+ #
# You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT+ environment variable to
# control the output. Possible values are:
# * [+simple+ (default)] Only displays the screenshot path.
@@ -22,6 +28,8 @@ module ActionDispatch
# * [+artifact+] Display the screenshot in the terminal, using the terminal
# artifact format (https://buildkite.github.io/terminal-to-html/inline-images/).
def take_screenshot
+ increment_unique
+ save_html if save_html?
save_image
puts display_image
end
@@ -38,17 +46,48 @@ module ActionDispatch
end
private
+ attr_accessor :_screenshot_counter
+
+ def save_html?
+ ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"] == "1"
+ end
+
+ def increment_unique
+ @_screenshot_counter ||= 0
+ @_screenshot_counter += 1
+ end
+
+ def unique
+ failed? ? "failures" : (_screenshot_counter || 0).to_s
+ end
+
def image_name
- name = method_name[0...225]
- failed? ? "failures_#{name}" : name
+ name = "#{unique}_#{method_name}"
+ name[0...225]
end
def image_path
- @image_path ||= absolute_image_path.to_s
+ absolute_image_path.to_s
+ end
+
+ def html_path
+ absolute_html_path.to_s
+ end
+
+ def absolute_path
+ Rails.root.join("tmp/screenshots/#{image_name}")
end
def absolute_image_path
- Rails.root.join("tmp/screenshots/#{image_name}.png")
+ "#{absolute_path}.png"
+ end
+
+ def absolute_html_path
+ "#{absolute_path}.html"
+ end
+
+ def save_html
+ page.save_page(absolute_html_path)
end
def save_image
@@ -66,7 +105,8 @@ module ActionDispatch
end
def display_image
- message = +"[Screenshot]: #{image_path}\n"
+ message = +"[Screenshot Image]: #{image_path}\n"
+ message << +"[Screenshot HTML]: #{html_path}\n" if save_html?
case output_type
when "artifact"
diff --git a/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb b/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb
index b0b36f9d74..5d69a887ef 100644
--- a/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb
+++ b/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb
@@ -6,60 +6,93 @@ require "capybara/dsl"
require "selenium/webdriver"
class ScreenshotHelperTest < ActiveSupport::TestCase
+ def setup
+ @new_test = DrivenBySeleniumWithChrome.new("x")
+ @new_test.send("_screenshot_counter=", nil)
+ end
+
test "image path is saved in tmp directory" do
- new_test = DrivenBySeleniumWithChrome.new("x")
+ Rails.stub :root, Pathname.getwd do
+ assert_equal Rails.root.join("tmp/screenshots/0_x.png").to_s, @new_test.send(:image_path)
+ end
+ end
+
+ test "image path unique counter is changed when incremented" do
+ @new_test.send(:increment_unique)
Rails.stub :root, Pathname.getwd do
- assert_equal Rails.root.join("tmp/screenshots/x.png").to_s, new_test.send(:image_path)
+ assert_equal Rails.root.join("tmp/screenshots/1_x.png").to_s, @new_test.send(:image_path)
end
end
- test "image path includes failures text if test did not pass" do
- new_test = DrivenBySeleniumWithChrome.new("x")
+ # To allow multiple screenshots in same test
+ test "image path unique counter generates different path in same test" do
+ Rails.stub :root, Pathname.getwd do
+ @new_test.send(:increment_unique)
+ assert_equal Rails.root.join("tmp/screenshots/1_x.png").to_s, @new_test.send(:image_path)
+
+ @new_test.send(:increment_unique)
+ assert_equal Rails.root.join("tmp/screenshots/2_x.png").to_s, @new_test.send(:image_path)
+ end
+ end
+ test "image path includes failures text if test did not pass" do
Rails.stub :root, Pathname.getwd do
- new_test.stub :passed?, false do
- assert_equal Rails.root.join("tmp/screenshots/failures_x.png").to_s, new_test.send(:image_path)
+ @new_test.stub :passed?, false do
+ assert_equal Rails.root.join("tmp/screenshots/failures_x.png").to_s, @new_test.send(:image_path)
+ assert_equal Rails.root.join("tmp/screenshots/failures_x.html").to_s, @new_test.send(:html_path)
end
end
end
test "image path does not include failures text if test skipped" do
- new_test = DrivenBySeleniumWithChrome.new("x")
-
Rails.stub :root, Pathname.getwd do
- new_test.stub :passed?, false do
- new_test.stub :skipped?, true do
- assert_equal Rails.root.join("tmp/screenshots/x.png").to_s, new_test.send(:image_path)
+ @new_test.stub :passed?, false do
+ @new_test.stub :skipped?, true do
+ assert_equal Rails.root.join("tmp/screenshots/0_x.png").to_s, @new_test.send(:image_path)
+ assert_equal Rails.root.join("tmp/screenshots/0_x.html").to_s, @new_test.send(:html_path)
end
end
end
end
- test "image name truncates names over 225 characters" do
- new_test = DrivenBySeleniumWithChrome.new("x" * 400)
+ test "image name truncates names over 225 characters including counter" do
+ long_test = DrivenBySeleniumWithChrome.new("x" * 400)
Rails.stub :root, Pathname.getwd do
- assert_equal Rails.root.join("tmp/screenshots/#{"x" * 225}.png").to_s, new_test.send(:image_path)
+ assert_equal Rails.root.join("tmp/screenshots/0_#{"x" * 223}.png").to_s, long_test.send(:image_path)
+ assert_equal Rails.root.join("tmp/screenshots/0_#{"x" * 223}.html").to_s, long_test.send(:html_path)
end
end
test "defaults to simple output for the screenshot" do
- new_test = DrivenBySeleniumWithChrome.new("x")
- assert_equal "simple", new_test.send(:output_type)
+ assert_equal "simple", @new_test.send(:output_type)
+ end
+
+ test "display_image return html path when RAILS_SYSTEM_TESTING_SCREENSHOT_HTML environment" do
+ original_html_setting = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"]
+ ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"] = "1"
+
+ assert @new_test.send(:save_html?)
+
+ Rails.stub :root, Pathname.getwd do
+ @new_test.stub :passed?, false do
+ assert_match %r|\[Screenshot HTML\].+?tmp/screenshots/failures_x\.html|, @new_test.send(:display_image)
+ end
+ end
+ ensure
+ ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"] = original_html_setting
end
test "display_image return artifact format when specify RAILS_SYSTEM_TESTING_SCREENSHOT environment" do
original_output_type = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"]
ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] = "artifact"
- new_test = DrivenBySeleniumWithChrome.new("x")
-
- assert_equal "artifact", new_test.send(:output_type)
+ assert_equal "artifact", @new_test.send(:output_type)
Rails.stub :root, Pathname.getwd do
- new_test.stub :passed?, false do
- assert_match %r|url=artifact://.+?tmp/screenshots/failures_x\.png|, new_test.send(:display_image)
+ @new_test.stub :passed?, false do
+ assert_match %r|url=artifact://.+?tmp/screenshots/failures_x\.png|, @new_test.send(:display_image)
end
end
ensure
@@ -67,10 +100,8 @@ class ScreenshotHelperTest < ActiveSupport::TestCase
end
test "image path returns the absolute path from root" do
- new_test = DrivenBySeleniumWithChrome.new("x")
-
Rails.stub :root, Pathname.getwd.join("..") do
- assert_equal Rails.root.join("tmp/screenshots/x.png").to_s, new_test.send(:image_path)
+ assert_equal Rails.root.join("tmp/screenshots/0_x.png").to_s, @new_test.send(:image_path)
end
end
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 366032c734..7f2071189b 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Allow specifying fixtures to be ignored by setting `ignore` in YAML file's '_fixture' section.
+
+ *Tongfei Gao*
+
* Make the DATABASE_URL env variable only affect the primary connection. Add new env variables for multiple databases.
*John Crepezzi*, *Eileen Uchitelle*
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index ef1eef6b69..800235a302 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -572,7 +572,7 @@ module ActiveRecord
end
end
- # See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
+ # See https://dev.mysql.com/doc/refman/5.7/en/server-error-reference.html
ER_DUP_ENTRY = 1062
ER_NOT_NULL_VIOLATION = 1048
ER_NO_REFERENCED_ROW = 1216
diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb
index 20cc987d6e..bf7d99449d 100644
--- a/activerecord/lib/active_record/errors.rb
+++ b/activerecord/lib/active_record/errors.rb
@@ -334,7 +334,7 @@ module ActiveRecord
# See the following:
#
# * https://www.postgresql.org/docs/current/static/transaction-iso.html
- # * https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html#error_er_lock_deadlock
+ # * https://dev.mysql.com/doc/refman/5.7/en/server-error-reference.html#error_er_lock_deadlock
class TransactionRollbackError < StatementInvalid
end
diff --git a/activerecord/lib/active_record/fixture_set/file.rb b/activerecord/lib/active_record/fixture_set/file.rb
index f1ea0e022f..b2030a5bb9 100644
--- a/activerecord/lib/active_record/fixture_set/file.rb
+++ b/activerecord/lib/active_record/fixture_set/file.rb
@@ -29,6 +29,10 @@ module ActiveRecord
config_row["model_class"]
end
+ def ignored_fixtures
+ config_row["ignore"]
+ end
+
private
def rows
@rows ||= raw_rows.reject { |fixture_name, _| fixture_name == "_fixture" }
@@ -40,7 +44,7 @@ module ActiveRecord
if row
row.last
else
- { 'model_class': nil }
+ { 'model_class': nil, 'ignore': nil }
end
end
end
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 046ed0e95c..3df4b3c87f 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -420,6 +420,29 @@ module ActiveRecord
#
# Any fixture labeled "DEFAULTS" is safely ignored.
#
+ # Besides using "DEFAULTS", you can also specify what fixtures will
+ # be ignored by setting "ignore" in "_fixture" section.
+ #
+ # # users.yml
+ # _fixture:
+ # ignore:
+ # - base
+ # # or use "ignore: base" when there is only one fixture needs to be ignored.
+ #
+ # base: &base
+ # admin: false
+ # introduction: "This is a default description"
+ #
+ # admin:
+ # <<: *base
+ # admin: true
+ #
+ # visitor:
+ # <<: *base
+ #
+ # In the above example, 'base' will be ignored when creating fixtures.
+ # This can be used for common attributes inheriting.
+ #
# == Configure the fixture model class
#
# It's possible to set the fixture's model class directly in the YAML file.
@@ -614,7 +637,7 @@ module ActiveRecord
end
end
- attr_reader :table_name, :name, :fixtures, :model_class, :config
+ attr_reader :table_name, :name, :fixtures, :model_class, :ignored_fixtures, :config
def initialize(_, name, class_name, path, config = ActiveRecord::Base)
@name = name
@@ -647,8 +670,8 @@ module ActiveRecord
# Returns a hash of rows to be inserted. The key is the table, the value is
# a list of rows to insert to that table.
def table_rows
- # allow a standard key to be used for doing defaults in YAML
- fixtures.delete("DEFAULTS")
+ # allow specifying fixtures to be ignored by setting `ignore` in `_fixture` section
+ fixtures.except!(*ignored_fixtures)
TableRows.new(
table_name,
@@ -667,6 +690,21 @@ module ActiveRecord
end
end
+ def ignored_fixtures=(base)
+ @ignored_fixtures =
+ case base
+ when Array
+ base
+ when String
+ [base]
+ else
+ []
+ end
+
+ @ignored_fixtures << "DEFAULTS" unless @ignored_fixtures.include?("DEFAULTS")
+ @ignored_fixtures.compact
+ end
+
# Loads the fixtures from the YAML file at +path+.
# If the file sets the +model_class+ and current instance value is not set,
# it uses the file value.
@@ -678,6 +716,7 @@ module ActiveRecord
yaml_files.each_with_object({}) do |file, fixtures|
FixtureSet::File.open(file) do |fh|
self.model_class ||= fh.model_class if fh.model_class
+ self.ignored_fixtures ||= fh.ignored_fixtures
fh.each do |fixture_name, row|
fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
end
diff --git a/activerecord/test/cases/database_configurations_test.rb b/activerecord/test/cases/database_configurations_test.rb
index 725d1b5d1b..714b9d75c5 100644
--- a/activerecord/test/cases/database_configurations_test.rb
+++ b/activerecord/test/cases/database_configurations_test.rb
@@ -89,7 +89,7 @@ class LegacyDatabaseConfigurationsTest < ActiveRecord::TestCase
end
def test_first_is_deprecated
- first_config = ActiveRecord::Base.configurations.values.first
+ first_config = ActiveRecord::Base.configurations.configurations.map(&:config).first
assert_deprecated do
env_name, config = ActiveRecord::Base.configurations.first
assert_equal "arunit", env_name
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index a7f01e898e..7ad032a632 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -1279,6 +1279,33 @@ class CustomNameForFixtureOrModelTest < ActiveRecord::TestCase
end
end
+class IgnoreFixturesTest < ActiveRecord::TestCase
+ fixtures :other_books, :parrots
+
+ test "ignores books fixtures" do
+ assert_raise(StandardError) { other_books(:published) }
+ assert_raise(StandardError) { other_books(:published_paperback) }
+ assert_raise(StandardError) { other_books(:published_ebook) }
+
+ assert_equal 2, Book.count
+ assert_equal "Agile Web Development with Rails", other_books(:awdr).name
+ assert_equal "published", other_books(:awdr).status
+ assert_equal "paperback", other_books(:awdr).format
+ assert_equal "english", other_books(:awdr).language
+
+ assert_equal "Ruby for Rails", other_books(:rfr).name
+ assert_equal "ebook", other_books(:rfr).format
+ assert_equal "published", other_books(:rfr).status
+ end
+
+ test "ignores parrots fixtures" do
+ assert_raise(StandardError) { parrots(:DEFAULT) }
+ assert_raise(StandardError) { parrots(:DEAD_PARROT) }
+
+ assert_equal "DeadParrot", parrots(:polly).parrot_sti_class
+ end
+end
+
class FixturesWithDefaultScopeTest < ActiveRecord::TestCase
fixtures :bulbs
diff --git a/activerecord/test/fixtures/other_books.yml b/activerecord/test/fixtures/other_books.yml
new file mode 100644
index 0000000000..62806c03d7
--- /dev/null
+++ b/activerecord/test/fixtures/other_books.yml
@@ -0,0 +1,26 @@
+_fixture:
+ model_class: Book
+ ignore:
+ - PUBLISHED
+ - PUBLISHED_PAPERBACK
+ - PUBLISHED_EBOOK
+
+PUBLISHED: &PUBLISHED
+ status: :published
+
+PUBLISHED_PAPERBACK: &PUBLISHED_PAPERBACK
+ <<: *PUBLISHED
+ format: "paperback"
+ language: :english
+
+PUBLISHED_EBOOK: &PUBLISHED_EBOOK
+ <<: *PUBLISHED
+ format: "ebook"
+
+awdr:
+ <<: *PUBLISHED_PAPERBACK
+ name: "Agile Web Development with Rails"
+
+rfr:
+ <<: *PUBLISHED_EBOOK
+ name: "Ruby for Rails"
diff --git a/activerecord/test/fixtures/parrots.yml b/activerecord/test/fixtures/parrots.yml
index 8425ef98e0..4f0a090e03 100644
--- a/activerecord/test/fixtures/parrots.yml
+++ b/activerecord/test/fixtures/parrots.yml
@@ -1,3 +1,9 @@
+_fixture:
+ ignore: DEAD_PARROT
+
+DEAD_PARROT: &DEAD_PARROT
+ parrot_sti_class: DeadParrot
+
george:
name: "Curious George"
treasures: diamond, sapphire
@@ -17,7 +23,7 @@ polly:
name: $LABEL
killer: blackbeard
treasures: sapphire, ruby
- parrot_sti_class: DeadParrot
+ <<: *DEAD_PARROT
DEFAULTS: &DEFAULTS
treasures: sapphire, ruby
diff --git a/activestorage/test/fixtures/files/racecar.tif b/activestorage/test/fixtures/files/racecar.tif
index 0a11b22896..97430741e2 100644
--- a/activestorage/test/fixtures/files/racecar.tif
+++ b/activestorage/test/fixtures/files/racecar.tif
Binary files differ
diff --git a/activesupport/lib/active_support/core_ext/string/access.rb b/activesupport/lib/active_support/core_ext/string/access.rb
index 4f70e7f5fc..eff31e5493 100644
--- a/activesupport/lib/active_support/core_ext/string/access.rb
+++ b/activesupport/lib/active_support/core_ext/string/access.rb
@@ -76,17 +76,7 @@ class String
# str.first(0) # => ""
# str.first(6) # => "hello"
def first(limit = 1)
- ActiveSupport::Deprecation.warn(
- "Calling String#first with a negative integer limit " \
- "will raise an ArgumentError in Rails 6.1."
- ) if limit < 0
- if limit == 0
- ""
- elsif limit >= size
- dup
- else
- to(limit - 1)
- end
+ self[0, limit] || (raise ArgumentError, "negative limit")
end
# Returns the last character of the string. If a limit is supplied, returns a substring
@@ -100,16 +90,6 @@ class String
# str.last(0) # => ""
# str.last(6) # => "hello"
def last(limit = 1)
- ActiveSupport::Deprecation.warn(
- "Calling String#last with a negative integer limit " \
- "will raise an ArgumentError in Rails 6.1."
- ) if limit < 0
- if limit == 0
- ""
- elsif limit >= size
- dup
- else
- from(-limit)
- end
+ self[[length - limit, 0].max, limit] || (raise ArgumentError, "negative limit")
end
end
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index b1ab9533e7..af8f9c9b09 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -482,12 +482,16 @@ class StringAccessTest < ActiveSupport::TestCase
assert_not_same different_string, string
end
- test "#first with negative Integer is deprecated" do
- string = "hello"
- message = "Calling String#first with a negative integer limit " \
- "will raise an ArgumentError in Rails 6.1."
- assert_deprecated(message) do
- string.first(-1)
+ test "#first with Integer returns a non-frozen string" do
+ string = "he"
+ (0..string.length + 1).each do |limit|
+ assert_not string.first(limit).frozen?
+ end
+ end
+
+ test "#first with negative Integer raises ArgumentError" do
+ assert_raise ArgumentError do
+ "hello".first(-1)
end
end
@@ -509,12 +513,16 @@ class StringAccessTest < ActiveSupport::TestCase
assert_not_same different_string, string
end
- test "#last with negative Integer is deprecated" do
- string = "hello"
- message = "Calling String#last with a negative integer limit " \
- "will raise an ArgumentError in Rails 6.1."
- assert_deprecated(message) do
- string.last(-1)
+ test "#last with Integer returns a non-frozen string" do
+ string = "he"
+ (0..string.length + 1).each do |limit|
+ assert_not string.last(limit).frozen?
+ end
+ end
+
+ test "#last with negative Integer raises ArgumentError" do
+ assert_raise ArgumentError do
+ "hello".last(-1)
end
end