Skip to content

Commit a5bd5db

Browse files
committed
Add unit tests for Params extension
Adds comprehensive unit tests for the Params extension: - Tests for schema definition and inheritance - Tests for validate_params method - Tests for method wrapping with both #call and custom methods via operate_on - Tests for validation failures and short-circuiting - Updates spec_helper to load the Params extension
1 parent 479a8cd commit a5bd5db

File tree

2 files changed

+201
-0
lines changed

2 files changed

+201
-0
lines changed

spec/spec_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
require "dry/operation"
99
require "dry/operation/extensions/active_record"
10+
require "dry/operation/extensions/params"
1011
require "dry/operation/extensions/rom"
1112
require "dry/operation/extensions/sequel"
1213

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
# frozen_string_literal: true
2+
3+
require "spec_helper"
4+
5+
RSpec.describe Dry::Operation::Extensions::Params do
6+
include Dry::Monads[:result]
7+
8+
describe ".params" do
9+
it "defines a schema for the operation" do
10+
klass = Class.new(Dry::Operation) do
11+
include Dry::Operation::Extensions::Params
12+
13+
params do
14+
required(:name).filled(:string)
15+
end
16+
end
17+
18+
expect(klass._params_schema).to be_a(Dry::Schema::Params)
19+
end
20+
21+
it "allows schema to be inherited by subclasses" do
22+
parent = Class.new(Dry::Operation) do
23+
include Dry::Operation::Extensions::Params
24+
25+
params do
26+
required(:name).filled(:string)
27+
end
28+
end
29+
30+
child = Class.new(parent)
31+
32+
expect(child._params_schema).to eq(parent._params_schema)
33+
end
34+
35+
it "allows subclass to override parent schema" do
36+
parent = Class.new(Dry::Operation) do
37+
include Dry::Operation::Extensions::Params
38+
39+
params do
40+
required(:name).filled(:string)
41+
end
42+
end
43+
44+
child = Class.new(parent) do
45+
params do
46+
required(:email).filled(:string)
47+
end
48+
end
49+
50+
expect(child._params_schema).not_to eq(parent._params_schema)
51+
end
52+
end
53+
54+
describe "#validate_params" do
55+
it "returns Success with input when no schema is defined" do
56+
klass = Class.new(Dry::Operation) do
57+
include Dry::Operation::Extensions::Params
58+
end
59+
60+
instance = klass.new
61+
result = instance.validate_params(name: "John")
62+
63+
expect(result).to eq(Success(name: "John"))
64+
end
65+
66+
it "returns Success with validated params when validation passes" do
67+
klass = Class.new(Dry::Operation) do
68+
include Dry::Operation::Extensions::Params
69+
70+
params do
71+
required(:name).filled(:string)
72+
end
73+
end
74+
75+
instance = klass.new
76+
result = instance.validate_params(name: "John")
77+
78+
expect(result).to eq(Success(name: "John"))
79+
end
80+
81+
it "returns Failure with errors when validation fails" do
82+
klass = Class.new(Dry::Operation) do
83+
include Dry::Operation::Extensions::Params
84+
85+
params do
86+
required(:name).filled(:string)
87+
end
88+
end
89+
90+
instance = klass.new
91+
result = instance.validate_params(name: "")
92+
93+
expect(result).to be_a(Dry::Monads::Failure)
94+
expect(result.failure).to eq([:invalid_params, {name: ["must be filled"]}])
95+
end
96+
97+
it "coerces values according to schema" do
98+
klass = Class.new(Dry::Operation) do
99+
include Dry::Operation::Extensions::Params
100+
101+
params do
102+
required(:age).value(:integer)
103+
end
104+
end
105+
106+
instance = klass.new
107+
result = instance.validate_params(age: "25")
108+
109+
expect(result).to eq(Success(age: 25))
110+
end
111+
end
112+
113+
describe "method wrapping" do
114+
it "validates params before calling the method" do
115+
klass = Class.new(Dry::Operation) do
116+
include Dry::Operation::Extensions::Params
117+
118+
params do
119+
required(:name).filled(:string)
120+
end
121+
122+
def call(input)
123+
input
124+
end
125+
end
126+
127+
instance = klass.new
128+
result = instance.call(name: "John")
129+
130+
expect(result).to eq(Success(name: "John"))
131+
end
132+
133+
it "returns validation failure without executing method body" do
134+
executed = false
135+
136+
klass = Class.new(Dry::Operation) do
137+
include Dry::Operation::Extensions::Params
138+
139+
params do
140+
required(:name).filled(:string)
141+
end
142+
143+
define_method(:call) do |input|
144+
executed = true
145+
input
146+
end
147+
end
148+
149+
instance = klass.new
150+
result = instance.call(name: "")
151+
152+
expect(result).to be_a(Dry::Monads::Failure)
153+
expect(result.failure).to eq([:invalid_params, {name: ["must be filled"]}])
154+
expect(executed).to be(false)
155+
end
156+
157+
it "works with custom methods specified via operate_on" do
158+
klass = Class.new(Dry::Operation) do
159+
include Dry::Operation::Extensions::Params
160+
161+
operate_on :process
162+
163+
params do
164+
required(:name).filled(:string)
165+
end
166+
167+
def process(input)
168+
input
169+
end
170+
end
171+
172+
instance = klass.new
173+
result = instance.process(name: "John")
174+
175+
expect(result).to eq(Success(name: "John"))
176+
end
177+
178+
it "validates custom methods when params is defined before the method" do
179+
klass = Class.new(Dry::Operation) do
180+
include Dry::Operation::Extensions::Params
181+
182+
operate_on :process
183+
184+
params do
185+
required(:name).filled(:string)
186+
end
187+
188+
def process(input)
189+
input
190+
end
191+
end
192+
193+
instance = klass.new
194+
result = instance.process(name: "")
195+
196+
expect(result).to be_a(Dry::Monads::Failure)
197+
expect(result.failure).to eq([:invalid_params, {name: ["must be filled"]}])
198+
end
199+
end
200+
end

0 commit comments

Comments
 (0)