@@ -8,6 +8,7 @@ def test_form_field_renders_label(render):
88 type = "text" ,
99 required = False ,
1010 extra_class = "" ,
11+ input_class = "" ,
1112 )
1213 assert "Email Address" in html
1314 assert '<label class="label"' in html
@@ -23,6 +24,7 @@ def test_form_field_renders_input(render):
2324 type = "email" ,
2425 required = False ,
2526 extra_class = "" ,
27+ input_class = "" ,
2628 )
2729 assert 'name="email"' in html
2830 assert 'type="email"' in html
@@ -39,6 +41,7 @@ def test_form_field_shows_error(render):
3941 type = "text" ,
4042 required = False ,
4143 extra_class = "" ,
44+ input_class = "" ,
4245 )
4346 assert "This field is required." in html
4447 assert "is-danger" in html
@@ -55,6 +58,7 @@ def test_form_field_no_error_omits_danger(render):
5558 type = "text" ,
5659 required = False ,
5760 extra_class = "" ,
61+ input_class = "" ,
5862 )
5963 assert "is-danger" not in html
6064
@@ -69,6 +73,7 @@ def test_form_field_required_attribute(render):
6973 type = "text" ,
7074 required = True ,
7175 extra_class = "" ,
76+ input_class = "" ,
7277 )
7378 assert "required" in html
7479
@@ -83,6 +88,7 @@ def test_select_renders_options(render):
8388 error = "" ,
8489 options = options ,
8590 extra_class = "" ,
91+ input_class = "" ,
8692 )
8793 assert "Option A" in html
8894 assert "Option B" in html
@@ -99,6 +105,7 @@ def test_select_shows_error(render):
99105 error = "Required" ,
100106 options = [],
101107 extra_class = "" ,
108+ input_class = "" ,
102109 )
103110 assert "Required" in html
104111 assert "is-danger" in html
@@ -113,6 +120,7 @@ def test_textarea_renders_value(render):
113120 error = "" ,
114121 rows = 4 ,
115122 extra_class = "" ,
123+ input_class = "" ,
116124 )
117125 assert "Hello world" in html
118126 assert 'name="bio"' in html
@@ -128,6 +136,7 @@ def test_textarea_shows_error(render):
128136 error = "Too short" ,
129137 rows = 4 ,
130138 extra_class = "" ,
139+ input_class = "" ,
131140 )
132141 assert "Too short" in html
133142 assert "is-danger" in html
@@ -143,6 +152,7 @@ def test_checkbox_group_renders_choices(render):
143152 selected = ["a" ],
144153 error = "" ,
145154 extra_class = "" ,
155+ control_class = "" ,
146156 )
147157 assert "Apple" in html
148158 assert "Banana" in html
@@ -160,6 +170,7 @@ def test_checkbox_group_unchecked_item(render):
160170 selected = ["a" ],
161171 error = "" ,
162172 extra_class = "" ,
173+ control_class = "" ,
163174 )
164175 assert html .count ("checked" ) == 1
165176
@@ -173,6 +184,130 @@ def test_checkbox_group_shows_error(render):
173184 selected = [],
174185 error = "Select at least one" ,
175186 extra_class = "" ,
187+ control_class = "" ,
176188 )
177189 assert "Select at least one" in html
178190 assert "is-danger" in html
191+
192+
193+ # ── Granular class prop tests ────────────────────────────────────────────────
194+
195+
196+ def test_form_field_input_class_applied (render ):
197+ html = render (
198+ "FormField.jinja" ,
199+ name = "email" ,
200+ label = "Email" ,
201+ value = "" ,
202+ error = "" ,
203+ type = "text" ,
204+ required = False ,
205+ extra_class = "" ,
206+ input_class = "is-rounded" ,
207+ )
208+ assert "is-rounded" in html
209+ assert 'class="input is-rounded"' in html
210+
211+
212+ def test_form_field_input_class_default_omitted (render ):
213+ html = render (
214+ "FormField.jinja" ,
215+ name = "email" ,
216+ label = "Email" ,
217+ value = "" ,
218+ error = "" ,
219+ type = "text" ,
220+ required = False ,
221+ extra_class = "" ,
222+ input_class = "" ,
223+ )
224+ assert 'class="input"' in html
225+
226+
227+ def test_select_input_class_applied (render ):
228+ html = render (
229+ "Select.jinja" ,
230+ name = "choice" ,
231+ label = "Choose" ,
232+ value = "" ,
233+ error = "" ,
234+ options = [],
235+ extra_class = "" ,
236+ input_class = "my-select" ,
237+ )
238+ assert 'class="my-select"' in html
239+
240+
241+ def test_select_input_class_default_omitted (render ):
242+ html = render (
243+ "Select.jinja" ,
244+ name = "choice" ,
245+ label = "Choose" ,
246+ value = "" ,
247+ error = "" ,
248+ options = [],
249+ extra_class = "" ,
250+ input_class = "" ,
251+ )
252+ # No class attribute on the bare <select> when input_class is empty
253+ assert "<select " not in html or 'class=""' not in html
254+
255+
256+ def test_textarea_input_class_applied (render ):
257+ html = render (
258+ "Textarea.jinja" ,
259+ name = "bio" ,
260+ label = "Bio" ,
261+ value = "" ,
262+ error = "" ,
263+ rows = 4 ,
264+ extra_class = "" ,
265+ input_class = "has-fixed-size" ,
266+ )
267+ assert "has-fixed-size" in html
268+ assert 'class="textarea has-fixed-size"' in html
269+
270+
271+ def test_textarea_input_class_default_omitted (render ):
272+ html = render (
273+ "Textarea.jinja" ,
274+ name = "bio" ,
275+ label = "Bio" ,
276+ value = "" ,
277+ error = "" ,
278+ rows = 4 ,
279+ extra_class = "" ,
280+ input_class = "" ,
281+ )
282+ assert 'class="textarea"' in html
283+
284+
285+ def test_checkbox_group_control_class_applied (render ):
286+ choices = [{"value" : "a" , "label" : "Apple" }]
287+ html = render (
288+ "CheckboxGroup.jinja" ,
289+ name = "fruits" ,
290+ label = "Fruits" ,
291+ choices = choices ,
292+ selected = [],
293+ error = "" ,
294+ extra_class = "" ,
295+ control_class = "is-flex" ,
296+ )
297+ assert "is-flex" in html
298+ assert 'class="control is-flex"' in html
299+
300+
301+ def test_checkbox_group_control_class_default_omitted (render ):
302+ choices = [{"value" : "a" , "label" : "Apple" }]
303+ html = render (
304+ "CheckboxGroup.jinja" ,
305+ name = "fruits" ,
306+ label = "Fruits" ,
307+ choices = choices ,
308+ selected = [],
309+ error = "" ,
310+ extra_class = "" ,
311+ control_class = "" ,
312+ )
313+ assert 'class="control"' in html
0 commit comments