| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | # -*- coding: utf-8; -*- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from unittest import TestCase | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  | from unittest.mock import MagicMock, patch | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-15 08:40:56 -06:00
										 |  |  | import sqlalchemy as sa | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | import colander | 
					
						
							|  |  |  | import deform | 
					
						
							|  |  |  | from pyramid import testing | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from wuttjamaican.conf import WuttaConfig | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | from wuttaweb.forms import base, widgets | 
					
						
							| 
									
										
										
										
											2025-06-29 09:16:44 -05:00
										 |  |  | from wuttaweb import helpers, subscribers | 
					
						
							| 
									
										
										
										
											2024-08-21 14:38:34 -05:00
										 |  |  | from wuttaweb.grids import Grid | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestForm(TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.config = WuttaConfig( | 
					
						
							|  |  |  |             defaults={ | 
					
						
							|  |  |  |                 "wutta.web.menus.handler_spec": "tests.util:NullMenuHandler", | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  |         self.app = self.config.get_app() | 
					
						
							| 
									
										
										
										
											2024-08-05 21:49:18 -05:00
										 |  |  |         self.request = testing.DummyRequest(wutta_config=self.config, use_oruga=False) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.pyramid_config = testing.setUp( | 
					
						
							|  |  |  |             request=self.request, | 
					
						
							|  |  |  |             settings={ | 
					
						
							|  |  |  |                 "wutta_config": self.config, | 
					
						
							|  |  |  |                 "mako.directories": ["wuttaweb:templates"], | 
					
						
							|  |  |  |                 "pyramid_deform.template_search_path": "wuttaweb:templates/deform", | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-29 09:16:44 -05:00
										 |  |  |         event = MagicMock(request=self.request) | 
					
						
							|  |  |  |         subscribers.new_request(event) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |     def tearDown(self): | 
					
						
							|  |  |  |         testing.tearDown() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-07 19:47:24 -05:00
										 |  |  |     def make_form(self, **kwargs): | 
					
						
							|  |  |  |         return base.Form(self.request, **kwargs) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def make_schema(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         schema = colander.Schema( | 
					
						
							|  |  |  |             children=[ | 
					
						
							|  |  |  |                 colander.SchemaNode(colander.String(), name="foo"), | 
					
						
							|  |  |  |                 colander.SchemaNode(colander.String(), name="bar"), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         return schema | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_init_with_none(self): | 
					
						
							|  |  |  |         form = self.make_form() | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         self.assertEqual(form.fields, []) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_init_with_fields(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							|  |  |  |         self.assertEqual(form.fields, ["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_init_with_schema(self): | 
					
						
							|  |  |  |         schema = self.make_schema() | 
					
						
							|  |  |  |         form = self.make_form(schema=schema) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(form.fields, ["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_vue_tagname(self): | 
					
						
							|  |  |  |         form = self.make_form() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(form.vue_tagname, "wutta-form") | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_vue_component(self): | 
					
						
							|  |  |  |         form = self.make_form() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(form.vue_component, "WuttaForm") | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_contains(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							|  |  |  |         self.assertIn("foo", form) | 
					
						
							|  |  |  |         self.assertNotIn("baz", form) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_iter(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         fields = list(iter(form)) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(fields, ["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         fields = [] | 
					
						
							|  |  |  |         for field in form: | 
					
						
							|  |  |  |             fields.append(field) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(fields, ["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_set_fields(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							|  |  |  |         self.assertEqual(form.fields, ["foo", "bar"]) | 
					
						
							|  |  |  |         form.set_fields(["baz"]) | 
					
						
							|  |  |  |         self.assertEqual(form.fields, ["baz"]) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |     def test_append(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["one", "two"]) | 
					
						
							|  |  |  |         self.assertEqual(form.fields, ["one", "two"]) | 
					
						
							|  |  |  |         form.append("one", "two", "three") | 
					
						
							|  |  |  |         self.assertEqual(form.fields, ["one", "two", "three"]) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |     def test_remove(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["one", "two", "three", "four"]) | 
					
						
							|  |  |  |         self.assertEqual(form.fields, ["one", "two", "three", "four"]) | 
					
						
							|  |  |  |         form.remove("two", "three") | 
					
						
							|  |  |  |         self.assertEqual(form.fields, ["one", "four"]) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_set_node(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         self.assertEqual(form.nodes, {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # complete node | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         node = colander.SchemaNode(colander.Bool(), name="foo") | 
					
						
							|  |  |  |         form.set_node("foo", node) | 
					
						
							|  |  |  |         self.assertIs(form.nodes["foo"], node) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # type only | 
					
						
							|  |  |  |         typ = colander.Bool() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_node("foo", typ) | 
					
						
							|  |  |  |         node = form.nodes["foo"] | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         self.assertIsInstance(node, colander.SchemaNode) | 
					
						
							|  |  |  |         self.assertIsInstance(node.typ, colander.Bool) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(node.name, "foo") | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # schema is updated if already present | 
					
						
							|  |  |  |         schema = form.get_schema() | 
					
						
							|  |  |  |         self.assertIsNotNone(schema) | 
					
						
							|  |  |  |         typ = colander.Date() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_node("foo", typ) | 
					
						
							|  |  |  |         node = form.nodes["foo"] | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         self.assertIsInstance(node, colander.SchemaNode) | 
					
						
							|  |  |  |         self.assertIsInstance(node.typ, colander.Date) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(node.name, "foo") | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_set_widget(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         self.assertEqual(form.widgets, {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # basic | 
					
						
							|  |  |  |         widget = widgets.SelectWidget() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_widget("foo", widget) | 
					
						
							|  |  |  |         self.assertIs(form.widgets["foo"], widget) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # schema is updated if already present | 
					
						
							|  |  |  |         schema = form.get_schema() | 
					
						
							|  |  |  |         self.assertIsNotNone(schema) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIs(schema["foo"].widget, widget) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         new_widget = widgets.TextInputWidget() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_widget("foo", new_widget) | 
					
						
							|  |  |  |         self.assertIs(form.widgets["foo"], new_widget) | 
					
						
							|  |  |  |         self.assertIs(schema["foo"].widget, new_widget) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-11 23:05:25 -06:00
										 |  |  |         # can also just specify widget pseudo-type (invalid) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertNotIn("bar", form.widgets) | 
					
						
							|  |  |  |         self.assertRaises(ValueError, form.set_widget, "bar", "ldjfadjfadj") | 
					
						
							| 
									
										
										
										
											2024-12-11 23:05:25 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # can also just specify widget pseudo-type (valid) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertNotIn("bar", form.widgets) | 
					
						
							|  |  |  |         form.set_widget("bar", "notes") | 
					
						
							|  |  |  |         self.assertIsInstance(form.widgets["bar"], widgets.NotesWidget) | 
					
						
							| 
									
										
										
										
											2024-12-11 23:05:25 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_make_widget(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-12-11 23:05:25 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # notes | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         widget = form.make_widget("notes") | 
					
						
							| 
									
										
										
										
											2024-12-11 23:05:25 -06:00
										 |  |  |         self.assertIsInstance(widget, widgets.NotesWidget) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # invalid | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         widget = form.make_widget("fdajvdafjjf") | 
					
						
							| 
									
										
										
										
											2024-12-11 23:05:25 -06:00
										 |  |  |         self.assertIsNone(widget) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 15:15:00 -06:00
										 |  |  |     def test_set_default_widgets(self): | 
					
						
							|  |  |  |         model = self.app.model | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # no defaults for "plain" schema | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-12-12 15:15:00 -06:00
										 |  |  |         self.assertEqual(form.widgets, {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # no defaults for "plain" mapped class | 
					
						
							|  |  |  |         form = self.make_form(model_class=model.Setting) | 
					
						
							|  |  |  |         self.assertEqual(form.widgets, {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class MyWidget(widgets.Widget): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # widget set for datetime mapped field | 
					
						
							|  |  |  |         form = self.make_form(model_class=model.Upgrade) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("created", form.widgets) | 
					
						
							|  |  |  |         self.assertIsNot(form.widgets["created"], MyWidget) | 
					
						
							|  |  |  |         self.assertNotIsInstance(form.widgets["created"], MyWidget) | 
					
						
							| 
									
										
										
										
											2024-12-12 15:15:00 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # widget *not* set for datetime, if override present | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form( | 
					
						
							|  |  |  |             model_class=model.Upgrade, widgets={"created": MyWidget()} | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertIn("created", form.widgets) | 
					
						
							|  |  |  |         self.assertIsInstance(form.widgets["created"], MyWidget) | 
					
						
							| 
									
										
										
										
											2024-12-12 15:15:00 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-15 08:40:56 -06:00
										 |  |  |         # mock up a table with all relevant column types | 
					
						
							|  |  |  |         class Whatever(model.Base): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             __tablename__ = "whatever" | 
					
						
							| 
									
										
										
										
											2025-01-15 08:40:56 -06:00
										 |  |  |             id = sa.Column(sa.Integer(), primary_key=True) | 
					
						
							|  |  |  |             date = sa.Column(sa.Date()) | 
					
						
							|  |  |  |             date_time = sa.Column(sa.DateTime()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # widget set for all known types | 
					
						
							|  |  |  |         form = self.make_form(model_class=Whatever) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIsInstance(form.widgets["date"], widgets.WuttaDateWidget) | 
					
						
							|  |  |  |         self.assertIsInstance(form.widgets["date_time"], widgets.WuttaDateTimeWidget) | 
					
						
							| 
									
										
										
										
											2025-01-15 08:40:56 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-09 20:56:09 -06:00
										 |  |  |     def test_set_grid(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							|  |  |  |         self.assertNotIn("foo", form.widgets) | 
					
						
							|  |  |  |         self.assertNotIn("foogrid", form.grid_vue_context) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         grid = Grid( | 
					
						
							|  |  |  |             self.request, | 
					
						
							|  |  |  |             key="foogrid", | 
					
						
							|  |  |  |             columns=["a", "b"], | 
					
						
							|  |  |  |             data=[{"a": 1, "b": 2}, {"a": 3, "b": 4}], | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         form.set_grid("foo", grid) | 
					
						
							|  |  |  |         self.assertIn("foo", form.widgets) | 
					
						
							|  |  |  |         self.assertIsInstance(form.widgets["foo"], widgets.GridWidget) | 
					
						
							|  |  |  |         self.assertIn("foogrid", form.grid_vue_context) | 
					
						
							| 
									
										
										
										
											2024-12-09 20:56:09 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |     def test_set_validator(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         self.assertEqual(form.validators, {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def validate1(node, value): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # basic | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_validator("foo", validate1) | 
					
						
							|  |  |  |         self.assertIs(form.validators["foo"], validate1) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         def validate2(node, value): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # schema is updated if already present | 
					
						
							|  |  |  |         schema = form.get_schema() | 
					
						
							|  |  |  |         self.assertIsNotNone(schema) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIs(schema["foo"].validator, validate1) | 
					
						
							|  |  |  |         form.set_validator("foo", validate2) | 
					
						
							|  |  |  |         self.assertIs(form.validators["foo"], validate2) | 
					
						
							|  |  |  |         self.assertIs(schema["foo"].validator, validate2) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |     def test_set_default(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         self.assertEqual(form.defaults, {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # basic | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_default("foo", 42) | 
					
						
							|  |  |  |         self.assertEqual(form.defaults["foo"], 42) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |     def test_get_schema(self): | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  |         model = self.app.model | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         form = self.make_form() | 
					
						
							|  |  |  |         self.assertIsNone(form.schema) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # provided schema is returned | 
					
						
							|  |  |  |         schema = self.make_schema() | 
					
						
							|  |  |  |         form = self.make_form(schema=schema) | 
					
						
							|  |  |  |         self.assertIs(form.schema, schema) | 
					
						
							|  |  |  |         self.assertIs(form.get_schema(), schema) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-07 19:47:24 -05:00
										 |  |  |         # schema is auto-generated if fields provided | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-07 19:47:24 -05:00
										 |  |  |         schema = form.get_schema() | 
					
						
							|  |  |  |         self.assertEqual(len(schema.children), 2) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(schema["foo"].name, "foo") | 
					
						
							| 
									
										
										
										
											2024-08-07 19:47:24 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # but auto-generating without fields is not supported | 
					
						
							|  |  |  |         form = self.make_form() | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         self.assertIsNone(form.schema) | 
					
						
							|  |  |  |         self.assertRaises(NotImplementedError, form.get_schema) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  |         # schema is auto-generated if model_class provided | 
					
						
							|  |  |  |         form = self.make_form(model_class=model.Setting) | 
					
						
							|  |  |  |         schema = form.get_schema() | 
					
						
							|  |  |  |         self.assertEqual(len(schema.children), 2) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("name", schema) | 
					
						
							|  |  |  |         self.assertIn("value", schema) | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         # but node overrides are honored when auto-generating | 
					
						
							|  |  |  |         form = self.make_form(model_class=model.Setting) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         value_node = colander.SchemaNode(colander.Bool(), name="value") | 
					
						
							|  |  |  |         form.set_node("value", value_node) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         schema = form.get_schema() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIs(schema["value"], value_node) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  |         # schema is auto-generated if model_instance provided | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(model_instance=model.Setting(name="uhoh")) | 
					
						
							|  |  |  |         self.assertEqual(form.fields, ["name", "value"]) | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  |         self.assertIsNone(form.schema) | 
					
						
							|  |  |  |         # nb. force method to get new fields | 
					
						
							|  |  |  |         del form.fields | 
					
						
							|  |  |  |         schema = form.get_schema() | 
					
						
							|  |  |  |         self.assertEqual(len(schema.children), 2) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("name", schema) | 
					
						
							|  |  |  |         self.assertIn("value", schema) | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-14 15:55:10 -05:00
										 |  |  |         # ColanderAlchemy schema still has *all* requested fields | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form( | 
					
						
							|  |  |  |             model_instance=model.Setting(name="uhoh"), | 
					
						
							|  |  |  |             fields=["name", "value", "foo", "bar"], | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual(form.fields, ["name", "value", "foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-14 15:55:10 -05:00
										 |  |  |         self.assertIsNone(form.schema) | 
					
						
							|  |  |  |         schema = form.get_schema() | 
					
						
							|  |  |  |         self.assertEqual(len(schema.children), 4) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("name", schema) | 
					
						
							|  |  |  |         self.assertIn("value", schema) | 
					
						
							|  |  |  |         self.assertIn("foo", schema) | 
					
						
							|  |  |  |         self.assertIn("bar", schema) | 
					
						
							| 
									
										
										
										
											2024-08-14 15:55:10 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 12:41:22 -05:00
										 |  |  |         # schema nodes are required by default | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-11 12:41:22 -05:00
										 |  |  |         schema = form.get_schema() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIs(schema["foo"].missing, colander.required) | 
					
						
							|  |  |  |         self.assertIs(schema["bar"].missing, colander.required) | 
					
						
							| 
									
										
										
										
											2024-08-11 12:41:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # but fields can be marked *not* required | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							|  |  |  |         form.set_required("bar", False) | 
					
						
							| 
									
										
										
										
											2024-08-11 12:41:22 -05:00
										 |  |  |         schema = form.get_schema() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIs(schema["foo"].missing, colander.required) | 
					
						
							|  |  |  |         self.assertIs(schema["bar"].missing, colander.null) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # validator overrides are honored | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         def validate(node, value): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         form = self.make_form(model_class=model.Setting) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_validator("name", validate) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         schema = form.get_schema() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIs(schema["name"].validator, validate) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # validator can be set for whole form | 
					
						
							|  |  |  |         form = self.make_form(model_class=model.Setting) | 
					
						
							|  |  |  |         schema = form.get_schema() | 
					
						
							|  |  |  |         self.assertIsNone(schema.validator) | 
					
						
							|  |  |  |         form = self.make_form(model_class=model.Setting) | 
					
						
							|  |  |  |         form.set_validator(None, validate) | 
					
						
							|  |  |  |         schema = form.get_schema() | 
					
						
							|  |  |  |         self.assertIs(schema.validator, validate) | 
					
						
							| 
									
										
										
										
											2024-08-11 12:41:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         # default value overrides are honored | 
					
						
							|  |  |  |         form = self.make_form(model_class=model.Setting) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_default("name", "foo") | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         schema = form.get_schema() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(schema["name"].default, "foo") | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |     def test_get_deform(self): | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  |         model = self.app.model | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         schema = self.make_schema() | 
					
						
							| 
									
										
										
										
											2024-08-07 19:47:24 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # basic | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         form = self.make_form(schema=schema) | 
					
						
							| 
									
										
										
										
											2025-09-01 11:53:50 -05:00
										 |  |  |         self.assertIsNone(form.deform_form) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         dform = form.get_deform() | 
					
						
							|  |  |  |         self.assertIsInstance(dform, deform.Form) | 
					
						
							|  |  |  |         self.assertIs(form.deform_form, dform) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  |         # with model instance as dict | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         myobj = {"foo": "one", "bar": "two"} | 
					
						
							| 
									
										
										
										
											2024-08-07 19:47:24 -05:00
										 |  |  |         form = self.make_form(schema=schema, model_instance=myobj) | 
					
						
							|  |  |  |         dform = form.get_deform() | 
					
						
							|  |  |  |         self.assertEqual(dform.cstruct, myobj) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  |         # with sqlalchemy model instance | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         myobj = model.Setting(name="foo", value="bar") | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  |         form = self.make_form(model_instance=myobj) | 
					
						
							|  |  |  |         dform = form.get_deform() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(dform.cstruct, {"name": "foo", "value": "bar"}) | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # sqlalchemy instance with null value | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         myobj = model.Setting(name="foo", value=None) | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  |         form = self.make_form(model_instance=myobj) | 
					
						
							|  |  |  |         dform = form.get_deform() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(dform.cstruct, {"name": "foo", "value": colander.null}) | 
					
						
							| 
									
										
										
										
											2024-08-11 16:52:13 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  |     def test_get_cancel_url(self): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # is referrer by default | 
					
						
							|  |  |  |         form = self.make_form() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.request.get_referrer = MagicMock(return_value="/cancel-default") | 
					
						
							|  |  |  |         self.assertEqual(form.get_cancel_url(), "/cancel-default") | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  |         del self.request.get_referrer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # or can be static URL | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(cancel_url="/cancel-static") | 
					
						
							|  |  |  |         self.assertEqual(form.get_cancel_url(), "/cancel-static") | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # or can be fallback URL (nb. 'NOPE' indicates no referrer) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(cancel_url_fallback="/cancel-fallback") | 
					
						
							|  |  |  |         self.request.get_referrer = MagicMock(return_value="NOPE") | 
					
						
							|  |  |  |         self.assertEqual(form.get_cancel_url(), "/cancel-fallback") | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  |         del self.request.get_referrer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # or can be referrer fallback, i.e. home page | 
					
						
							|  |  |  |         form = self.make_form() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  |         def get_referrer(default=None): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             if default == "NOPE": | 
					
						
							|  |  |  |                 return "NOPE" | 
					
						
							|  |  |  |             return "/home-page" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  |         self.request.get_referrer = get_referrer | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(form.get_cancel_url(), "/home-page") | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  |         del self.request.get_referrer | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |     def test_get_label(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							|  |  |  |         self.assertEqual(form.get_label("foo"), "Foo") | 
					
						
							|  |  |  |         form.set_label("foo", "Baz") | 
					
						
							|  |  |  |         self.assertEqual(form.get_label("foo"), "Baz") | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_set_label(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							|  |  |  |         self.assertEqual(form.get_label("foo"), "Foo") | 
					
						
							|  |  |  |         form.set_label("foo", "Baz") | 
					
						
							|  |  |  |         self.assertEqual(form.get_label("foo"), "Baz") | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # schema should be updated when setting label | 
					
						
							|  |  |  |         schema = self.make_schema() | 
					
						
							|  |  |  |         form = self.make_form(schema=schema) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_label("foo", "Woohoo") | 
					
						
							|  |  |  |         self.assertEqual(form.get_label("foo"), "Woohoo") | 
					
						
							|  |  |  |         self.assertEqual(schema["foo"].title, "Woohoo") | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  |     def test_readonly_fields(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  |         self.assertEqual(form.readonly_fields, set()) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertFalse(form.is_readonly("foo")) | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_readonly("foo") | 
					
						
							|  |  |  |         self.assertEqual(form.readonly_fields, {"foo"}) | 
					
						
							|  |  |  |         self.assertTrue(form.is_readonly("foo")) | 
					
						
							|  |  |  |         self.assertFalse(form.is_readonly("bar")) | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_readonly("bar") | 
					
						
							|  |  |  |         self.assertEqual(form.readonly_fields, {"foo", "bar"}) | 
					
						
							|  |  |  |         self.assertTrue(form.is_readonly("foo")) | 
					
						
							|  |  |  |         self.assertTrue(form.is_readonly("bar")) | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_readonly("foo", False) | 
					
						
							|  |  |  |         self.assertEqual(form.readonly_fields, {"bar"}) | 
					
						
							|  |  |  |         self.assertFalse(form.is_readonly("foo")) | 
					
						
							|  |  |  |         self.assertTrue(form.is_readonly("bar")) | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 12:41:22 -05:00
										 |  |  |     def test_required_fields(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(fields=["foo", "bar"]) | 
					
						
							| 
									
										
										
										
											2024-08-11 12:41:22 -05:00
										 |  |  |         self.assertEqual(form.required_fields, {}) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIsNone(form.is_required("foo")) | 
					
						
							| 
									
										
										
										
											2024-08-11 12:41:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_required("foo") | 
					
						
							|  |  |  |         self.assertEqual(form.required_fields, {"foo": True}) | 
					
						
							|  |  |  |         self.assertTrue(form.is_required("foo")) | 
					
						
							|  |  |  |         self.assertIsNone(form.is_required("bar")) | 
					
						
							| 
									
										
										
										
											2024-08-11 12:41:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_required("bar") | 
					
						
							|  |  |  |         self.assertEqual(form.required_fields, {"foo": True, "bar": True}) | 
					
						
							|  |  |  |         self.assertTrue(form.is_required("foo")) | 
					
						
							|  |  |  |         self.assertTrue(form.is_required("bar")) | 
					
						
							| 
									
										
										
										
											2024-08-11 12:41:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_required("foo", False) | 
					
						
							|  |  |  |         self.assertEqual(form.required_fields, {"foo": False, "bar": True}) | 
					
						
							|  |  |  |         self.assertFalse(form.is_required("foo")) | 
					
						
							|  |  |  |         self.assertTrue(form.is_required("bar")) | 
					
						
							| 
									
										
										
										
											2024-08-11 12:41:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |     def test_render_vue_tag(self): | 
					
						
							|  |  |  |         schema = self.make_schema() | 
					
						
							|  |  |  |         form = self.make_form(schema=schema) | 
					
						
							|  |  |  |         html = form.render_vue_tag() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(html, "<wutta-form></wutta-form>") | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_render_vue_template(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.pyramid_config.include("pyramid_mako") | 
					
						
							|  |  |  |         self.pyramid_config.add_subscriber( | 
					
						
							|  |  |  |             "wuttaweb.subscribers.before_render", "pyramid.events.BeforeRender" | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # form button is disabled on @submit by default | 
					
						
							|  |  |  |         schema = self.make_schema() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(schema=schema, cancel_url="/") | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         html = form.render_vue_template() | 
					
						
							|  |  |  |         self.assertIn('<script type="text/x-template" id="wutta-form-template">', html) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("@submit", html) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # but not if form is configured otherwise | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form = self.make_form(schema=schema, auto_disable_submit=False, cancel_url="/") | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         html = form.render_vue_template() | 
					
						
							|  |  |  |         self.assertIn('<script type="text/x-template" id="wutta-form-template">', html) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertNotIn("@submit", html) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-23 14:14:41 -05:00
										 |  |  |     def test_add_grid_vue_context(self): | 
					
						
							| 
									
										
										
										
											2024-08-21 14:38:34 -05:00
										 |  |  |         form = self.make_form() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # grid must have key | 
					
						
							|  |  |  |         grid = Grid(self.request) | 
					
						
							| 
									
										
										
										
											2024-08-23 14:14:41 -05:00
										 |  |  |         self.assertRaises(ValueError, form.add_grid_vue_context, grid) | 
					
						
							| 
									
										
										
										
											2024-08-21 14:38:34 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # otherwise it works | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         grid = Grid(self.request, key="foo") | 
					
						
							| 
									
										
										
										
											2024-08-23 14:14:41 -05:00
										 |  |  |         self.assertEqual(len(form.grid_vue_context), 0) | 
					
						
							|  |  |  |         form.add_grid_vue_context(grid) | 
					
						
							|  |  |  |         self.assertEqual(len(form.grid_vue_context), 1) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("foo", form.grid_vue_context) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             form.grid_vue_context["foo"], | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "data": [], | 
					
						
							|  |  |  |                 "row_classes": {}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-08-21 14:38:34 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # calling again with same key will replace data | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         records = [{"foo": 1}, {"foo": 2}] | 
					
						
							|  |  |  |         grid = Grid(self.request, key="foo", columns=["foo"], data=records) | 
					
						
							| 
									
										
										
										
											2024-08-23 14:14:41 -05:00
										 |  |  |         form.add_grid_vue_context(grid) | 
					
						
							|  |  |  |         self.assertEqual(len(form.grid_vue_context), 1) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("foo", form.grid_vue_context) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             form.grid_vue_context["foo"], | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "data": records, | 
					
						
							|  |  |  |                 "row_classes": {}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-08-21 14:38:34 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-19 13:40:23 -05:00
										 |  |  |     def test_render_vue_finalize(self): | 
					
						
							|  |  |  |         form = self.make_form() | 
					
						
							|  |  |  |         html = form.render_vue_finalize() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("<script>", html) | 
					
						
							| 
									
										
										
										
											2024-08-19 13:40:23 -05:00
										 |  |  |         self.assertIn("Vue.component('wutta-form', WuttaForm)", html) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |     def test_render_vue_field(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.pyramid_config.include("pyramid_deform") | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         schema = self.make_schema() | 
					
						
							|  |  |  |         form = self.make_form(schema=schema) | 
					
						
							| 
									
										
										
										
											2024-08-05 11:45:00 -05:00
										 |  |  |         dform = form.get_deform() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # typical | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         html = form.render_vue_field("foo") | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         self.assertIn('<b-field :horizontal="true" label="Foo">', html) | 
					
						
							|  |  |  |         self.assertIn('<b-input name="foo"', html) | 
					
						
							| 
									
										
										
										
											2024-08-05 11:45:00 -05:00
										 |  |  |         # nb. no error message | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertNotIn("message", html) | 
					
						
							| 
									
										
										
										
											2024-08-05 11:45:00 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-07 19:47:24 -05:00
										 |  |  |         # readonly | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         html = form.render_vue_field("foo", readonly=True) | 
					
						
							| 
									
										
										
										
											2024-08-07 19:47:24 -05:00
										 |  |  |         self.assertIn('<b-field :horizontal="true" label="Foo">', html) | 
					
						
							|  |  |  |         self.assertNotIn('<b-input name="foo"', html) | 
					
						
							|  |  |  |         # nb. no error message | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertNotIn("message", html) | 
					
						
							| 
									
										
										
										
											2024-08-07 19:47:24 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-23 19:23:40 -05:00
										 |  |  |         # with error message | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object( | 
					
						
							|  |  |  |             form, "get_field_errors", return_value=["something is wrong"] | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             html = form.render_vue_field("foo") | 
					
						
							|  |  |  |             self.assertIn("something is wrong", html) | 
					
						
							| 
									
										
										
										
											2024-08-05 11:45:00 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  |         # add another field, but not to deform, so it should still | 
					
						
							|  |  |  |         # display but with no widget | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.fields.append("zanzibar") | 
					
						
							|  |  |  |         html = form.render_vue_field("zanzibar") | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  |         self.assertIn('<b-field :horizontal="true" label="Zanzibar">', html) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertNotIn("<b-input", html) | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  |         # nb. no error message | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertNotIn("message", html) | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # try that once more but with a model record instance | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(form, "model_instance", new={"zanzibar": "omgwtfbbq"}): | 
					
						
							|  |  |  |             html = form.render_vue_field("zanzibar") | 
					
						
							|  |  |  |         self.assertIn("<b-field", html) | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  |         self.assertIn('label="Zanzibar"', html) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertNotIn("<b-input", html) | 
					
						
							|  |  |  |         self.assertIn(">omgwtfbbq<", html) | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  |         # nb. no error message | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertNotIn("message", html) | 
					
						
							| 
									
										
										
										
											2024-08-10 21:07:38 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-15 02:10:08 -05:00
										 |  |  |     def test_get_vue_field_value(self): | 
					
						
							|  |  |  |         schema = self.make_schema() | 
					
						
							|  |  |  |         form = self.make_form(schema=schema) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # TODO: yikes what a hack (?) | 
					
						
							|  |  |  |         dform = form.get_deform() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         dform.set_appstruct({"foo": "one", "bar": "two"}) | 
					
						
							| 
									
										
										
										
											2024-08-15 02:10:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # null for missing field | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         value = form.get_vue_field_value("doesnotexist") | 
					
						
							| 
									
										
										
										
											2024-08-15 02:10:08 -05:00
										 |  |  |         self.assertIsNone(value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # normal value is returned | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         value = form.get_vue_field_value("foo") | 
					
						
							|  |  |  |         self.assertEqual(value, "one") | 
					
						
							| 
									
										
										
										
											2024-08-15 02:10:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # but not if we remove field from deform | 
					
						
							|  |  |  |         # TODO: what is the use case here again? | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         dform.children.remove(dform["foo"]) | 
					
						
							|  |  |  |         value = form.get_vue_field_value("foo") | 
					
						
							| 
									
										
										
										
											2024-08-15 02:10:08 -05:00
										 |  |  |         self.assertIsNone(value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |     def test_get_vue_model_data(self): | 
					
						
							|  |  |  |         schema = self.make_schema() | 
					
						
							|  |  |  |         form = self.make_form(schema=schema) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # 2 fields by default (foo, bar) | 
					
						
							|  |  |  |         data = form.get_vue_model_data() | 
					
						
							|  |  |  |         self.assertEqual(len(data), 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # still just 2 fields even if we request more | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_fields(["foo", "bar", "baz"]) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         data = form.get_vue_model_data() | 
					
						
							|  |  |  |         self.assertEqual(len(data), 2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-23 20:38:46 -05:00
										 |  |  |         # confirm bool values make it thru as-is | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         schema.add(colander.SchemaNode(colander.Bool(), name="baz")) | 
					
						
							|  |  |  |         form = self.make_form( | 
					
						
							|  |  |  |             schema=schema, | 
					
						
							|  |  |  |             model_instance={ | 
					
						
							|  |  |  |                 "foo": "one", | 
					
						
							|  |  |  |                 "bar": "two", | 
					
						
							|  |  |  |                 "baz": True, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-08-23 20:38:46 -05:00
										 |  |  |         data = form.get_vue_model_data() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(list(data.values()), ["one", "two", True]) | 
					
						
							| 
									
										
										
										
											2024-08-23 20:38:46 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-11 22:28:32 -06:00
										 |  |  |     def test_has_global_errors(self): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def fail(node, value): | 
					
						
							|  |  |  |             node.raise_invalid("things are bad!") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         schema = self.make_schema() | 
					
						
							|  |  |  |         schema.validator = fail | 
					
						
							|  |  |  |         form = self.make_form(schema=schema) | 
					
						
							|  |  |  |         self.assertFalse(form.has_global_errors()) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.request.method = "POST" | 
					
						
							|  |  |  |         self.request.POST = {"foo": "one", "bar": "two"} | 
					
						
							| 
									
										
										
										
											2024-12-11 22:28:32 -06:00
										 |  |  |         self.assertFalse(form.validate()) | 
					
						
							|  |  |  |         self.assertTrue(form.has_global_errors()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_get_global_errors(self): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def fail(node, value): | 
					
						
							|  |  |  |             node.raise_invalid("things are bad!") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         schema = self.make_schema() | 
					
						
							|  |  |  |         schema.validator = fail | 
					
						
							|  |  |  |         form = self.make_form(schema=schema) | 
					
						
							|  |  |  |         self.assertEqual(form.get_global_errors(), []) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.request.method = "POST" | 
					
						
							|  |  |  |         self.request.POST = {"foo": "one", "bar": "two"} | 
					
						
							| 
									
										
										
										
											2024-12-11 22:28:32 -06:00
										 |  |  |         self.assertFalse(form.validate()) | 
					
						
							|  |  |  |         self.assertTrue(form.get_global_errors(), ["things are bad!"]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-05 11:45:00 -05:00
										 |  |  |     def test_get_field_errors(self): | 
					
						
							|  |  |  |         schema = self.make_schema() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-23 19:23:40 -05:00
										 |  |  |         # simple 'Required' validation failure | 
					
						
							|  |  |  |         form = self.make_form(schema=schema) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.request.method = "POST" | 
					
						
							|  |  |  |         self.request.POST = {"foo": "one"} | 
					
						
							| 
									
										
										
										
											2024-08-23 19:23:40 -05:00
										 |  |  |         self.assertFalse(form.validate()) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         errors = form.get_field_errors("bar") | 
					
						
							|  |  |  |         self.assertEqual(errors, ["Required"]) | 
					
						
							| 
									
										
										
										
											2024-08-05 11:45:00 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-23 19:23:40 -05:00
										 |  |  |         # no errors | 
					
						
							|  |  |  |         form = self.make_form(schema=schema) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.request.POST = {"foo": "one", "bar": "two"} | 
					
						
							| 
									
										
										
										
											2024-08-23 19:23:40 -05:00
										 |  |  |         self.assertTrue(form.validate()) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         errors = form.get_field_errors("bar") | 
					
						
							| 
									
										
										
										
											2024-08-23 19:23:40 -05:00
										 |  |  |         self.assertEqual(errors, []) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_validate(self): | 
					
						
							|  |  |  |         schema = self.make_schema() | 
					
						
							|  |  |  |         form = self.make_form(schema=schema) | 
					
						
							| 
									
										
										
										
											2025-09-01 11:53:50 -05:00
										 |  |  |         self.assertIsNone(form.validated) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # will not validate unless request is POST | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.request.POST = {"foo": "blarg", "bar": "baz"} | 
					
						
							|  |  |  |         self.request.method = "GET" | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         self.assertFalse(form.validate()) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.request.method = "POST" | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         data = form.validate() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(data, {"foo": "blarg", "bar": "baz"}) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 09:56:47 -05:00
										 |  |  |         # validating a second time updates form.validated | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.request.POST = {"foo": "BLARG", "bar": "BAZ"} | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         data = form.validate() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(data, {"foo": "BLARG", "bar": "BAZ"}) | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         self.assertIs(form.validated, data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # bad data does not validate | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.request.POST = {"foo": 42, "bar": None} | 
					
						
							| 
									
										
										
										
											2024-08-04 20:35:41 -05:00
										 |  |  |         self.assertFalse(form.validate()) | 
					
						
							|  |  |  |         dform = form.get_deform() | 
					
						
							|  |  |  |         self.assertEqual(len(dform.error.children), 2) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(dform["foo"].errormsg, "Pstruct is not a string") | 
					
						
							| 
									
										
										
										
											2024-08-11 09:56:47 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # when a form has readonly fields, validating it will *remove* | 
					
						
							|  |  |  |         # those fields from deform/schema as well as final data dict | 
					
						
							|  |  |  |         schema = self.make_schema() | 
					
						
							|  |  |  |         form = self.make_form(schema=schema) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.set_readonly("foo") | 
					
						
							|  |  |  |         self.request.POST = {"foo": "one", "bar": "two"} | 
					
						
							| 
									
										
										
										
											2024-08-11 09:56:47 -05:00
										 |  |  |         data = form.validate() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(data, {"bar": "two"}) | 
					
						
							| 
									
										
										
										
											2024-08-11 09:56:47 -05:00
										 |  |  |         dform = form.get_deform() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertNotIn("foo", schema) | 
					
						
							|  |  |  |         self.assertNotIn("foo", dform) | 
					
						
							|  |  |  |         self.assertIn("bar", schema) | 
					
						
							|  |  |  |         self.assertIn("bar", dform) |