Rails 5: Matching Asset URLs in Feature Specs
As part of an ongoing Rails Upgrade for a large web application, I needed to update a feature spec that checked the URL of included assets. In earlier versions of Rails, these URLs could simply be checked by calling:
expect(find('img.my_asset_image')[:src]).to end_with('/my-image.png')
This expectation would pass given the following ERB output:
# <%= image_url('my-image.png') %>
# => <img src="/assets/my-image.png" />
In Rails 5, though, assets are compiled and fingerprinted during the test runs. This resulted in the generated URL containing a random fingerprint that could not be determined until runtime:
# <%= image_url('my-image.png') %>
# => <img src="/assets/my-image-aa00bb11cc22dd33ee44ff55.png" />
Writing a Simple Custom Matcher
To resolve this issue, I ended up writing a small custom matcher for RSpec that matched the URL against a simple regular expression.
# spec/support/custom_matchers.rb
RSpec::Matchers.define :eql_asset_url do |asset_name|
match do |actual|
pattern = asset_matcher_pattern(asset_name)
expect(actual).to match(pattern)
end
failure_message do |actual|
pattern = asset_matcher_pattern(asset_name)
"expected #{actual} to contain an image asset url matching #{pattern}"
end
def asset_matcher_pattern(asset_name)
# Split the asset's path, filename and extension for matching
pathname = Pathname.new(asset_name)
dirname = pathname.dirname.to_s
dirname = '' if dirname == '.'
extname = pathname.extname.to_s
basename = pathname.basename.to_s.gsub(extname, '')
%r{/assets#{dirname}/#{basename}-[a-f0-9]*#{extname}}
end
end
Now in my feature specs, I can use the eql_asset_url
matcher to test generated asset URLs:
expect(find('img.my_asset_image')[:src]).to eql_asset_url('my-image.png')
👋 Thanks for reading - I hope you enjoyed this post. If you find it helpful and want to support further writing and tutorials like this one, please consider supporting my work with a coffee!
Support ☕️