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