hanami-view/spec/unit/part_builder_spec.rb

257 lines
7.4 KiB
Ruby

# frozen_string_literal: true
require "hanami/view/scope_builder"
RSpec.describe Hanami::View::PartBuilder do
subject(:part_builder) { render_env.part_builder }
let(:render_env) {
Hanami::View::RenderEnvironment.new(
renderer: Hanami::View::Renderer.new([FIXTURES_PATH], format: :html),
inflector: Dry::Inflector.new,
context: Hanami::View::Context.new,
scope_builder: Hanami::View::ScopeBuilder.new,
part_builder: Hanami::View::PartBuilder.new(namespace: namespace)
)
}
let(:namespace) { nil }
describe "#call" do
subject(:part) {
part_builder.(name, value, **options)
}
let(:name) { :user }
let(:value) { double(:user) }
let(:options) { {} }
shared_examples "a view part" do
let(:part_class) { Hanami::View::Part }
it "returns a part" do
expect(part).to be_a part_class
end
it "wraps the value" do
expect(part._value).to eq value
end
it "retains the render environment" do
expect(part._render_env).to eql render_env
end
end
shared_examples "a view part collection" do
let(:collection_part_class) { Hanami::View::Part }
let(:item_part_class) { Hanami::View::Part }
it "returns a part wrapping the collection" do
expect(part).to be_a collection_part_class
end
it "wraps the collection and its items" do
expect(part._value.map(&:_value)).to eq value
end
it "returns the collection's items as parts" do
part.to_a.each do |item|
expect(item).to be_a item_part_class
end
end
end
context "without namespace" do
describe "singular value" do
let(:value) { double("user") }
it_behaves_like "a view part"
describe "alternative name provided via :as option" do
let(:options) { {as: :admin_user} }
it_behaves_like "a view part"
end
describe "explicit part class provided via as: option" do
before do
Test::UserPart = Class.new(Hanami::View::Part)
end
let(:options) { {as: Test::UserPart} }
it_behaves_like "a view part" do
let(:part_class) { Test::UserPart }
end
end
end
describe "array-like value" do
let(:name) { :users }
let(:value) { [double(:user), double(:user)] }
it_behaves_like "a view part collection"
describe "alternative name provided via :as option" do
let(:options) { {as: :admin_user} }
it_behaves_like "a view part collection"
end
describe "explicit part class provided via as: option" do
before do
Test::UserPart = Class.new(Hanami::View::Part)
end
let(:options) { {as: Test::UserPart} }
it_behaves_like "a view part collection" do
let(:item_part_class) { Test::UserPart }
end
end
describe "explicit collection part class provided via as: option" do
before do
Test::UserCollectionPart = Class.new(Hanami::View::Part)
end
let(:options) { {as: [Test::UserCollectionPart]} }
it_behaves_like "a view part collection" do
let(:collection_part_class) { Test::UserCollectionPart }
end
end
end
end
context "with namespace" do
before do
module Test
module Parts
class Users < Hanami::View::Part
end
class UserCollection < Hanami::View::Part
end
class User < Hanami::View::Part
decorate :profile
end
class AdminUser < Hanami::View::Part
end
module UserModule
end
class Profile < Hanami::View::Part
end
end
end
end
let(:namespace) { Test::Parts }
describe "singular value" do
let(:value) { double("user", profile: "profile") }
it_behaves_like "a view part" do
let(:part_class) { Test::Parts::User }
end
it "returns decorated attributes in part classes found from the namespace" do
expect(part.profile).to be_a Test::Parts::Profile
end
describe "alternative name provided via :as option" do
let(:options) { {as: :admin_user} }
it_behaves_like "a view part" do
let(:part_class) { Test::Parts::AdminUser }
end
end
describe "alternative name provided via :as option, when matched constant is not a class inheriting from Hanami::View::Part" do
let(:options) { {as: :user_module} }
it_behaves_like "a view part" do
let(:part_class) { Hanami::View::Part }
end
end
describe "explicit part class provided via as: option" do
let(:options) { {as: Test::Parts::AdminUser} }
it_behaves_like "a view part" do
let(:part_class) { Test::Parts::AdminUser }
end
end
end
describe "array-like value" do
let(:name) { :users }
let(:value) { [double(:user), double(:user)] }
it_behaves_like "a view part collection" do
let(:collection_part_class) { Test::Parts::Users }
let(:item_part_class) { Test::Parts::User }
end
describe "alternative element name provided via :as option" do
let(:options) { {as: :admin_user} }
it_behaves_like "a view part collection" do
let(:collection_part_class) { Test::Parts::Users }
let(:item_part_class) { Test::Parts::AdminUser }
end
end
describe "alternative collection name provided via :as option" do
let(:options) { {as: [:user_collection]} }
it_behaves_like "a view part collection" do
let(:collection_part_class) { Test::Parts::UserCollection }
let(:item_part_class) { Test::Parts::User }
end
end
describe "alternative collection and element names provided via :as option" do
let(:options) { {as: [:user_collection, :admin_user]} }
it_behaves_like "a view part collection" do
let(:collection_part_class) { Test::Parts::UserCollection }
let(:item_part_class) { Test::Parts::AdminUser }
end
end
describe "explicit part class provided via as: option" do
let(:options) { {as: Test::Parts::AdminUser} }
it_behaves_like "a view part collection" do
let(:collection_part_class) { Test::Parts::Users }
let(:item_part_class) { Test::Parts::AdminUser }
end
end
describe "explicit collection part class provided via as: option" do
let(:options) { {as: [Test::Parts::UserCollection]} }
it_behaves_like "a view part collection" do
let(:collection_part_class) { Test::Parts::UserCollection }
let(:item_part_class) { Test::Parts::User }
end
end
describe "explicit collection and element part classes provided via :as option" do
let(:options) { {as: [Test::Parts::UserCollection, Test::Parts::AdminUser]} }
it_behaves_like "a view part collection" do
let(:collection_part_class) { Test::Parts::UserCollection }
let(:item_part_class) { Test::Parts::AdminUser }
end
end
end
end
end
end