discourse/spec/lib/service_spec.rb
Loïc Guitaut 9e9abe0a82 DEV: Unify params access in services
Currently, there are two ways (kind of) for accessing `params` inside a
service:
- when there is no contract or it hasn’t been reached yet, `params` is
  just the hash that was provided to the service. To access a key, you
  have to use the bracket notation `params[:my_key]`.
- when there is a contract and it has been executed successfully,
  `params` now references the contract and the attributes are accessible
  using methods (`params.my_key`).

This patch unifies how `params` exposes its attributes. Now, even if
there is no contract at all in a service, `params` will expose its
attributes through methods, that way things are more consistent.

This patch also makes sure there is always a `params` object available
even when no `params` key is provided to the service (this allows a
contract to fail because its attributes are blank instead of having the
service raising an error because it doesn’t find `params` in its context).
2024-12-13 11:13:18 +01:00

96 lines
2.5 KiB
Ruby

# frozen_string_literal: true
RSpec.describe Service do
let(:service_class) { Class.new { include Service::Base } }
describe "Steps" do
describe "Model step" do
context "when providing default values to step implementation" do
before do
service_class.class_eval do
model :my_model
def fetch_my_model(default_arg: 2)
true
end
end
end
it "raises an error" do
expect { service_class.call }.to raise_error(/In model 'my_model': default values/)
end
end
end
describe "Policy step" do
context "when providing default values to step implementation" do
before do
service_class.class_eval do
policy :my_policy
def my_policy(default_arg: 2)
true
end
end
end
it "raises an error" do
expect { service_class.call }.to raise_error(/In policy 'my_policy': default values/)
end
end
end
describe "Generic step" do
context "when providing default values to step implementation" do
before do
service_class.class_eval do
step :generic_step
def generic_step(default_arg: 2)
true
end
end
end
it "raises an error" do
expect { service_class.call }.to raise_error(/In step 'generic_step': default values/)
end
end
end
end
describe "Parameters handling" do
subject(:result) { service_class.call(**args) }
context "when calling the service without any params" do
let(:args) { {} }
it "instantiate a default params object" do
expect(result[:params]).not_to be_nil
end
end
context "when calling the service with params" do
let(:args) { { params: { param1: "one" } } }
context "when there is no `params` step defined" do
it "allows accessing `params` through methods" do
expect(result[:params].param1).to eq("one")
end
it "returns nothing for a non-existent key" do
expect(result[:params].non_existent_key).to be_nil
end
end
context "when there is a `params` step defined" do
before { service_class.class_eval { params { attribute :param1 } } }
it "returns the contract as the params object" do
expect(result[:params]).to be_a(Service::ContractBase)
end
end
end
end
end