| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | # -*- coding: utf-8; -*- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 15:15:00 -06:00
										 |  |  | import datetime | 
					
						
							| 
									
										
										
										
											2024-12-28 20:33:56 -06:00
										 |  |  | import decimal | 
					
						
							| 
									
										
										
										
											2024-08-21 14:38:34 -05:00
										 |  |  | from unittest.mock import patch | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | import colander | 
					
						
							|  |  |  | import deform | 
					
						
							|  |  |  | from pyramid import testing | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-09 20:56:09 -06:00
										 |  |  | from wuttaweb import grids | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | from wuttaweb.forms import widgets as mod | 
					
						
							| 
									
										
										
										
											2025-01-02 21:09:31 -06:00
										 |  |  | from wuttaweb.forms import schema | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  | from wuttaweb.forms.schema import ( | 
					
						
							|  |  |  |     FileDownload, | 
					
						
							|  |  |  |     PersonRef, | 
					
						
							|  |  |  |     RoleRefs, | 
					
						
							|  |  |  |     Permissions, | 
					
						
							|  |  |  |     WuttaDateTime, | 
					
						
							|  |  |  |     EmailRecipients, | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2025-01-06 16:47:48 -06:00
										 |  |  | from wuttaweb.testing import WebTestCase | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-13 16:29:34 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | class TestObjectRefWidget(WebTestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-13 16:29:34 -05:00
										 |  |  |     def make_field(self, node, **kwargs): | 
					
						
							|  |  |  |         # TODO: not sure why default renderer is in use even though | 
					
						
							|  |  |  |         # pyramid_deform was included in setup?  but this works.. | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         kwargs.setdefault("renderer", deform.Form.default_renderer) | 
					
						
							| 
									
										
										
										
											2024-08-13 16:29:34 -05:00
										 |  |  |         return deform.Field(node, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-27 21:11:44 -05:00
										 |  |  |     def make_widget(self, **kwargs): | 
					
						
							|  |  |  |         return mod.ObjectRefWidget(self.request, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |     def test_serialize(self): | 
					
						
							|  |  |  |         model = self.app.model | 
					
						
							|  |  |  |         person = model.Person(full_name="Betty Boop") | 
					
						
							|  |  |  |         self.session.add(person) | 
					
						
							|  |  |  |         self.session.commit() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(schema, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-02 21:09:31 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # standard (editable) | 
					
						
							|  |  |  |             node = colander.SchemaNode(PersonRef(self.request)) | 
					
						
							|  |  |  |             widget = self.make_widget() | 
					
						
							|  |  |  |             field = self.make_field(node) | 
					
						
							|  |  |  |             html = widget.serialize(field, person.uuid) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertIn("<b-select ", html) | 
					
						
							| 
									
										
										
										
											2025-01-02 21:09:31 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # readonly | 
					
						
							|  |  |  |             node = colander.SchemaNode(PersonRef(self.request)) | 
					
						
							|  |  |  |             node.model_instance = person | 
					
						
							|  |  |  |             widget = self.make_widget() | 
					
						
							|  |  |  |             field = self.make_field(node) | 
					
						
							|  |  |  |             html = widget.serialize(field, person.uuid, readonly=True) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertIn("Betty Boop", html) | 
					
						
							|  |  |  |             self.assertNotIn("<a", html) | 
					
						
							| 
									
										
										
										
											2025-01-02 21:09:31 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # with hyperlink | 
					
						
							|  |  |  |             node = colander.SchemaNode(PersonRef(self.request)) | 
					
						
							|  |  |  |             node.model_instance = person | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             widget = self.make_widget(url=lambda p: "/foo") | 
					
						
							| 
									
										
										
										
											2025-01-02 21:09:31 -06:00
										 |  |  |             field = self.make_field(node) | 
					
						
							|  |  |  |             html = widget.serialize(field, person.uuid, readonly=True) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertIn("Betty Boop", html) | 
					
						
							|  |  |  |             self.assertIn("<a", html) | 
					
						
							| 
									
										
										
										
											2025-01-02 21:09:31 -06:00
										 |  |  |             self.assertIn('href="/foo"', html) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-27 21:11:44 -05:00
										 |  |  |     def test_get_template_values(self): | 
					
						
							|  |  |  |         model = self.app.model | 
					
						
							|  |  |  |         person = model.Person(full_name="Betty Boop") | 
					
						
							|  |  |  |         self.session.add(person) | 
					
						
							|  |  |  |         self.session.commit() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(schema, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-02 21:09:31 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # standard | 
					
						
							|  |  |  |             node = colander.SchemaNode(PersonRef(self.request)) | 
					
						
							|  |  |  |             widget = self.make_widget() | 
					
						
							|  |  |  |             field = self.make_field(node) | 
					
						
							|  |  |  |             values = widget.get_template_values(field, person.uuid, {}) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertIn("cstruct", values) | 
					
						
							|  |  |  |             self.assertNotIn("url", values) | 
					
						
							| 
									
										
										
										
											2025-01-02 21:09:31 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # readonly w/ empty option | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             node = colander.SchemaNode( | 
					
						
							|  |  |  |                 PersonRef(self.request, empty_option=("_empty_", "(empty)")) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             widget = self.make_widget(readonly=True, url=lambda obj: "/foo") | 
					
						
							| 
									
										
										
										
											2025-01-02 21:09:31 -06:00
										 |  |  |             field = self.make_field(node) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             values = widget.get_template_values(field, "_empty_", {}) | 
					
						
							|  |  |  |             self.assertIn("cstruct", values) | 
					
						
							|  |  |  |             self.assertNotIn("url", values) | 
					
						
							| 
									
										
										
										
											2024-12-11 09:48:50 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-15 08:40:56 -06:00
										 |  |  | class TestWuttaDateWidget(WebTestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def make_field(self, node, **kwargs): | 
					
						
							|  |  |  |         # TODO: not sure why default renderer is in use even though | 
					
						
							|  |  |  |         # pyramid_deform was included in setup?  but this works.. | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         kwargs.setdefault("renderer", deform.Form.default_renderer) | 
					
						
							| 
									
										
										
										
											2025-01-15 08:40:56 -06:00
										 |  |  |         return deform.Field(node, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def make_widget(self, **kwargs): | 
					
						
							|  |  |  |         return mod.WuttaDateWidget(self.request, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_serialize(self): | 
					
						
							|  |  |  |         node = colander.SchemaNode(colander.Date()) | 
					
						
							|  |  |  |         field = self.make_field(node) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # first try normal date | 
					
						
							|  |  |  |         widget = self.make_widget() | 
					
						
							|  |  |  |         dt = datetime.date(2025, 1, 15) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # editable widget has normal picker html | 
					
						
							|  |  |  |         result = widget.serialize(field, str(dt)) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("<wutta-datepicker", result) | 
					
						
							| 
									
										
										
										
											2025-01-15 08:40:56 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # readonly is rendered per app convention | 
					
						
							|  |  |  |         result = widget.serialize(field, str(dt), readonly=True) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(result, "2025-01-15") | 
					
						
							| 
									
										
										
										
											2025-01-15 08:40:56 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # now try again with datetime | 
					
						
							|  |  |  |         widget = self.make_widget() | 
					
						
							|  |  |  |         dt = datetime.datetime(2025, 1, 15, 8, 35) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # editable widget has normal picker html | 
					
						
							|  |  |  |         result = widget.serialize(field, str(dt)) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("<wutta-datepicker", result) | 
					
						
							| 
									
										
										
										
											2025-01-15 08:40:56 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # readonly is rendered per app convention | 
					
						
							|  |  |  |         result = widget.serialize(field, str(dt), readonly=True) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(result, "2025-01-15") | 
					
						
							| 
									
										
										
										
											2025-01-15 08:40:56 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 15:15:00 -06:00
										 |  |  | class TestWuttaDateTimeWidget(WebTestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def make_field(self, node, **kwargs): | 
					
						
							|  |  |  |         # TODO: not sure why default renderer is in use even though | 
					
						
							|  |  |  |         # pyramid_deform was included in setup?  but this works.. | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         kwargs.setdefault("renderer", deform.Form.default_renderer) | 
					
						
							| 
									
										
										
										
											2024-12-12 15:15:00 -06:00
										 |  |  |         return deform.Field(node, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def make_widget(self, **kwargs): | 
					
						
							|  |  |  |         return mod.WuttaDateTimeWidget(self.request, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_serialize(self): | 
					
						
							|  |  |  |         node = colander.SchemaNode(WuttaDateTime()) | 
					
						
							|  |  |  |         field = self.make_field(node) | 
					
						
							|  |  |  |         widget = self.make_widget() | 
					
						
							|  |  |  |         dt = datetime.datetime(2024, 12, 12, 13, 49, tzinfo=datetime.timezone.utc) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # editable widget has normal picker html | 
					
						
							|  |  |  |         result = widget.serialize(field, str(dt)) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("<wutta-datepicker", result) | 
					
						
							| 
									
										
										
										
											2024-12-12 15:15:00 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # readonly is rendered per app convention | 
					
						
							|  |  |  |         result = widget.serialize(field, str(dt), readonly=True) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(result, "2024-12-12 13:49+0000") | 
					
						
							| 
									
										
										
										
											2024-12-12 15:15:00 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-28 20:33:56 -06:00
										 |  |  | class TestWuttaMoneyInputWidget(WebTestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def make_field(self, node, **kwargs): | 
					
						
							|  |  |  |         # TODO: not sure why default renderer is in use even though | 
					
						
							|  |  |  |         # pyramid_deform was included in setup?  but this works.. | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         kwargs.setdefault("renderer", deform.Form.default_renderer) | 
					
						
							| 
									
										
										
										
											2024-12-28 20:33:56 -06:00
										 |  |  |         return deform.Field(node, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def make_widget(self, **kwargs): | 
					
						
							|  |  |  |         return mod.WuttaMoneyInputWidget(self.request, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_serialize(self): | 
					
						
							| 
									
										
										
										
											2025-01-02 21:28:55 -06:00
										 |  |  |         node = colander.SchemaNode(schema.WuttaMoney(self.request)) | 
					
						
							| 
									
										
										
										
											2024-12-28 20:33:56 -06:00
										 |  |  |         field = self.make_field(node) | 
					
						
							|  |  |  |         widget = self.make_widget() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         amount = decimal.Decimal("12.34") | 
					
						
							| 
									
										
										
										
											2024-12-28 20:33:56 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # editable widget has normal text input | 
					
						
							|  |  |  |         result = widget.serialize(field, str(amount)) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("<b-input", result) | 
					
						
							| 
									
										
										
										
											2024-12-28 20:33:56 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # readonly is rendered per app convention | 
					
						
							|  |  |  |         result = widget.serialize(field, str(amount), readonly=True) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(result, "<span>$12.34</span>") | 
					
						
							| 
									
										
										
										
											2024-12-28 20:33:56 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # readonly w/ null value | 
					
						
							|  |  |  |         result = widget.serialize(field, None, readonly=True) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(result, "<span></span>") | 
					
						
							| 
									
										
										
										
											2024-12-28 20:33:56 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-25 12:20:28 -05:00
										 |  |  | class TestFileDownloadWidget(WebTestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def make_field(self, node, **kwargs): | 
					
						
							|  |  |  |         # TODO: not sure why default renderer is in use even though | 
					
						
							|  |  |  |         # pyramid_deform was included in setup?  but this works.. | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         kwargs.setdefault("renderer", deform.Form.default_renderer) | 
					
						
							| 
									
										
										
										
											2024-08-25 12:20:28 -05:00
										 |  |  |         return deform.Field(node, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_serialize(self): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # nb. we let the field construct the widget via our type | 
					
						
							|  |  |  |         # (nb. at first we do not provide a url) | 
					
						
							|  |  |  |         node = colander.SchemaNode(FileDownload(self.request)) | 
					
						
							|  |  |  |         field = self.make_field(node) | 
					
						
							|  |  |  |         widget = field.widget | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # null value | 
					
						
							|  |  |  |         html = widget.serialize(field, None, readonly=True) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertNotIn("<a ", html) | 
					
						
							|  |  |  |         self.assertIn("<span>", html) | 
					
						
							| 
									
										
										
										
											2024-08-25 12:20:28 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # path to nonexistent file | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         html = widget.serialize(field, "/this/path/does/not/exist", readonly=True) | 
					
						
							|  |  |  |         self.assertNotIn("<a ", html) | 
					
						
							|  |  |  |         self.assertIn("<span>", html) | 
					
						
							| 
									
										
										
										
											2024-08-25 12:20:28 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # path to actual file | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         datfile = self.write_file("data.txt", "hello\n" * 1000) | 
					
						
							| 
									
										
										
										
											2024-08-25 12:20:28 -05:00
										 |  |  |         html = widget.serialize(field, datfile, readonly=True) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertNotIn("<a ", html) | 
					
						
							|  |  |  |         self.assertIn("<span>", html) | 
					
						
							|  |  |  |         self.assertIn("data.txt", html) | 
					
						
							|  |  |  |         self.assertIn("kB)", html) | 
					
						
							| 
									
										
										
										
											2024-08-25 12:20:28 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # path to file, w/ url | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         node = colander.SchemaNode(FileDownload(self.request, url="/download/blarg")) | 
					
						
							| 
									
										
										
										
											2024-08-25 12:20:28 -05:00
										 |  |  |         field = self.make_field(node) | 
					
						
							|  |  |  |         widget = field.widget | 
					
						
							|  |  |  |         html = widget.serialize(field, datfile, readonly=True) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertNotIn("<span>", html) | 
					
						
							| 
									
										
										
										
											2024-08-25 12:20:28 -05:00
										 |  |  |         self.assertIn('<a href="/download/blarg">', html) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("data.txt", html) | 
					
						
							|  |  |  |         self.assertIn("kB)", html) | 
					
						
							| 
									
										
										
										
											2024-08-25 12:20:28 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # nb. same readonly output even if we ask for editable | 
					
						
							|  |  |  |         html2 = widget.serialize(field, datfile, readonly=False) | 
					
						
							|  |  |  |         self.assertEqual(html2, html) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-09 20:56:09 -06:00
										 |  |  | class TestGridWidget(WebTestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def make_field(self, node, **kwargs): | 
					
						
							|  |  |  |         # TODO: not sure why default renderer is in use even though | 
					
						
							|  |  |  |         # pyramid_deform was included in setup?  but this works.. | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         kwargs.setdefault("renderer", deform.Form.default_renderer) | 
					
						
							| 
									
										
										
										
											2024-12-09 20:56:09 -06:00
										 |  |  |         return deform.Field(node, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_serialize(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         grid = grids.Grid( | 
					
						
							|  |  |  |             self.request, | 
					
						
							|  |  |  |             columns=["foo", "bar"], | 
					
						
							|  |  |  |             data=[{"foo": 1, "bar": 2}, {"foo": 3, "bar": 4}], | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-12-09 20:56:09 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         node = colander.SchemaNode(colander.String()) | 
					
						
							|  |  |  |         widget = mod.GridWidget(self.request, grid) | 
					
						
							|  |  |  |         field = self.make_field(node) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # readonly works okay | 
					
						
							|  |  |  |         html = widget.serialize(field, None, readonly=True) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("<b-table ", html) | 
					
						
							| 
									
										
										
										
											2024-12-09 20:56:09 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # but otherwise, error | 
					
						
							|  |  |  |         self.assertRaises(NotImplementedError, widget.serialize, field, None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | class TestRoleRefsWidget(WebTestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def make_field(self, node, **kwargs): | 
					
						
							|  |  |  |         # TODO: not sure why default renderer is in use even though | 
					
						
							|  |  |  |         # pyramid_deform was included in setup?  but this works.. | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         kwargs.setdefault("renderer", deform.Form.default_renderer) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         return deform.Field(node, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_serialize(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.pyramid_config.add_route("roles.view", "/roles/{uuid}") | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         model = self.app.model | 
					
						
							|  |  |  |         auth = self.app.get_auth_handler() | 
					
						
							|  |  |  |         admin = auth.get_role_administrator(self.session) | 
					
						
							|  |  |  |         blokes = model.Role(name="Blokes") | 
					
						
							|  |  |  |         self.session.add(blokes) | 
					
						
							|  |  |  |         self.session.commit() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # nb. we let the field construct the widget via our type | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(schema, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-02 21:09:31 -06:00
										 |  |  |             node = colander.SchemaNode(RoleRefs(self.request)) | 
					
						
							|  |  |  |             field = self.make_field(node) | 
					
						
							|  |  |  |             widget = field.widget | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # readonly values list includes admin | 
					
						
							|  |  |  |             html = widget.serialize(field, {admin.uuid, blokes.uuid}, readonly=True) | 
					
						
							|  |  |  |             self.assertIn(admin.name, html) | 
					
						
							|  |  |  |             self.assertIn(blokes.name, html) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # editable values list *excludes* admin (by default) | 
					
						
							|  |  |  |             html = widget.serialize(field, {admin.uuid, blokes.uuid}) | 
					
						
							|  |  |  |             self.assertNotIn(str(admin.uuid.hex), html) | 
					
						
							|  |  |  |             self.assertIn(str(blokes.uuid.hex), html) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # but admin is included for root user | 
					
						
							|  |  |  |             self.request.is_root = True | 
					
						
							|  |  |  |             node = colander.SchemaNode(RoleRefs(self.request)) | 
					
						
							|  |  |  |             field = self.make_field(node) | 
					
						
							|  |  |  |             widget = field.widget | 
					
						
							|  |  |  |             html = widget.serialize(field, {admin.uuid, blokes.uuid}) | 
					
						
							|  |  |  |             self.assertIn(str(admin.uuid.hex), html) | 
					
						
							|  |  |  |             self.assertIn(str(blokes.uuid.hex), html) | 
					
						
							| 
									
										
										
										
											2024-08-14 15:10:54 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestPermissionsWidget(WebTestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def make_field(self, node, **kwargs): | 
					
						
							|  |  |  |         # TODO: not sure why default renderer is in use even though | 
					
						
							|  |  |  |         # pyramid_deform was included in setup?  but this works.. | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         kwargs.setdefault("renderer", deform.Form.default_renderer) | 
					
						
							| 
									
										
										
										
											2024-08-14 15:10:54 -05:00
										 |  |  |         return deform.Field(node, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_serialize(self): | 
					
						
							|  |  |  |         permissions = { | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             "widgets": { | 
					
						
							|  |  |  |                 "label": "Widgets", | 
					
						
							|  |  |  |                 "perms": { | 
					
						
							|  |  |  |                     "widgets.polish": { | 
					
						
							|  |  |  |                         "label": "Polish the widgets", | 
					
						
							| 
									
										
										
										
											2024-08-14 15:10:54 -05:00
										 |  |  |                     }, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # nb. we let the field construct the widget via our type | 
					
						
							| 
									
										
										
										
											2025-01-02 21:09:31 -06:00
										 |  |  |         node = colander.SchemaNode(Permissions(self.request, permissions)) | 
					
						
							| 
									
										
										
										
											2024-08-14 15:10:54 -05:00
										 |  |  |         field = self.make_field(node) | 
					
						
							|  |  |  |         widget = field.widget | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # readonly output does *not* include the perm by default | 
					
						
							|  |  |  |         html = widget.serialize(field, set(), readonly=True) | 
					
						
							|  |  |  |         self.assertNotIn("Polish the widgets", html) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # readonly output includes the perm if set | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         html = widget.serialize(field, {"widgets.polish"}, readonly=True) | 
					
						
							| 
									
										
										
										
											2024-08-14 15:10:54 -05:00
										 |  |  |         self.assertIn("Polish the widgets", html) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # editable output always includes the perm | 
					
						
							|  |  |  |         html = widget.serialize(field, set()) | 
					
						
							|  |  |  |         self.assertIn("Polish the widgets", html) | 
					
						
							| 
									
										
										
										
											2024-12-13 22:20:04 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-23 19:24:17 -06:00
										 |  |  | class TestEmailRecipientsWidget(WebTestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def make_field(self, node, **kwargs): | 
					
						
							|  |  |  |         # TODO: not sure why default renderer is in use even though | 
					
						
							|  |  |  |         # pyramid_deform was included in setup?  but this works.. | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         kwargs.setdefault("renderer", deform.Form.default_renderer) | 
					
						
							| 
									
										
										
										
											2024-12-23 19:24:17 -06:00
										 |  |  |         return deform.Field(node, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_serialize(self): | 
					
						
							|  |  |  |         node = colander.SchemaNode(EmailRecipients()) | 
					
						
							|  |  |  |         field = self.make_field(node) | 
					
						
							|  |  |  |         widget = mod.EmailRecipientsWidget() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         recips = [ | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             "alice@example.com", | 
					
						
							|  |  |  |             "bob@example.com", | 
					
						
							| 
									
										
										
										
											2024-12-23 19:24:17 -06:00
										 |  |  |         ] | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         recips_str = ", ".join(recips) | 
					
						
							| 
									
										
										
										
											2024-12-23 19:24:17 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # readonly | 
					
						
							|  |  |  |         result = widget.serialize(field, recips_str, readonly=True) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("<ul>", result) | 
					
						
							|  |  |  |         self.assertIn("<li>alice@example.com</li>", result) | 
					
						
							| 
									
										
										
										
											2024-12-23 19:24:17 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # editable | 
					
						
							|  |  |  |         result = widget.serialize(field, recips_str) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("<b-input", result) | 
					
						
							| 
									
										
										
										
											2024-12-23 19:24:17 -06:00
										 |  |  |         self.assertIn('type="textarea"', result) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_deserialize(self): | 
					
						
							|  |  |  |         node = colander.SchemaNode(EmailRecipients()) | 
					
						
							|  |  |  |         field = self.make_field(node) | 
					
						
							|  |  |  |         widget = mod.EmailRecipientsWidget() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         recips = [ | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             "alice@example.com", | 
					
						
							|  |  |  |             "bob@example.com", | 
					
						
							| 
									
										
										
										
											2024-12-23 19:24:17 -06:00
										 |  |  |         ] | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         recips_str = ", ".join(recips) | 
					
						
							| 
									
										
										
										
											2024-12-23 19:24:17 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # values | 
					
						
							|  |  |  |         result = widget.deserialize(field, recips_str) | 
					
						
							|  |  |  |         self.assertEqual(result, recips_str) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # null | 
					
						
							|  |  |  |         result = widget.deserialize(field, colander.null) | 
					
						
							|  |  |  |         self.assertIs(result, colander.null) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-13 22:20:04 -06:00
										 |  |  | class TestBatchIdWidget(WebTestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def make_field(self, node, **kwargs): | 
					
						
							|  |  |  |         # TODO: not sure why default renderer is in use even though | 
					
						
							|  |  |  |         # pyramid_deform was included in setup?  but this works.. | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         kwargs.setdefault("renderer", deform.Form.default_renderer) | 
					
						
							| 
									
										
										
										
											2024-12-13 22:20:04 -06:00
										 |  |  |         return deform.Field(node, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_serialize(self): | 
					
						
							|  |  |  |         node = colander.SchemaNode(colander.Integer()) | 
					
						
							|  |  |  |         field = self.make_field(node) | 
					
						
							|  |  |  |         widget = mod.BatchIdWidget() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         result = widget.serialize(field, colander.null) | 
					
						
							|  |  |  |         self.assertIs(result, colander.null) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         result = widget.serialize(field, 42) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(result, "00000042") |