|
1 | | -# frozen_string_literal: true |
2 | | - |
3 | 1 | RSpec.describe "Select in Collection Integration", type: :view do |
4 | | - # Set up test database for collection models |
5 | 2 | before(:all) do |
6 | 3 | ActiveRecord::Schema.define do |
7 | 4 | create_table :orders, force: true do |t| |
|
17 | 14 | end |
18 | 15 | end |
19 | 16 |
|
20 | | - # Test model for collection (array of objects) |
21 | 17 | class Order < ActiveRecord::Base |
22 | | - # Serialize tag_ids as JSON array for multiple select testing |
23 | 18 | serialize :tag_ids, coder: JSON |
24 | 19 | end |
25 | 20 |
|
26 | | - describe "single select in collection" do |
27 | | - let(:initial_orders) do |
28 | | - [ |
29 | | - Order.new(item_id: 1), |
30 | | - Order.new(item_id: 2) |
31 | | - ] |
32 | | - end |
33 | | - let(:model) do |
34 | | - User.new(first_name: "Test", email: "test@example.com").tap do |user| |
35 | | - orders_list = initial_orders |
36 | | - user.define_singleton_method(:orders) { @orders ||= orders_list } |
37 | | - user.define_singleton_method(:orders=) { |val| @orders = val } |
38 | | - end |
| 21 | + let(:item_options) { [[1, "Coffee"], [2, "Tea"], [3, "Juice"]] } |
| 22 | + let(:tag_options) { [[1, "Ruby"], [2, "Rails"], [3, "Phlex"]] } |
| 23 | + |
| 24 | + def build_model(orders) |
| 25 | + User.new(first_name: "Test", email: "test@example.com").tap do |user| |
| 26 | + orders_list = orders |
| 27 | + user.define_singleton_method(:orders) { @orders ||= orders_list } |
| 28 | + user.define_singleton_method(:orders=) { |val| @orders = val } |
39 | 29 | end |
| 30 | + end |
| 31 | + |
| 32 | + describe "single select in collection" do |
| 33 | + let(:model) { build_model([Order.new(item_id: 1), Order.new(item_id: 2)]) } |
40 | 34 | let(:form) { Superform::Rails::Form.new(model, action: "/users") } |
41 | | - let(:item_options) { [[1, "Coffee"], [2, "Tea"], [3, "Juice"]] } |
42 | 35 |
|
43 | | - it "renders select with collection notation" do |
| 36 | + it "renders selects with collection notation and pre-selects values" do |
44 | 37 | html = render(form) do |f| |
45 | | - orders_collection = f.collection(:orders) |
46 | | - orders_collection.each do |order_namespace| |
| 38 | + f.collection(:orders).each do |order_namespace| |
47 | 39 | f.render order_namespace.field(:item_id).select(*item_options) |
48 | 40 | end |
49 | 41 | end |
50 | 42 |
|
51 | | - # Collection uses model_name[collection_name][index][field_name] notation |
52 | 43 | expect(html).to include('name="user[orders][0][item_id]"') |
53 | 44 | expect(html).to include('name="user[orders][1][item_id]"') |
54 | | - end |
55 | | - |
56 | | - it "pre-selects options based on collection values" do |
57 | | - html = render(form) do |f| |
58 | | - orders_collection = f.collection(:orders) |
59 | | - orders_collection.each do |order_namespace| |
60 | | - f.render order_namespace.field(:item_id).select(*item_options) |
61 | | - end |
62 | | - end |
63 | 45 |
|
64 | | - # First order should have item_id=1 (Coffee) selected |
65 | 46 | first_select = html.match(/<select[^>]*id="user_orders_0_item_id"[^>]*>.*?<\/select>/m)[0] |
66 | 47 | expect(first_select).to include('<option selected value="1">Coffee</option>') |
67 | 48 |
|
68 | | - # Second order should have item_id=2 (Tea) selected |
69 | 49 | second_select = html.match(/<select[^>]*id="user_orders_1_item_id"[^>]*>.*?<\/select>/m)[0] |
70 | 50 | expect(second_select).to include('<option selected value="2">Tea</option>') |
71 | 51 | end |
72 | | - |
73 | | - it "works with submitted params from collection" do |
74 | | - # Simulate Rails params after form submission |
75 | | - submitted_model = User.new(first_name: "Test", email: "test@example.com").tap do |user| |
76 | | - user.define_singleton_method(:orders) do |
77 | | - [ |
78 | | - Order.new(item_id: 3), # Changed to Juice |
79 | | - Order.new(item_id: 1) # Changed to Coffee |
80 | | - ] |
81 | | - end |
82 | | - end |
83 | | - submitted_form = Superform::Rails::Form.new(submitted_model, action: "/users") |
84 | | - |
85 | | - html = render(submitted_form) do |f| |
86 | | - orders_collection = f.collection(:orders) |
87 | | - orders_collection.each do |order_namespace| |
88 | | - f.render order_namespace.field(:item_id).select(*item_options) |
89 | | - end |
90 | | - end |
91 | | - |
92 | | - # First order should now have item_id=3 (Juice) selected |
93 | | - first_select = html.match(/<select[^>]*id="user_orders_0_item_id"[^>]*>.*?<\/select>/m)[0] |
94 | | - expect(first_select).to include('<option selected value="3">Juice</option>') |
95 | | - |
96 | | - # Second order should now have item_id=1 (Coffee) selected |
97 | | - second_select = html.match(/<select[^>]*id="user_orders_1_item_id"[^>]*>.*?<\/select>/m)[0] |
98 | | - expect(second_select).to include('<option selected value="1">Coffee</option>') |
99 | | - end |
100 | 52 | end |
101 | 53 |
|
102 | 54 | describe "multiple select in collection" do |
103 | | - let(:initial_orders) do |
104 | | - [ |
105 | | - Order.new(tag_ids: [1, 3]), |
106 | | - Order.new(tag_ids: [2]) |
107 | | - ] |
108 | | - end |
109 | | - let(:model) do |
110 | | - User.new(first_name: "Test", email: "test@example.com").tap do |user| |
111 | | - orders_list = initial_orders |
112 | | - user.define_singleton_method(:orders) { @orders ||= orders_list } |
113 | | - user.define_singleton_method(:orders=) { |val| @orders = val } |
114 | | - end |
115 | | - end |
| 55 | + let(:model) { build_model([Order.new(tag_ids: [1, 3]), Order.new(tag_ids: [2])]) } |
116 | 56 | let(:form) { Superform::Rails::Form.new(model, action: "/users") } |
117 | | - let(:tag_options) { [[1, "Ruby"], [2, "Rails"], [3, "Phlex"]] } |
118 | 57 |
|
119 | | - it "renders multiple select with correct field names" do |
120 | | - html = render(form) do |f| |
121 | | - orders_collection = f.collection(:orders) |
122 | | - orders_collection.each do |order_namespace| |
123 | | - f.render order_namespace.field(:tag_ids).select( |
124 | | - *tag_options, |
125 | | - multiple: true |
126 | | - ) |
| 58 | + def render_multiple_select(form) |
| 59 | + render(form) do |f| |
| 60 | + f.collection(:orders).each do |order_namespace| |
| 61 | + f.render order_namespace.field(:tag_ids).select(*tag_options, multiple: true) |
127 | 62 | end |
128 | 63 | end |
129 | | - |
130 | | - # Multiple select in collection should use [index][field_name][] notation |
131 | | - expect(html).to include('name="user[orders][0][tag_ids][]"') |
132 | | - expect(html).to include('name="user[orders][1][tag_ids][]"') |
133 | | - # Should include multiple attribute |
134 | | - expect(html.scan(/multiple/).count).to eq(2) |
135 | 64 | end |
136 | 65 |
|
137 | | - it "renders hidden inputs for empty submissions" do |
138 | | - html = render(form) do |f| |
139 | | - orders_collection = f.collection(:orders) |
140 | | - orders_collection.each do |order_namespace| |
141 | | - f.render order_namespace.field(:tag_ids).select( |
142 | | - *tag_options, |
143 | | - multiple: true |
144 | | - ) |
145 | | - end |
146 | | - end |
| 66 | + it "renders with correct field names and hidden inputs" do |
| 67 | + html = render_multiple_select(form) |
147 | 68 |
|
148 | | - # Should have hidden inputs before each select |
| 69 | + expect(html).to include('name="user[orders][0][tag_ids][]"') |
| 70 | + expect(html).to include('name="user[orders][1][tag_ids][]"') |
149 | 71 | expect(html).to include('<input type="hidden" name="user[orders][0][tag_ids][]" value="">') |
150 | 72 | expect(html).to include('<input type="hidden" name="user[orders][1][tag_ids][]" value="">') |
151 | 73 | end |
152 | 74 |
|
153 | 75 | it "pre-selects multiple options based on array values" do |
154 | | - html = render(form) do |f| |
155 | | - orders_collection = f.collection(:orders) |
156 | | - orders_collection.each do |order_namespace| |
157 | | - f.render order_namespace.field(:tag_ids).select( |
158 | | - *tag_options, |
159 | | - multiple: true |
160 | | - ) |
161 | | - end |
162 | | - end |
| 76 | + html = render_multiple_select(form) |
163 | 77 |
|
164 | | - # First order should have Ruby (1) and Phlex (3) selected |
165 | | - # Extract just the first select element for testing |
166 | 78 | first_select = html.match(/<select[^>]*id="user_orders_0_tag_ids"[^>]*>.*?<\/select>/m)[0] |
167 | 79 | expect(first_select).to include('<option selected value="1">Ruby</option>') |
168 | 80 | expect(first_select).to include('<option selected value="3">Phlex</option>') |
169 | | - # First order should NOT have Rails (2) selected |
170 | | - expect(first_select).to include('<option value="2">Rails</option>') |
171 | 81 | expect(first_select).not_to include('<option selected value="2">Rails</option>') |
172 | 82 |
|
173 | | - # Second order should have Rails (2) selected |
174 | | - second_select = html.match(/<select[^>]*id="user_orders_1_tag_ids"[^>]*>.*?<\/select>/m)[0] |
175 | | - expect(second_select).to include('<option selected value="2">Rails</option>') |
176 | | - end |
177 | | - |
178 | | - it "works with submitted params for multiple select" do |
179 | | - # Simulate Rails params after form submission |
180 | | - submitted_model = User.new(first_name: "Test", email: "test@example.com").tap do |user| |
181 | | - user.define_singleton_method(:orders) do |
182 | | - [ |
183 | | - Order.new(tag_ids: [2, 3]), # Changed to Rails + Phlex |
184 | | - Order.new(tag_ids: [1, 2, 3]) # Changed to all three |
185 | | - ] |
186 | | - end |
187 | | - end |
188 | | - submitted_form = Superform::Rails::Form.new(submitted_model, action: "/users") |
189 | | - |
190 | | - html = render(submitted_form) do |f| |
191 | | - orders_collection = f.collection(:orders) |
192 | | - orders_collection.each do |order_namespace| |
193 | | - f.render order_namespace.field(:tag_ids).select( |
194 | | - *tag_options, |
195 | | - multiple: true |
196 | | - ) |
197 | | - end |
198 | | - end |
199 | | - |
200 | | - # First order should now have Rails (2) and Phlex (3) selected |
201 | | - first_select = html.match(/<select[^>]*id="user_orders_0_tag_ids"[^>]*>.*?<\/select>/m)[0] |
202 | | - expect(first_select).to include('<option selected value="2">Rails</option>') |
203 | | - expect(first_select).to include('<option selected value="3">Phlex</option>') |
204 | | - |
205 | | - # Second order should have all three selected |
206 | 83 | second_select = html.match(/<select[^>]*id="user_orders_1_tag_ids"[^>]*>.*?<\/select>/m)[0] |
207 | | - expect(second_select).to include('<option selected value="1">Ruby</option>') |
208 | 84 | expect(second_select).to include('<option selected value="2">Rails</option>') |
209 | | - expect(second_select).to include('<option selected value="3">Phlex</option>') |
210 | 85 | end |
211 | 86 | end |
212 | 87 | end |
0 commit comments