fix: add basic create_row() support, esp. for batch views
This commit is contained in:
parent
66eccc52a2
commit
10610d5809
6 changed files with 696 additions and 48 deletions
|
|
@ -156,6 +156,17 @@ class TestBatchMasterView(WebTestCase):
|
|||
form = view.make_model_form(model_instance=batch)
|
||||
view.configure_form(form)
|
||||
|
||||
def test_is_editable(self):
|
||||
handler = self.make_handler()
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
):
|
||||
view = self.make_view()
|
||||
batch = handler.make_batch(self.session)
|
||||
self.assertTrue(view.is_editable(batch))
|
||||
batch.executed = datetime.datetime.now()
|
||||
self.assertFalse(view.is_editable(batch))
|
||||
|
||||
def test_objectify(self):
|
||||
handler = self.make_handler()
|
||||
with patch.multiple(mod.BatchMasterView, create=True, model_class=MockBatch):
|
||||
|
|
@ -345,24 +356,33 @@ class TestBatchMasterView(WebTestCase):
|
|||
):
|
||||
view = self.make_view()
|
||||
|
||||
self.assertRaises(AttributeError, view.get_row_model_class)
|
||||
self.assertIsNone(view.get_row_model_class())
|
||||
|
||||
# row class determined from batch class
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "model_class", new=MockBatch, create=True
|
||||
):
|
||||
with patch.object(mod.BatchMasterView, "model_class", new=MockBatch):
|
||||
cls = view.get_row_model_class()
|
||||
self.assertIs(cls, MockBatchRow)
|
||||
|
||||
self.assertRaises(AttributeError, view.get_row_model_class)
|
||||
self.assertIsNone(view.get_row_model_class())
|
||||
|
||||
# view may specify row class
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "row_model_class", new=MockBatchRow, create=True
|
||||
):
|
||||
with patch.object(mod.BatchMasterView, "row_model_class", new=MockBatchRow):
|
||||
cls = view.get_row_model_class()
|
||||
self.assertIs(cls, MockBatchRow)
|
||||
|
||||
def test_get_row_parent(self):
|
||||
handler = self.make_handler()
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
):
|
||||
view = self.make_view()
|
||||
batch = handler.make_batch(self.session)
|
||||
self.session.add(batch)
|
||||
row = handler.make_row()
|
||||
handler.add_row(batch, row)
|
||||
parent = view.get_row_parent(row)
|
||||
self.assertIs(parent, batch)
|
||||
|
||||
def test_get_row_grid_data(self):
|
||||
handler = self.make_handler()
|
||||
model = self.app.model
|
||||
|
|
@ -395,6 +415,9 @@ class TestBatchMasterView(WebTestCase):
|
|||
self.assertEqual(data.count(), 1)
|
||||
|
||||
def test_configure_row_grid(self):
|
||||
self.pyramid_config.add_route(
|
||||
"mock_batches.create_row", "/batch/mock/{uuid}/new-row"
|
||||
)
|
||||
handler = self.make_handler()
|
||||
model = self.app.model
|
||||
|
||||
|
|
@ -410,18 +433,50 @@ class TestBatchMasterView(WebTestCase):
|
|||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
):
|
||||
view = self.make_view()
|
||||
|
||||
Session = MagicMock(return_value=self.session)
|
||||
Session.query.side_effect = lambda m: self.session.query(m)
|
||||
with patch.multiple(
|
||||
mod.BatchMasterView, create=True, Session=Session, model_class=MockBatch
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "Session", return_value=self.session
|
||||
):
|
||||
with patch.multiple(
|
||||
mod.BatchMasterView,
|
||||
model_class=MockBatch,
|
||||
route_prefix="mock_batches",
|
||||
create=True,
|
||||
):
|
||||
with patch.object(
|
||||
self.request, "matchdict", new={"uuid": batch.uuid}
|
||||
):
|
||||
|
||||
with patch.object(self.request, "matchdict", new={"uuid": batch.uuid}):
|
||||
view = self.make_view()
|
||||
grid = view.make_row_model_grid(batch)
|
||||
self.assertIn("sequence", grid.labels)
|
||||
self.assertEqual(grid.labels["sequence"], "Seq.")
|
||||
# basic sanity check
|
||||
grid = view.make_row_model_grid(batch)
|
||||
self.assertEqual(
|
||||
grid.columns, ["sequence", "status_code", "modified"]
|
||||
)
|
||||
self.assertIn("sequence", grid.labels)
|
||||
self.assertEqual(grid.labels["sequence"], "Seq.")
|
||||
self.assertEqual(grid.tools, {})
|
||||
|
||||
# missing 'sequence' column
|
||||
grid = view.make_row_model_grid(
|
||||
batch, columns=["status_code", "modified"]
|
||||
)
|
||||
self.assertEqual(grid.columns, ["status_code", "modified"])
|
||||
|
||||
# sequence column is made to be first if present
|
||||
grid = view.make_row_model_grid(
|
||||
batch, columns=["status_code", "modified", "sequence"]
|
||||
)
|
||||
self.assertEqual(
|
||||
grid.columns, ["sequence", "status_code", "modified"]
|
||||
)
|
||||
|
||||
# with "create row" button
|
||||
with patch.object(
|
||||
self.request, "is_root", new=True, create=True
|
||||
):
|
||||
grid = view.make_row_model_grid(batch)
|
||||
self.assertIn("create_row", grid.tools)
|
||||
|
||||
def test_render_row_status(self):
|
||||
with patch.object(mod.BatchMasterView, "get_batch_handler", return_value=None):
|
||||
|
|
@ -429,9 +484,53 @@ class TestBatchMasterView(WebTestCase):
|
|||
row = MagicMock(foo=1, STATUS={1: "bar"})
|
||||
self.assertEqual(view.render_row_status(row, "foo", 1), "bar")
|
||||
|
||||
def test_configure_row_form(self):
|
||||
handler = self.make_handler()
|
||||
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
):
|
||||
view = self.make_view()
|
||||
|
||||
# some fields are readonly by default
|
||||
form = view.make_form(model_class=MockBatchRow)
|
||||
view.configure_row_form(form)
|
||||
self.assertIn("sequence", form.fields)
|
||||
self.assertTrue(form.is_readonly("sequence"))
|
||||
self.assertIn("status_code", form.fields)
|
||||
self.assertTrue(form.is_readonly("status_code"))
|
||||
self.assertIn("modified", form.fields)
|
||||
self.assertTrue(form.is_readonly("modified"))
|
||||
|
||||
# but those fields are removed when creating
|
||||
with patch.object(view, "creating", new=True):
|
||||
form = view.make_form(model_class=MockBatchRow)
|
||||
view.configure_row_form(form)
|
||||
self.assertNotIn("sequence", form.fields)
|
||||
self.assertNotIn("status_code", form.fields)
|
||||
self.assertNotIn("modified", form.fields)
|
||||
|
||||
def test_create_row_save_form(self):
|
||||
handler = self.make_handler()
|
||||
batch = MockBatch()
|
||||
row = MockBatchRow()
|
||||
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
):
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "Session", return_value=self.session
|
||||
):
|
||||
view = self.make_view()
|
||||
form = view.make_form(model_class=MockBatchRow)
|
||||
|
||||
with patch.object(view, "get_instance", return_value=batch):
|
||||
with patch.object(view, "objectify", return_value=row):
|
||||
with patch.object(handler, "add_row") as add_row:
|
||||
view.create_row_save_form(form)
|
||||
add_row.assert_called_once_with(batch, row)
|
||||
|
||||
def test_defaults(self):
|
||||
# nb. coverage only
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "model_class", new=MockBatch, create=True
|
||||
):
|
||||
with patch.object(mod.BatchMasterView, "model_class", new=MockBatch):
|
||||
mod.BatchMasterView.defaults(self.pyramid_config)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ class TestMasterView(WebTestCase):
|
|||
downloadable=True,
|
||||
executable=True,
|
||||
configurable=True,
|
||||
has_rows=True,
|
||||
rows_creatable=True,
|
||||
):
|
||||
mod.MasterView.defaults(self.pyramid_config)
|
||||
|
||||
|
|
@ -327,6 +329,68 @@ class TestMasterView(WebTestCase):
|
|||
):
|
||||
self.assertIs(mod.MasterView.get_row_model_class(), model.User)
|
||||
|
||||
def test_get_row_model_name(self):
|
||||
|
||||
# error by default (since no model class)
|
||||
self.assertRaises(AttributeError, mod.MasterView.get_row_model_name)
|
||||
|
||||
# may specify model name directly
|
||||
with patch.object(mod.MasterView, "row_model_name", new="Widget", create=True):
|
||||
self.assertEqual(mod.MasterView.get_row_model_name(), "Widget")
|
||||
|
||||
# or indirectly via model class
|
||||
MyModel = MagicMock(__name__="Blaster")
|
||||
with patch.object(mod.MasterView, "row_model_class", new=MyModel):
|
||||
self.assertEqual(mod.MasterView.get_row_model_name(), "Blaster")
|
||||
|
||||
def test_get_row_model_title(self):
|
||||
|
||||
# error by default (since no model class)
|
||||
self.assertRaises(AttributeError, mod.MasterView.get_row_model_title)
|
||||
|
||||
# may specify model title directly
|
||||
with patch.object(
|
||||
mod.MasterView, "row_model_title", new="Wutta Widget", create=True
|
||||
):
|
||||
self.assertEqual(mod.MasterView.get_row_model_title(), "Wutta Widget")
|
||||
|
||||
# or may specify model name
|
||||
with patch.object(mod.MasterView, "row_model_name", new="Blaster", create=True):
|
||||
self.assertEqual(mod.MasterView.get_row_model_title(), "Blaster")
|
||||
|
||||
# or may specify model class
|
||||
MyModel = MagicMock(__name__="Dinosaur")
|
||||
with patch.object(mod.MasterView, "row_model_class", new=MyModel):
|
||||
self.assertEqual(mod.MasterView.get_row_model_title(), "Dinosaur")
|
||||
|
||||
def test_get_row_model_title_plural(self):
|
||||
|
||||
# error by default (since no model class)
|
||||
self.assertRaises(AttributeError, mod.MasterView.get_row_model_title_plural)
|
||||
|
||||
# subclass may specify *plural* model title
|
||||
with patch.object(
|
||||
mod.MasterView, "row_model_title_plural", new="People", create=True
|
||||
):
|
||||
self.assertEqual(mod.MasterView.get_row_model_title_plural(), "People")
|
||||
|
||||
# or it may specify *singular* model title
|
||||
with patch.object(
|
||||
mod.MasterView, "row_model_title", new="Wutta Widget", create=True
|
||||
):
|
||||
self.assertEqual(
|
||||
mod.MasterView.get_row_model_title_plural(), "Wutta Widgets"
|
||||
)
|
||||
|
||||
# or it may specify model name
|
||||
with patch.object(mod.MasterView, "row_model_name", new="Blaster", create=True):
|
||||
self.assertEqual(mod.MasterView.get_row_model_title_plural(), "Blasters")
|
||||
|
||||
# or it may specify model class
|
||||
MyModel = MagicMock(__name__="Dinosaur")
|
||||
with patch.object(mod.MasterView, "row_model_class", new=MyModel, create=True):
|
||||
self.assertEqual(mod.MasterView.get_row_model_title_plural(), "Dinosaurs")
|
||||
|
||||
##############################
|
||||
# support methods
|
||||
##############################
|
||||
|
|
@ -1722,6 +1786,34 @@ class TestMasterView(WebTestCase):
|
|||
# row methods
|
||||
##############################
|
||||
|
||||
def test_get_rows_title(self):
|
||||
model = self.app.model
|
||||
|
||||
with patch.object(mod.MasterView, "row_model_class", new=model.User):
|
||||
view = self.make_view()
|
||||
|
||||
# default based on row model class
|
||||
self.assertEqual(view.get_rows_title(), "Users")
|
||||
|
||||
# explicit override
|
||||
with patch.object(view, "rows_title", create=True, new="Mock Rows"):
|
||||
self.assertEqual(view.get_rows_title(), "Mock Rows")
|
||||
|
||||
def test_get_row_parent(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
||||
person = model.Person(full_name="Fred Flintstone")
|
||||
self.session.add(person)
|
||||
user = model.User(username="fred", person=person)
|
||||
self.session.add(user)
|
||||
self.session.commit()
|
||||
|
||||
with patch.multiple(
|
||||
mod.MasterView, model_class=model.Person, row_model_class=model.User
|
||||
):
|
||||
self.assertRaises(NotImplementedError, view.get_row_parent, user)
|
||||
|
||||
def test_collect_row_labels(self):
|
||||
|
||||
# default labels
|
||||
|
|
@ -1833,15 +1925,110 @@ class TestMasterView(WebTestCase):
|
|||
row = MagicMock()
|
||||
self.assertRaises(NotImplementedError, view.get_row_action_url_view, row, 0)
|
||||
|
||||
def test_get_rows_title(self):
|
||||
def test_make_row_model_form(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
||||
# no default
|
||||
self.assertIsNone(view.get_rows_title())
|
||||
# no model class
|
||||
form = view.make_row_model_form()
|
||||
self.assertIsNone(form.model_class)
|
||||
|
||||
# class may specify
|
||||
with patch.object(view, "rows_title", create=True, new="Mock Rows"):
|
||||
self.assertEqual(view.get_rows_title(), "Mock Rows")
|
||||
# explicit model class + fields
|
||||
form = view.make_row_model_form(
|
||||
model_class=model.User, fields=["username", "active"]
|
||||
)
|
||||
self.assertIs(form.model_class, model.User)
|
||||
self.assertEqual(form.fields, ["username", "active"])
|
||||
|
||||
# implicit model + fields
|
||||
with patch.multiple(
|
||||
mod.MasterView,
|
||||
create=True,
|
||||
row_model_class=model.User,
|
||||
row_form_fields=["username", "person"],
|
||||
):
|
||||
form = view.make_row_model_form()
|
||||
self.assertIs(form.model_class, model.User)
|
||||
self.assertEqual(form.fields, ["username", "person"])
|
||||
|
||||
def test_configure_row_form(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
||||
# uuid field is pruned
|
||||
with patch.object(mod.MasterView, "row_model_class", new=model.User):
|
||||
form = view.make_form(model_class=model.User, fields=["uuid", "username"])
|
||||
self.assertIn("uuid", form.fields)
|
||||
view.configure_row_form(form)
|
||||
self.assertNotIn("uuid", form.fields)
|
||||
|
||||
def test_create_row(self):
|
||||
self.pyramid_config.add_route("home", "/")
|
||||
self.pyramid_config.add_route("login", "/auth/login")
|
||||
self.pyramid_config.add_route("people", "/people/")
|
||||
self.pyramid_config.add_route("people.view", "/people/{uuid}")
|
||||
model = self.app.model
|
||||
|
||||
person = model.Person(
|
||||
first_name="Fred", last_name="Flintstone", full_name="Fred Flintstone"
|
||||
)
|
||||
self.session.add(person)
|
||||
user = model.User(username="fred", person=person)
|
||||
self.session.add(user)
|
||||
self.session.commit()
|
||||
|
||||
with patch.multiple(
|
||||
mod.MasterView,
|
||||
create=True,
|
||||
model_class=model.Person,
|
||||
row_model_class=model.User,
|
||||
row_form_fields=["person_uuid", "username"],
|
||||
route_prefix="people",
|
||||
):
|
||||
with patch.object(mod.MasterView, "Session", return_value=self.session):
|
||||
with patch.object(self.request, "matchdict", {"uuid": person.uuid}):
|
||||
with patch.object(
|
||||
mod.MasterView, "get_row_parent", return_value=person
|
||||
):
|
||||
view = self.make_view()
|
||||
|
||||
# get the form page
|
||||
response = view.create_row()
|
||||
self.assertIsInstance(response, Response)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
# nb. no error
|
||||
self.assertNotIn("Required", response.text)
|
||||
|
||||
self.assertEqual(len(person.users), 1)
|
||||
|
||||
# post request to add user
|
||||
with patch.multiple(
|
||||
self.request,
|
||||
method="POST",
|
||||
POST={
|
||||
"person_uuid": person.uuid.hex,
|
||||
"username": "freddie2",
|
||||
},
|
||||
):
|
||||
response = view.create_row()
|
||||
# nb. should get redirect back to view page
|
||||
self.assertEqual(response.status_code, 302)
|
||||
# user should now be in DB
|
||||
self.session.refresh(person)
|
||||
self.assertEqual(len(person.users), 2)
|
||||
|
||||
# try another post with invalid data (username is required)
|
||||
with patch.multiple(
|
||||
self.request,
|
||||
method="POST",
|
||||
POST={"person_uuid": person.uuid.hex, "username": ""},
|
||||
):
|
||||
response = view.create_row()
|
||||
# nb. should get a form with errors
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn("Required", response.text)
|
||||
self.session.refresh(person)
|
||||
self.assertEqual(len(person.users), 2)
|
||||
|
||||
|
||||
class TestVersionedMasterView(VersionWebTestCase):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue