diff --git a/app/presenters/alchemy/picture_view.rb b/app/components/alchemy/picture_view.rb similarity index 89% rename from app/presenters/alchemy/picture_view.rb rename to app/components/alchemy/picture_view.rb index 0c386ecf0f..c2765e945e 100644 --- a/app/presenters/alchemy/picture_view.rb +++ b/app/components/alchemy/picture_view.rb @@ -2,11 +2,7 @@ module Alchemy # Renders a picture ingredient view - class PictureView - include ActionView::Helpers::AssetTagHelper - include ActionView::Helpers::UrlHelper - include Rails.application.routes.url_helpers - + class PictureView < ViewComponent::Base attr_reader :ingredient, :html_options, :options, :picture DEFAULT_OPTIONS = { @@ -16,14 +12,14 @@ class PictureView sizes: [] }.with_indifferent_access - def initialize(ingredient, options = {}, html_options = {}) + def initialize(ingredient, options: {}, html_options: {}) @ingredient = ingredient @options = DEFAULT_OPTIONS.merge(ingredient.settings).merge(options || {}) @html_options = html_options || {} @picture = ingredient.picture end - def render + def call return if picture.blank? output = caption ? img_tag + caption : img_tag @@ -43,6 +39,8 @@ def render end end + private + def caption return unless show_caption? diff --git a/app/views/alchemy/ingredients/_picture_view.html.erb b/app/views/alchemy/ingredients/_picture_view.html.erb index 14c1d770c0..1a2f81f980 100644 --- a/app/views/alchemy/ingredients/_picture_view.html.erb +++ b/app/views/alchemy/ingredients/_picture_view.html.erb @@ -1,5 +1,4 @@ -<%= Alchemy::PictureView.new( +<%= render Alchemy::PictureView.new( picture_view, - local_assigns[:options], - local_assigns[:html_options] -).render %> + **local_assigns.slice(:options, :html_options) +) -%> diff --git a/spec/presenters/alchemy/picture_view_spec.rb b/spec/components/alchemy/picture_view_spec.rb similarity index 68% rename from spec/presenters/alchemy/picture_view_spec.rb rename to spec/components/alchemy/picture_view_spec.rb index 07f8d6ceb7..0b13d73ca9 100644 --- a/spec/presenters/alchemy/picture_view_spec.rb +++ b/spec/components/alchemy/picture_view_spec.rb @@ -2,9 +2,7 @@ require "rails_helper" -RSpec.describe Alchemy::PictureView do - include Capybara::RSpecMatchers - +RSpec.describe Alchemy::PictureView, type: :component do let(:image) do File.new(File.expand_path("../../fixtures/image.png", __dir__)) end @@ -52,22 +50,24 @@ {} end - subject(:view) do - described_class.new(ingredient, options, html_options).render + subject(:render_view) do + render_inline described_class.new(ingredient, options: options, html_options: html_options) end it "should enclose the image in a
element" do - expect(view).to have_selector("figure img") + render_view + expect(page).to have_selector("figure img") end it "should show the caption" do - expect(view).to have_selector("figure figcaption") - expect(view).to have_content("This is a cute cat") + render_view + expect(page).to have_selector("figure figcaption") + expect(page).to have_content("This is a cute cat") end it "does not pass default options to picture url" do expect(ingredient).to receive(:picture_url).with({}) { picture_url } - view + render_view end context "but disabled in the options" do @@ -76,39 +76,42 @@ end it "should not enclose the image in a
element" do - expect(view).to_not have_selector("figure img") + render_view + expect(page).to_not have_selector("figure img") end it "should not show the caption" do - expect(view).to_not have_selector("figure figcaption") - expect(view).to_not have_content("This is a cute cat") + render_view + expect(page).to_not have_selector("figure figcaption") + expect(page).to_not have_content("This is a cute cat") end end context "but disabled in the ingredient settings" do before do allow(ingredient).to receive(:settings).and_return({show_caption: false}) + render_view end it "should not enclose the image in a
element" do - expect(view).to_not have_selector("figure img") + expect(page).to_not have_selector("figure img") end it "should not show the caption" do - expect(view).to_not have_selector("figure figcaption") - expect(view).to_not have_content("This is a cute cat") + expect(page).to_not have_selector("figure figcaption") + expect(page).to_not have_content("This is a cute cat") end context "but enabled in the options hash" do let(:options) { {show_caption: true} } it "should enclose the image in a
element" do - expect(view).to have_selector("figure img") + expect(page).to have_selector("figure img") end it "should show the caption" do - expect(view).to have_selector("figure figcaption") - expect(view).to have_content("This is a cute cat") + expect(page).to have_selector("figure figcaption") + expect(page).to have_content("This is a cute cat") end end end @@ -116,32 +119,34 @@ context "and ingredient with css class" do before do ingredient.css_class = "left" + render_view end it "should have the class on the
element" do - expect(view).to have_selector("figure.left img") + expect(page).to have_selector("figure.left img") end it "should not have the class on the element" do - expect(view).not_to have_selector("figure img.left") + expect(page).not_to have_selector("figure img.left") end end context "and css class in the html_options" do before do html_options[:class] = "right" + render_view end it "should have the class from the html_options on the
element" do - expect(view).to have_selector("figure.right img") + expect(page).to have_selector("figure.right img") end it "should not have the class from the ingredient on the
element" do - expect(view).not_to have_selector("figure.left img") + expect(page).not_to have_selector("figure.left img") end it "should not have the class from the html_options on the element" do - expect(view).not_to have_selector("figure img.right") + expect(page).not_to have_selector("figure img.right") end end end @@ -151,22 +156,24 @@ {} end - subject(:view) do + subject(:render_view) do ingredient.link = "/home" - described_class.new(ingredient, options).render + render_inline described_class.new(ingredient, options: options) end it "should enclose the image in a link tag" do - expect(view).to have_selector('a[href="/home"] img') + render_view + expect(page).to have_selector('a[href="/home"] img') end context "but disabled link option" do before do options[:disable_link] = true + render_view end it "should not enclose the image in a link tag" do - expect(view).not_to have_selector("a img") + expect(page).not_to have_selector("a img") end end end @@ -177,11 +184,11 @@ end subject(:picture_view) do - described_class.new(ingredient, options) + described_class.new(ingredient, options: options) end it "does not overwrite DEFAULT_OPTIONS" do - described_class.new(ingredient, {my_custom_option: true}) + described_class.new(ingredient, options: {my_custom_option: true}) expect(picture_view.options).to_not have_key(:my_custom_option) end end @@ -193,8 +200,8 @@ end end - subject(:view) do - described_class.new(ingredient).render + subject(:render_view) do + render_inline described_class.new(ingredient) end let(:srcset) do @@ -203,7 +210,7 @@ it "does not pass srcset option to picture_url" do expect(ingredient).to receive(:picture_url).with({}) { picture_url } - view + render_view end context "when only width or width and height are set" do @@ -214,8 +221,8 @@ it "adds srcset attribute including image url and width for each size" do url1 = ingredient.picture_url(size: "1024x768") url2 = ingredient.picture_url(size: "800x") - - expect(view).to have_selector("img[srcset=\"#{url1} 1024w, #{url2} 800w\"]") + render_view + expect(page).to have_selector("img[srcset=\"#{url1} 1024w, #{url2} 800w\"]") end end @@ -227,19 +234,19 @@ it "adds srcset attribute including image url and height for each size" do url1 = ingredient.picture_url(size: "x768") url2 = ingredient.picture_url(size: "x600") - - expect(view).to have_selector("img[srcset=\"#{url1} 768h, #{url2} 600h\"]") + render_view + expect(page).to have_selector("img[srcset=\"#{url1} 768h, #{url2} 600h\"]") end end end context "with no srcset ingredient setting" do - subject(:view) do - described_class.new(ingredient).render + subject!(:render_view) do + render_inline described_class.new(ingredient) end it "image tag has no srcset attribute" do - expect(view).not_to have_selector("img[srcset]") + expect(page).not_to have_selector("img[srcset]") end end @@ -250,8 +257,8 @@ end end - subject(:view) do - described_class.new(ingredient).render + subject(:render_view) do + render_inline described_class.new(ingredient) end let(:sizes) do @@ -263,27 +270,28 @@ it "does not pass sizes option to picture_url" do expect(ingredient).to receive(:picture_url).with({}) { picture_url } - view + render_view end it "adds sizes attribute for each size" do - expect(view).to have_selector("img[sizes=\"#{sizes[0]}, #{sizes[1]}\"]") + render_view + expect(page).to have_selector("img[sizes=\"#{sizes[0]}, #{sizes[1]}\"]") end end context "with no sizes ingredient setting" do - subject(:view) do - described_class.new(ingredient).render + subject!(:render_view) do + render_inline described_class.new(ingredient) end it "image tag has no sizes attribute" do - expect(view).not_to have_selector("img[sizes]") + expect(page).not_to have_selector("img[sizes]") end end describe "alt text" do - subject(:view) do - described_class.new(ingredient, {}, html_options).render + subject!(:render_view) do + render_inline described_class.new(ingredient, html_options: html_options) end let(:html_options) { {} } @@ -296,7 +304,7 @@ end it "uses this as image alt text" do - expect(view).to have_selector('img[alt="A cute cat"]') + expect(page).to have_selector('img[alt="A cute cat"]') end end @@ -305,7 +313,7 @@ let(:html_options) { {alt: "Cute kittens"} } it "uses this as image alt text" do - expect(view).to have_selector('img[alt="Cute kittens"]') + expect(page).to have_selector('img[alt="Cute kittens"]') end end @@ -319,13 +327,13 @@ end it "uses a humanized picture name as alt text" do - expect(view).to have_selector('img[alt="Cute kitty-cat"]') + expect(page).to have_selector('img[alt="Cute kitty-cat"]') end end context "and no name on the picture" do it "has no alt text" do - expect(view).to_not have_selector("img[alt]") + expect(page).to_not have_selector("img[alt]") end end end diff --git a/spec/views/alchemy/ingredients/picture_view_spec.rb b/spec/views/alchemy/ingredients/picture_view_spec.rb index de37a17175..f405112584 100644 --- a/spec/views/alchemy/ingredients/picture_view_spec.rb +++ b/spec/views/alchemy/ingredients/picture_view_spec.rb @@ -16,12 +16,8 @@ ) end - before do - expect_any_instance_of(Alchemy::PictureView).to receive(:render).and_call_original - end - - it "renders an image tag" do + it "renders Alchemy::PictureView" do + expect_any_instance_of(Alchemy::PictureView).to receive(:call) render ingredient - expect(rendered).to have_css("img") end end