172 lines
4.5 KiB
Ruby
172 lines
4.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "dry/view/scope_builder"
|
|
require "dry/view/render_environment_missing"
|
|
|
|
RSpec::Matchers.define :scope do |locals|
|
|
match do |actual|
|
|
locals == actual._locals
|
|
end
|
|
end
|
|
|
|
RSpec.describe Dry::View::Part do
|
|
let(:name) { :user }
|
|
let(:value) { double(:value) }
|
|
let(:render_env) {
|
|
Dry::View::RenderEnvironment.new(
|
|
renderer: renderer,
|
|
inflector: Dry::Inflector.new,
|
|
context: Dry::View::Context.new,
|
|
scope_builder: Dry::View::ScopeBuilder.new,
|
|
part_builder: Dry::View::ScopeBuilder.new
|
|
)
|
|
}
|
|
let(:renderer) { spy(:renderer, format: :xml) }
|
|
|
|
context "with a render environment" do
|
|
subject(:part) {
|
|
described_class.new(
|
|
name: name,
|
|
value: value,
|
|
render_env: render_env
|
|
)
|
|
}
|
|
|
|
describe "#render" do
|
|
it "renders a partial with the part available in its scope" do
|
|
part.render(:info)
|
|
expect(renderer).to have_received(:partial).with(:info, scope(user: part))
|
|
end
|
|
|
|
it "allows the part to be made available on a different name" do
|
|
part.render(:info, as: :admin)
|
|
expect(renderer).to have_received(:partial).with(:info, scope(admin: part))
|
|
end
|
|
|
|
it "includes extra locals in the scope" do
|
|
part.render(:info, extra_local: "hello")
|
|
expect(renderer).to have_received(:partial).with(:info, scope(user: part, extra_local: "hello"))
|
|
end
|
|
end
|
|
|
|
describe "#to_s" do
|
|
before do
|
|
allow(value).to receive(:to_s).and_return "to_s on the value"
|
|
end
|
|
|
|
it "delegates to the wrapped value" do
|
|
expect(part.to_s).to eq "to_s on the value"
|
|
end
|
|
end
|
|
|
|
describe "#new" do
|
|
it "preserves render environment" do
|
|
new_part = part.new(value: "new value")
|
|
expect(new_part._render_env).to be part._render_env
|
|
end
|
|
end
|
|
|
|
describe "#inspect" do
|
|
it "includes the clsas name, name, and value only" do
|
|
expect(part.inspect).to eq "#<Dry::View::Part name=:user value=#<Double :value>>"
|
|
end
|
|
end
|
|
|
|
describe "#_format" do
|
|
it "returns the render environment's format" do
|
|
expect(part._format).to eq :xml
|
|
end
|
|
end
|
|
|
|
describe "#method_missing" do
|
|
let(:value) { double(greeting: "hello from value") }
|
|
|
|
it "calls a matching method on the value" do
|
|
expect(part.greeting).to eq "hello from value"
|
|
end
|
|
|
|
it "forwards all arguments to the method" do
|
|
blk = -> {}
|
|
part.greeting "args", &blk
|
|
|
|
expect(value).to have_received(:greeting).with("args", &blk)
|
|
end
|
|
|
|
it "raises an error if no method matches" do
|
|
expect { part.farewell }.to raise_error(NoMethodError)
|
|
end
|
|
end
|
|
|
|
describe "#respond_to?" do
|
|
let(:value) { double(greeting: "hello from value") }
|
|
|
|
it "handles convenience methods" do
|
|
expect(part).to respond_to(:format)
|
|
expect(part).to respond_to(:context)
|
|
expect(part).to respond_to(:render)
|
|
expect(part).to respond_to(:scope)
|
|
expect(part).to respond_to(:value)
|
|
end
|
|
|
|
it "handles value methods" do
|
|
expect(part).to respond_to(:greeting)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "without a render environment" do
|
|
subject(:part) {
|
|
described_class.new(
|
|
name: name,
|
|
value: value
|
|
)
|
|
}
|
|
|
|
describe "#format" do
|
|
it "raises an error" do
|
|
expect { part.render(:info) }.to raise_error(Dry::View::RenderEnvironmentMissing::MissingEnvironmentError)
|
|
end
|
|
end
|
|
|
|
describe "#render" do
|
|
it "raises an error" do
|
|
expect { part.render(:info) }.to raise_error(Dry::View::RenderEnvironmentMissing::MissingEnvironmentError)
|
|
end
|
|
end
|
|
|
|
describe "#scope" do
|
|
it "raises an error" do
|
|
expect { part.scope(:info) }.to raise_error(Dry::View::RenderEnvironmentMissing::MissingEnvironmentError)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "without a name provided" do
|
|
describe "#_name" do
|
|
context "when class has a name" do
|
|
before do
|
|
Test::MyPart = Class.new(Dry::View::Part)
|
|
end
|
|
|
|
subject(:part) {
|
|
Test::MyPart.new(value: value)
|
|
}
|
|
|
|
it "is inferred from the class name" do
|
|
expect(part._name).to eq "my_part"
|
|
end
|
|
end
|
|
|
|
context "when class is anonymous" do
|
|
subject(:part) {
|
|
Class.new(Dry::View::Part).new(value: value)
|
|
}
|
|
|
|
it "defaults to 'part'" do
|
|
expect(part._name).to eq "part"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|