A simple solution to an annoying problem!
# Rakefile task "assets:precompile" => "db:migrate" if ENV['MIGRATE_ON_PRECOMPILE'] # run to enable heroku config:set MIGRATE_ON_PRECOMPILE=1
A simple solution to an annoying problem!
# Rakefile task "assets:precompile" => "db:migrate" if ENV['MIGRATE_ON_PRECOMPILE'] # run to enable heroku config:set MIGRATE_ON_PRECOMPILE=1
We don’t want to compile assets during test runs, since that is slow, but we also don’t want the asset pipeline to fail because assets are missing.
This will not work if you plan on doing javascript integration tests, but everything else should work fine.
Rails 5.1 added a flag for this which prints deprecations and will be removed in rails 5.2 so that is not a elegant solution either.
config.assets.unknown_asset_fallback = true
So we are now using this fix to fake assets being available!:
# config/environments/test.rb
# make our tests fast by avoiding asset compilation
# but do not raise when assets are not compiled either
Rails.application.config.assets.compile = false
Sprockets::Rails::Helper.prepend(Module.new do
def resolve_asset_path(path, *)
super || path
end
end)
Rails 4 by default wants to upgrade all cookies, which makes rails 3 unable to read them. But we want that to work since we let rails 3 and 4 run in parallel to test performance (which is terrible on rails 4 … )
# While we run servers with rails 3 and rails 4 we don't want to encrypt our cookie
# once everything is on rails 4 we can by using the upgrade signed to encrypted strategy
# tested via test/integration/rails_compatibility_test.rb
if RAILS4
ActionDispatch::Cookies::ChainedCookieJars.class_eval do
def signed_or_encrypted
signed
end
end
# do not update ... compare to action_dispatch/middleware/cookies.rb:184
ActionDispatch::Cookies::UpgradeLegacySignedCookieJar.class_eval do
def initialize(*args)
super
@verifier = @legacy_verifier
end
def verify_and_upgrade_legacy_signed_message(name, signed_message)
deserialize(name, @legacy_verifier.verify(signed_message))
rescue ActiveSupport::MessageVerifier::InvalidSignature
nil
end
end
end

# application_helper.rb
def render_nested_errors(object, seen=Set.new)
return "" if seen.include?(object)
seen << object
return "" if object.errors.empty?
content_tag :ul do
lis = object.errors.map do |attribute, message|
content_tag(:li) do
content = "".html_safe
content << object.errors.full_message(attribute, message)
values = (object.respond_to?(attribute) ? Array.wrap(object.send(attribute)) : [])
if values.first.is_a?(ActiveRecord::Base)
values.each do |value|
content << render_nested_errors(value, seen)
end
end
content
end
end
safe_join lis
end
end
# application_helper_test.rb
describe "#render_nested_errors" do
# simulate what erb will do so we can see html_safe issues
def render
ERB::Util.html_escape(render_nested_errors(stage))
end
let(:stage) { stages(:test_staging) }
it "renders nothing for valid" do
render.must_equal ""
end
it "renders simple errors" do
stage.errors.add(:base, "Kaboom")
render.must_equal "<ul><li>Kaboom</li></ul>"
end
it "renders nested errors" do
stage.errors.add(:deploy_groups, "Invalid") # happens on save normally .. not a helpful message for our users
stage.errors.add(:base, "BASE") # other error to make sure nesting is correct
stage.deploy_groups.to_a.first.errors.add(:base, "Kaboom")
render.must_equal "<ul><li>Deploy groups Invalid<ul><li>Kaboom</li></ul></li><li>BASE</li></ul>"
end
it "does not loop" do
stage.errors.add(:project, "Invalid")
stage.project.stubs(stages: [stage])
stage.project.errors.add(:stages, "Invalid")
render.must_equal "<ul><li>Project Invalid<ul><li>Stages Invalid</li></ul></li></ul>"
end
it "cannot inject html" do
stage.errors.add(:deploy_groups, "<foo>")
stage.errors.add(:base, "<bar>")
stage.deploy_groups.to_a.first.errors.add(:base, "<baz>")
render.must_equal "<ul><li>Deploy groups <foo><ul><li><baz></li></ul></li><li><bar></li></ul>"
end
end
Not using a browser is a lot faster, so let’s try to avoid it if possible.
click_ujs_link "Delete"
click_ujs_link "Post"
...
def click_ujs_link(name)
link = find(:link, name, {})
visit_with_method link['data-method'], link['href']
end
def visit_with_method(method, url)
page.driver.send method, url
visit page.driver.response.location
end