3
0
Fork 0

fix: rename form-saving methods etc. for consistency in MasterView

also adds redirect methods where missing
This commit is contained in:
Lance Edgar 2025-12-23 20:28:46 -06:00
parent 3e7aa1fa0b
commit 9edf6f298c
3 changed files with 399 additions and 196 deletions

View file

@ -9,7 +9,7 @@ from unittest.mock import MagicMock, patch
from sqlalchemy import orm
from pyramid import testing
from pyramid.response import Response
from pyramid.httpexceptions import HTTPNotFound
from pyramid.httpexceptions import HTTPNotFound, HTTPFound
from wuttjamaican.conf import WuttaConfig
from wuttaweb.views import master as mod
@ -977,7 +977,7 @@ class TestMasterView(WebTestCase):
form = view.make_model_form(fields=["name", "description"])
form.validated = {"name": "first"}
obj = view.objectify(form)
self.assertIs(obj, form.validated)
self.assertEqual(obj, form.validated)
# explicit model class (editing)
with patch.multiple(
@ -1115,6 +1115,40 @@ class TestMasterView(WebTestCase):
# setting did not change in DB
self.assertEqual(self.app.get_setting(self.session, "foo.bar"), "fraggle")
# post again to save setting
with patch.multiple(
self.request,
method="POST",
POST={
"name": "foo.bar",
"value": "friggle",
},
):
with patch.object(view, "persist", new=persist):
response = view.create()
self.assertIsInstance(response, HTTPFound)
self.assertFalse(self.request.session.peek_flash("error"))
self.assertEqual(
self.app.get_setting(self.session, "foo.bar"), "friggle"
)
# and this time force an error on save
with patch.multiple(
self.request,
method="POST",
POST={"name": "foo.bar", "value": "froooooggle"},
):
with patch.object(
view, "save_create_form", side_effect=RuntimeError("testing")
):
response = view.create()
self.assertEqual(response.status_code, 200)
# nb. flash error is already gone, b/c template is rendered
self.assertFalse(self.request.session.peek_flash("error"))
self.assertEqual(
self.app.get_setting(self.session, "foo.bar"), "friggle"
)
def test_view(self):
self.pyramid_config.include("wuttaweb.views.common")
self.pyramid_config.include("wuttaweb.views.auth")
@ -1210,6 +1244,7 @@ class TestMasterView(WebTestCase):
with patch.multiple(
mod.MasterView,
create=True,
# nb. not actually using the model_class here
model_name="Setting",
model_key="name",
get_index_url=MagicMock(return_value="/settings/"),
@ -1231,32 +1266,54 @@ class TestMasterView(WebTestCase):
self.session.commit()
# post request to save settings
self.request.method = "POST"
self.request.POST = {
"name": "foo.bar",
"value": "froogle",
}
with patch.object(view, "persist", new=persist):
response = view.edit()
# nb. should get redirect back to view page
self.assertEqual(response.status_code, 302)
# setting should be updated in DB
self.assertEqual(
self.app.get_setting(self.session, "foo.bar"), "froogle"
)
with patch.multiple(
self.request,
method="POST",
POST={"name": "foo.bar", "value": "froogle"},
):
with patch.object(view, "persist", new=persist):
response = view.edit()
self.assertIsInstance(response, HTTPFound)
self.assertEqual(
response.location, "http://example.com/settings/foo.bar"
)
# setting is saved in DB
self.assertEqual(
self.app.get_setting(self.session, "foo.bar"), "froogle"
)
# try another post with invalid data (value is required)
self.request.method = "POST"
self.request.POST = {}
with patch.object(view, "persist", new=persist):
response = view.edit()
# nb. should get a form with errors
self.assertEqual(response.status_code, 200)
self.assertIn("Required", response.text)
# setting did not change in DB
self.assertEqual(
self.app.get_setting(self.session, "foo.bar"), "froogle"
)
with patch.multiple(self.request, method="POST", POST={}):
with patch.object(view, "persist", new=persist):
response = view.edit()
# nb. should get a form with errors
self.assertEqual(response.status_code, 200)
self.assertIn("Required", response.text)
# setting did not change in DB
self.assertEqual(
self.app.get_setting(self.session, "foo.bar"), "froogle"
)
# once more with forced error
with patch.multiple(
self.request,
method="POST",
POST={
"name": "foo.bar",
"value": "froooooggle",
},
):
with patch.object(
view, "save_edit_form", side_effect=RuntimeError("testing")
):
response = view.edit()
self.assertEqual(response.status_code, 200)
# nb. flash error is already gone, b/c template is rendered
self.assertFalse(self.request.session.peek_flash("error"))
# setting did not change in DB
self.assertEqual(
self.app.get_setting(self.session, "foo.bar"), "froogle"
)
def test_delete(self):
self.pyramid_config.include("wuttaweb.views.common")
@ -1266,18 +1323,21 @@ class TestMasterView(WebTestCase):
self.pyramid_config.add_route("settings.edit", "/settings/{name}/edit")
model = self.app.model
self.app.save_setting(self.session, "foo.bar", "frazzle")
self.app.save_setting(self.session, "another", "fun-value")
self.session.commit()
self.assertEqual(self.session.query(model.Setting).count(), 1)
self.assertEqual(self.session.query(model.Setting).count(), 2)
def get_instance():
setting = self.session.get(model.Setting, "foo.bar")
name = self.request.matchdict["name"]
setting = self.session.get(model.Setting, name)
if not setting:
raise view.notfound()
return {
"name": setting.name,
"value": setting.value,
}
# sanity/coverage check using /settings/XXX/delete
self.request.matchdict = {"name": "foo.bar"}
with patch.multiple(
mod.MasterView,
create=True,
@ -1290,32 +1350,51 @@ class TestMasterView(WebTestCase):
with patch.object(view, "get_instance", new=get_instance):
# get the form page
response = view.delete()
self.assertIsInstance(response, Response)
self.assertEqual(response.status_code, 200)
self.assertIn("frazzle", response.text)
with patch.object(self.request, "matchdict", new={"name": "foo.bar"}):
response = view.delete()
self.assertIsInstance(response, Response)
self.assertEqual(response.status_code, 200)
self.assertIn("frazzle", response.text)
def delete_instance(setting):
self.app.delete_setting(self.session, setting["name"])
self.request.method = "POST"
self.request.POST = {}
with patch.object(view, "delete_instance", new=delete_instance):
with patch.multiple(
self.request, matchdict={"name": "foo.bar"}, method="POST", POST={}
):
with patch.object(view, "delete_instance", new=delete_instance):
# enforces "instance not deletable" rules
with patch.object(view, "is_deletable", return_value=False):
# enforces "instance not deletable" rules
with patch.object(view, "is_deletable", return_value=False):
response = view.delete()
# nb. should get redirect back to view page
self.assertEqual(response.status_code, 302)
# setting remains in DB
self.assertEqual(self.session.query(model.Setting).count(), 2)
# post request to delete setting
response = view.delete()
# nb. should get redirect back to view page
self.assertEqual(response.status_code, 302)
# setting remains in DB
self.assertEqual(self.session.query(model.Setting).count(), 1)
# nb. should get redirect back to view page
self.assertEqual(response.status_code, 302)
# setting should be gone from DB
self.assertEqual(self.session.query(model.Setting).count(), 1)
# post request to delete setting
response = view.delete()
# nb. should get redirect back to view page
self.assertEqual(response.status_code, 302)
# setting should be gone from DB
self.assertEqual(self.session.query(model.Setting).count(), 0)
# try to delete 2nd setting, but force an error
with patch.multiple(
self.request, matchdict={"name": "another"}, method="POST", POST={}
):
with patch.object(
view, "save_delete_form", side_effect=RuntimeError("testing")
):
response = view.delete()
self.assertEqual(response.status_code, 200)
# nb. flash error is already gone, b/c template is rendered
self.assertFalse(self.request.session.peek_flash("error"))
# setting is still in DB
self.assertEqual(self.session.query(model.Setting).count(), 1)
self.assertEqual(
self.app.get_setting(self.session, "another"), "fun-value"
)
def test_delete_instance(self):
model = self.app.model