diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml new file mode 100644 index 0000000..e026d7e --- /dev/null +++ b/.github/workflows/integration_test.yml @@ -0,0 +1,58 @@ +name: Integration Tests + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + test-branch: [rails3, rails4, main, rails6, rails6-webpacker] + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Checkout test app + uses: actions/checkout@v2 + with: + repository: jamesmartin/inline_svg_test_app + ref: ${{ matrix.test-branch }} + path: test_app + - name: Set up Ruby 2.6 + uses: actions/setup-ruby@v1 + with: + ruby-version: 2.6.x + - name: Build local gem + run: | + gem install bundler + bundle install --jobs 4 --retry 3 + bundle exec rake build + - name: Use the local gem in the test App + id: uselocalgem + uses: jacobtomlinson/gha-find-replace@0.1.1 + with: + find: "gem 'inline_svg'" + replace: "gem 'inline_svg', path: '${{github.workspace}}'" + - name: Check local gem in use + run: | + test "${{ steps.uselocalgem.outputs.modifiedFiles }}" != "0" + grep "inline_svg" $GITHUB_WORKSPACE/test_app/Gemfile + - name: Bundle + run: | + cd $GITHUB_WORKSPACE/test_app + bundle install --jobs 4 --retry 3 + - name: Set up Node.js 12.x + uses: actions/setup-node@v1 + with: + node-version: 12.x + if: matrix.test-branch == 'rails6-webpacker' + - name: Generate Webpacker config + run: | + cd $GITHUB_WORKSPACE/test_app + yarn install --check-files + bundle exec rake webpacker:compile + if: matrix.test-branch == 'rails6-webpacker' + - name: Test + run: | + cd $GITHUB_WORKSPACE/test_app + bundle exec rake test diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml new file mode 100644 index 0000000..9769f86 --- /dev/null +++ b/.github/workflows/ruby.yml @@ -0,0 +1,20 @@ +name: Ruby + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Ruby 2.6 + uses: actions/setup-ruby@v1 + with: + ruby-version: 2.6.x + - name: Build and test with Rake + run: | + gem install bundler + bundle install --jobs 4 --retry 3 + bundle exec rake diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5d28cb3..0000000 --- a/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: ruby -rvm: - - 2.3 - - 2.4 - - 2.5 -before_install: - - gem install -v 2.0.1 bundler --no-rdoc --no-ri -script: bundle exec rspec diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c414b5..00d17e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,33 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased][unreleased] + - Nothing +## [1.7.2] - 2020-12-07 +### Fixed +- Improve performance of `CachedAssetFile`. [#118](https://github.com/jamesmartin/inline_svg/pull/118). Thanks [@stevendaniels](https://github.com/stevendaniels) +- Avoid XSS by preventing malicious input of filenames. [#117](https://github.com/jamesmartin/inline_svg/pull/117). Thanks [@pbyrne](https://github.com/pbyrne). + +## [1.7.1] - 2020-03-17 +### Fixed +- Static Asset Finder uses pathname for compatibility with Sprockets 4+. [#106](https://github.com/jamesmartin/inline_svg/pull/106). Thanks [@subdigital](https://github.com/subdigital) + +## [1.7.0] - 2020-02-13 +### Added +- WebpackAssetFinder serves files from dev server if one is running. [#111](https://github.com/jamesmartin/inline_svg/pull/111). Thanks, [@connorshea](https://github.com/connorshea) + +### Fixed +- Using Webpacker and Asset Pipeline in a single App could result in SVGs not being found because the wrong `AssetFinder` was used. [#114](https://github.com/jamesmartin/inline_svg/pull/114). Thanks, [@kylefox](https://github.com/kylefox) +- Prevent "EOFError error" when using webpack dev server over HTTPS [#113](https://github.com/jamesmartin/inline_svg/pull/113). Thanks, [@kylefox](https://github.com/kylefox) + + +## [1.6.0] - 2019-11-13 +### Added +- Support Webpack via the new `inline_svg_pack_tag` helper and deprecate `inline_svg` helper in preparation for v2.0. +[#103](https://github.com/jamesmartin/inline_svg/pull/103) +Thanks, [@kylefox](https://github.com/kylefox) + ## [1.5.2] - 2019-06-20 ### Fixed - Revert automatic Webpack asset finder behavior. Make Webpack "opt-in". @@ -214,7 +239,11 @@ transformations](https://github.com/jamesmartin/inline_svg/blob/master/README.md ### Added - Basic Railtie and view helper to inline SVG documents to Rails views. -[unreleased]: https://github.com/jamesmartin/inline_svg/compare/v1.5.2...HEAD +[unreleased]: https://github.com/jamesmartin/inline_svg/compare/v1.7.2...HEAD +[1.7.2]: https://github.com/jamesmartin/inline_svg/compare/v1.7.1...v1.7.2 +[1.7.1]: https://github.com/jamesmartin/inline_svg/compare/v1.7.0...v1.7.1 +[1.7.0]: https://github.com/jamesmartin/inline_svg/compare/v1.6.0...v1.7.0 +[1.6.0]: https://github.com/jamesmartin/inline_svg/compare/v1.5.2...v1.6.0 [1.5.2]: https://github.com/jamesmartin/inline_svg/compare/v1.5.1...v1.5.2 [1.5.1]: https://github.com/jamesmartin/inline_svg/compare/v1.5.0...v1.5.1 [1.5.0]: https://github.com/jamesmartin/inline_svg/compare/v1.4.0...v1.5.0 diff --git a/README.md b/README.md index ebfb66f..cfb2558 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ # Inline SVG -[![Build Status](https://travis-ci.org/jamesmartin/inline_svg.svg?branch=master)](https://travis-ci.org/jamesmartin/inline_svg) +![Unit tests](https://github.com/jamesmartin/inline_svg/workflows/Ruby/badge.svg) +![Integration Tests](https://github.com/jamesmartin/inline_svg/workflows/Integration%20Tests/badge.svg) Styling a SVG document with CSS for use on the web is most reliably achieved by [adding classes to the document and embedding](http://css-tricks.com/using-svg/) it inline in the HTML. -This gem adds a Rails helper method (`inline_svg`) that reads an SVG document (via Sprockets or Webpacker, so works with the Rails Asset Pipeline), applies a CSS class attribute to the root of the document and +This gem adds Rails helper methods (`inline_svg_tag` and `inline_svg_pack_tag`) that read an SVG document (via Sprockets or Webpacker, so works with the Rails Asset Pipeline), applies a CSS class attribute to the root of the document and then embeds it into a view. Inline SVG supports: @@ -16,18 +17,6 @@ Inline SVG supports: - [Rails 5](http://weblog.rubyonrails.org/2016/6/30/Rails-5-0-final/) (from [v0.10.0](https://github.com/jamesmartin/inline_svg/releases/tag/v0.10.0)) - [Rails 6](https://weblog.rubyonrails.org/2019/4/24/Rails-6-0-rc1-released/) with Sprockets or Webpacker (from [v1.5.2](https://github.com/jamesmartin/inline_svg/releases/tag/v1.5.2)). -## Webpacker - - -Webpacker support is currently "opt-in" and must be manually configured like -so: - -```ruby -InlineSvg.configure do |config| - config.asset_finder = InlineSvg::WebpackAssetFinder -end -``` - ## Changelog This project adheres to [Semantic Versioning](http://semver.org). All notable changes are documented in the @@ -49,9 +38,15 @@ Or install it yourself as: ## Usage +```ruby +# Sprockets +inline_svg_tag(file_name, options={}) + +# Webpacker +inline_svg_pack_tag(file_name, options={}) ``` -inline_svg(file_name, options={}) -``` + +_**Note:** The remainder of this README uses `inline_svg_tag` for examples, but the exact same principles work for `inline_svg_pack_tag`._ The `file_name` can be a full path to a file, the file's basename or an `IO` object. The @@ -69,7 +64,7 @@ Here's an example of embedding an SVG document and applying a 'class' attribute:

Embedded SVG Documents

- <%= inline_svg "some-document.svg", class: 'some-class' %> + <%= inline_svg_tag "some-document.svg", class: 'some-class' %>
@@ -103,11 +98,12 @@ key | description `preserve_aspect_ratio` | adds a `preserveAspectRatio` attribute to the SVG `aria` | adds common accessibility attributes to the SVG (see [PR #34](https://github.com/jamesmartin/inline_svg/pull/34#issue-152062674) for details) `aria_hidden` | adds the `aria-hidden=true` attribute to the SVG +`fallback` | set fallback SVG document Example: ```ruby -inline_svg( +inline_svg_tag( "some-document.svg", id: 'some-id', class: 'some-class', @@ -118,13 +114,14 @@ inline_svg( nocomment: true, preserve_aspect_ratio: 'xMaxYMax meet', aria: true, - aria_hidden: true + aria_hidden: true, + fallback: 'fallback-document.svg' ) ``` ## Accessibility -Use the `aria: true` option to make `inline_svg` add the following +Use the `aria: true` option to make `inline_svg_tag` add the following accessibility (a11y) attributes to your embedded SVG: * Adds a `role="img"` attribute to the root SVG element @@ -135,7 +132,7 @@ Here's an example: ```erb <%= - inline_svg('iconmonstr-glasses-12-icon.svg', + inline_svg_tag('iconmonstr-glasses-12-icon.svg', aria: true, title: 'An SVG', desc: 'This is my SVG. There are many like it. You get the picture') %> @@ -149,11 +146,11 @@ Here's an example: ``` -***Note:*** The title and desc `id` attributes generated for, and referenced by, `aria-labelled-by` are one-way digests based on the value of the title and desc elements and an optional "salt" value using the SHA1 algorithm. This reduces the chance of `inline_svg` embedding elements inside the SVG with `id` attributes that clash with other elements elsewhere on the page. +***Note:*** The title and desc `id` attributes generated for, and referenced by, `aria-labelled-by` are one-way digests based on the value of the title and desc elements and an optional "salt" value using the SHA1 algorithm. This reduces the chance of `inline_svg_tag` embedding elements inside the SVG with `id` attributes that clash with other elements elsewhere on the page. ## Custom Transformations -The transformation behavior of `inline_svg` can be customized by creating custom transformation classes. +The transformation behavior of `inline_svg_tag` can be customized by creating custom transformation classes. For example, inherit from `InlineSvg::CustomTransformation` and implement the `#transform` method: @@ -182,7 +179,7 @@ end The custom transformation can then be called like so: ```haml %div - = inline_svg "some-document.svg", my_custom_attribute: 'some value' + = inline_svg_tag "some-document.svg", my_custom_attribute: 'some value' ``` In this example, the following transformation would be applied to a SVG document: @@ -203,8 +200,8 @@ end The custom transformation will be triggered even if you don't pass any attribute value ```haml %div - = inline_svg "some-document.svg" - = inline_svg "some-document.svg", my_custom_attribute: 'some value' + = inline_svg_tag "some-document.svg" + = inline_svg_tag "some-document.svg", my_custom_attribute: 'some value' ``` In this example, the following transformation would be applied to a SVG document: @@ -284,7 +281,7 @@ end **Note:** Paths are read recursively, so think about keeping your SVG assets restricted to as few paths as possible, and using the filter option to further -restrict assets to only those likely to be used by `inline_svg`. +restrict assets to only those likely to be used by `inline_svg_tag`. ## Missing SVG Files @@ -311,7 +308,7 @@ Which would instead render: ``` -Alternatively, `inline_svg` can be configured to raise an exception when a file +Alternatively, `inline_svg_tag` can be configured to raise an exception when a file is not found: ```ruby diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 03cc066..0000000 --- a/circle.yml +++ /dev/null @@ -1,3 +0,0 @@ -machine: - ruby: - version: 2.5.0 diff --git a/lib/inline_svg/action_view/helpers.rb b/lib/inline_svg/action_view/helpers.rb index c634eb8..882648b 100644 --- a/lib/inline_svg/action_view/helpers.rb +++ b/lib/inline_svg/action_view/helpers.rb @@ -4,7 +4,38 @@ module InlineSvg module ActionView module Helpers + def inline_svg_tag(filename, transform_params={}) + with_asset_finder(InlineSvg.configuration.asset_finder) do + render_inline_svg(filename, transform_params) + end + end + + def inline_svg_pack_tag(filename, transform_params={}) + with_asset_finder(InlineSvg::WebpackAssetFinder) do + render_inline_svg(filename, transform_params) + end + end + def inline_svg(filename, transform_params={}) + ActiveSupport::Deprecation.warn( + '`inline_svg` is deprecated and will be removed from inline_svg 2.0 (use `inline_svg_tag` or `inline_svg_pack_tag` instead)' + ) + + render_inline_svg(filename, transform_params) + end + + private + + def backwards_compatible_html_escape(filename) + # html_escape_once was introduced in newer versions of Rails. + if ERB::Util.respond_to?(:html_escape_once) + ERB::Util.html_escape_once(filename) + else + ERB::Util.html_escape(filename) + end + end + + def render_inline_svg(filename, transform_params={}) begin svg_file = read_svg(filename) rescue InlineSvg::AssetFile::FileNotFound => error @@ -23,8 +54,6 @@ def inline_svg(filename, transform_params={}) InlineSvg::TransformPipeline.generate_html_from(svg_file, transform_params).html_safe end - private - def read_svg(filename) if InlineSvg::IOResource === filename InlineSvg::IOResource.read filename @@ -35,7 +64,7 @@ def read_svg(filename) def placeholder(filename) css_class = InlineSvg.configuration.svg_not_found_css_class - not_found_message = "'#{filename}' #{extension_hint(filename)}" + not_found_message = "'#{backwards_compatible_html_escape(filename)}' #{extension_hint(filename)}" if css_class.nil? return "".html_safe @@ -48,6 +77,14 @@ def configured_asset_file InlineSvg.configuration.asset_file end + def with_asset_finder(asset_finder) + Thread.current[:inline_svg_asset_finder] = asset_finder + output = yield + Thread.current[:inline_svg_asset_finder] = nil + + output + end + def extension_hint(filename) filename.ends_with?(".svg") ? "" : "(Try adding .svg to your filename) " end diff --git a/lib/inline_svg/cached_asset_file.rb b/lib/inline_svg/cached_asset_file.rb index af0c0c1..82d7c3a 100644 --- a/lib/inline_svg/cached_asset_file.rb +++ b/lib/inline_svg/cached_asset_file.rb @@ -18,6 +18,7 @@ def initialize(paths: [], filters: []) @paths = Array(paths).compact.map { |p| Pathname.new(p) } @filters = Array(filters).map { |f| Regexp.new(f) } @assets = @paths.reduce({}) { |assets, p| assets.merge(read_assets(assets, p)) } + @sorted_asset_keys = assets.keys.sort { |a, b| a.size <=> b.size } end # Public: Finds the named asset and returns the contents as a string. @@ -39,17 +40,7 @@ def named(asset_name) # Returns a String representing the key for the named asset or nil if there # is no match. def key_for_asset(asset_name) - match = all_keys_matching(asset_name).sort do |a, b| - a.string.size <=> b.string.size - end.first - match && match.string - end - - # Internal: Find all potential asset keys matching the given asset name. - # - # Returns an array of MatchData objects for keys matching the asset name. - def all_keys_matching(asset_name) - assets.keys.map { |k| /(#{asset_name})/.match(k.to_s) }.compact + @sorted_asset_keys.find { |k| k.include?(asset_name) } end # Internal: Recursively descends through current_paths reading each file it diff --git a/lib/inline_svg/finds_asset_paths.rb b/lib/inline_svg/finds_asset_paths.rb index e37da11..5be65a2 100644 --- a/lib/inline_svg/finds_asset_paths.rb +++ b/lib/inline_svg/finds_asset_paths.rb @@ -6,7 +6,7 @@ def self.by_filename(filename) end def self.configured_asset_finder - InlineSvg.configuration.asset_finder + Thread.current[:inline_svg_asset_finder] || InlineSvg.configuration.asset_finder end end end diff --git a/lib/inline_svg/static_asset_finder.rb b/lib/inline_svg/static_asset_finder.rb index 7518a7f..d0ea282 100644 --- a/lib/inline_svg/static_asset_finder.rb +++ b/lib/inline_svg/static_asset_finder.rb @@ -1,7 +1,9 @@ +require "pathname" + # Naive fallback asset finder for when sprockets >= 3.0 && # config.assets.precompile = false # Thanks to @ryanswood for the original code: -# https://github.com/AbleHealth/inline_svg/commit/661bbb3bef7d1b4bd6ccd63f5f018305797b9509 +# https://github.com/jamesmartin/inline_svg/commit/661bbb3bef7d1b4bd6ccd63f5f018305797b9509 module InlineSvg class StaticAssetFinder def self.find_asset(filename) @@ -14,7 +16,7 @@ def initialize(filename) def pathname if ::Rails.application.config.assets.compile - ::Rails.application.assets[@filename].pathname + Pathname.new(::Rails.application.assets[@filename].filename) else manifest = ::Rails.application.assets_manifest asset_path = manifest.assets[@filename] diff --git a/lib/inline_svg/version.rb b/lib/inline_svg/version.rb index 7dd8304..987e186 100644 --- a/lib/inline_svg/version.rb +++ b/lib/inline_svg/version.rb @@ -1,3 +1,3 @@ module InlineSvg - VERSION = "1.5.2" + VERSION = "1.7.2" end diff --git a/lib/inline_svg/webpack_asset_finder.rb b/lib/inline_svg/webpack_asset_finder.rb index 8c74b96..6d55fef 100644 --- a/lib/inline_svg/webpack_asset_finder.rb +++ b/lib/inline_svg/webpack_asset_finder.rb @@ -6,14 +6,45 @@ def self.find_asset(filename) def initialize(filename) @filename = filename + @asset_path = Webpacker.manifest.lookup(@filename) end def pathname - public_path = Webpacker.config.public_path - file_path = Webpacker.instance.manifest.lookup(@filename) - return unless public_path && file_path + return if @asset_path.blank? - File.join(public_path, file_path) + if Webpacker.dev_server.running? + dev_server_asset(@asset_path) + elsif Webpacker.config.public_path.present? + File.join(Webpacker.config.public_path, @asset_path) + end + end + + private + + def dev_server_asset(file_path) + asset = fetch_from_dev_server(file_path) + + begin + Tempfile.new(file_path).tap do |file| + file.binmode + file.write(asset) + file.rewind + end + rescue StandardError => e + Rails.logger.error "[inline_svg] Error creating tempfile for #{@filename}: #{e}" + raise + end + end + + def fetch_from_dev_server(file_path) + http = Net::HTTP.new(Webpacker.dev_server.host, Webpacker.dev_server.port) + http.use_ssl = Webpacker.dev_server.https? + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + + http.request(Net::HTTP::Get.new(file_path)).body + rescue StandardError => e + Rails.logger.error "[inline_svg] Error fetching #{@filename} from webpack-dev-server: #{e}" + raise end end end diff --git a/spec/helpers/inline_svg_spec.rb b/spec/helpers/inline_svg_spec.rb index 1e7743c..b83346b 100644 --- a/spec/helpers/inline_svg_spec.rb +++ b/spec/helpers/inline_svg_spec.rb @@ -13,7 +13,7 @@ def transform(doc) let(:helper) { ( Class.new { include InlineSvg::ActionView::Helpers } ).new } - describe "#inline_svg" do + shared_examples "inline_svg helper" do |helper_method:| context "when passed the name of an SVG that does not exist" do after(:each) do @@ -31,7 +31,7 @@ def transform(doc) and_raise(InlineSvg::AssetFile::FileNotFound.new) expect { - helper.inline_svg('some-missing-file.svg') + helper.send(helper_method, 'some-missing-file.svg') }.to raise_error(InlineSvg::AssetFile::FileNotFound) end end @@ -41,17 +41,28 @@ def transform(doc) with('some-missing-file.svg'). and_raise(InlineSvg::AssetFile::FileNotFound.new) - output = helper.inline_svg('some-missing-file.svg') + output = helper.send(helper_method, 'some-missing-file.svg') expect(output).to eq "" expect(output).to be_html_safe end + it "escapes malicious input" do + malicious = "-->.svg" + allow(InlineSvg::AssetFile).to receive(:named). + with(malicious). + and_raise(InlineSvg::AssetFile::FileNotFound.new) + + output = helper.send(helper_method, malicious) + expect(output).to eq "" + expect(output).to be_html_safe + end + it "gives a helpful hint when no .svg extension is provided in the filename" do allow(InlineSvg::AssetFile).to receive(:named). with('missing-file-with-no-extension'). and_raise(InlineSvg::AssetFile::FileNotFound.new) - output = helper.inline_svg('missing-file-with-no-extension') + output = helper.send(helper_method, 'missing-file-with-no-extension') expect(output).to eq "" end @@ -64,7 +75,7 @@ def transform(doc) with('some-other-missing-file.svg'). and_raise(InlineSvg::AssetFile::FileNotFound.new) - output = helper.inline_svg('some-other-missing-file.svg') + output = helper.send(helper_method, 'some-other-missing-file.svg') expect(output).to eq "" expect(output).to be_html_safe end @@ -79,7 +90,7 @@ def transform(doc) SVG allow(InlineSvg::AssetFile).to receive(:named).with('fallback.svg').and_return(fallback_file) - expect(helper.inline_svg('missing.svg', fallback: 'fallback.svg')).to eq fallback_file + expect(helper.send(helper_method, 'missing.svg', fallback: 'fallback.svg')).to eq fallback_file end end end @@ -92,7 +103,7 @@ def transform(doc) SVG allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(example_file) - expect(helper.inline_svg('some-file')).to eq example_file + expect(helper.send(helper_method, 'some-file')).to eq example_file end end @@ -105,7 +116,7 @@ def transform(doc) A title SVG allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg) - expect(helper.inline_svg('some-file', title: 'A title')).to eq expected_output + expect(helper.send(helper_method, 'some-file', title: 'A title')).to eq expected_output end end @@ -118,7 +129,7 @@ def transform(doc) A description SVG allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg) - expect(helper.inline_svg('some-file', desc: 'A description')).to eq expected_output + expect(helper.send(helper_method, 'some-file', desc: 'A description')).to eq expected_output end end @@ -131,7 +142,7 @@ def transform(doc) SVG allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg) - expect(helper.inline_svg('some-file', nocomment: true)).to eq expected_output + expect(helper.send(helper_method, 'some-file', nocomment: true)).to eq expected_output end end @@ -144,7 +155,7 @@ def transform(doc) SVG allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg) - expect(helper.inline_svg('some-file', aria_hidden: true)).to eq expected_output + expect(helper.send(helper_method, 'some-file', aria_hidden: true)).to eq expected_output end end @@ -157,7 +168,7 @@ def transform(doc) A titleA description SVG allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg) - expect(helper.inline_svg('some-file', title: 'A title', desc: 'A description', nocomment: true)).to eq expected_output + expect(helper.send(helper_method, 'some-file', title: 'A title', desc: 'A description', nocomment: true)).to eq expected_output end end @@ -180,7 +191,7 @@ def transform(doc) SVG allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg) - expect(helper.inline_svg('some-file', custom: 'some value')).to eq expected_output + expect(helper.send(helper_method, 'some-file', custom: 'some value')).to eq expected_output end end @@ -201,7 +212,7 @@ def transform(doc) allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg) - expect(helper.inline_svg('some-file')).to eq "\n" + expect(helper.send(helper_method, 'some-file')).to eq "\n" end end @@ -211,7 +222,7 @@ def transform(doc) allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg) - expect(helper.inline_svg('some-file', custom: 'some value')).to eq "\n" + expect(helper.send(helper_method, 'some-file', custom: 'some value')).to eq "\n" end end end @@ -223,13 +234,13 @@ def transform(doc) expect(InlineSvg::IOResource).to receive(:===).with(argument).and_return(true) expect(InlineSvg::IOResource).to receive(:read).with(argument) expect(InlineSvg::AssetFile).to_not receive(:named) - helper.inline_svg(argument) + helper.send(helper_method, argument) end it 'accept filename' do expect(InlineSvg::IOResource).to receive(:===).with(argument).and_return(false) expect(InlineSvg::IOResource).to_not receive(:read) expect(InlineSvg::AssetFile).to receive(:named).with(argument) - helper.inline_svg(argument) + helper.send(helper_method, argument) end end context 'when passed IO object argument' do @@ -239,17 +250,29 @@ def transform(doc) it 'return valid svg' do expect(InlineSvg::IOResource).to receive(:===).with(io_object).and_return(true) expect(InlineSvg::IOResource).to receive(:read).with(io_object).and_return("") - output = helper.inline_svg(io_object) + output = helper.send(helper_method, io_object) expect(output).to eq "\n" expect(output).to be_html_safe end it 'return valid svg for file' do - output = helper.inline_svg(File.new(file_path)) + output = helper.send(helper_method, File.new(file_path)) expect(output).to eq "\n" expect(output).to be_html_safe end end end + + describe '#inline_svg' do + it_behaves_like "inline_svg helper", helper_method: :inline_svg + end + + describe '#inline_svg_tag' do + it_behaves_like "inline_svg helper", helper_method: :inline_svg_tag + end + + describe '#inline_svg_tag' do + it_behaves_like "inline_svg helper", helper_method: :inline_svg_pack_tag + end end