feat: add basic Edit support for CRUD master view
This commit is contained in:
parent
9e1fc6e57d
commit
1a8fc8dd44
12 changed files with 640 additions and 51 deletions
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
|
||||
from unittest import TestCase
|
||||
from unittest.mock import MagicMock
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import colander
|
||||
import deform
|
||||
|
@ -151,6 +151,34 @@ class TestForm(TestCase):
|
|||
dform = form.get_deform()
|
||||
self.assertEqual(dform.cstruct, myobj)
|
||||
|
||||
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")
|
||||
|
@ -170,6 +198,26 @@ class TestForm(TestCase):
|
|||
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_render_vue_tag(self):
|
||||
schema = self.make_schema()
|
||||
form = self.make_form(schema=schema)
|
||||
|
@ -183,13 +231,13 @@ class TestForm(TestCase):
|
|||
|
||||
# form button is disabled on @submit by default
|
||||
schema = self.make_schema()
|
||||
form = self.make_form(schema=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)
|
||||
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)
|
||||
|
@ -224,6 +272,25 @@ class TestForm(TestCase):
|
|||
html = form.render_vue_field('foo')
|
||||
self.assertIn(':message="`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_field_errors(self):
|
||||
schema = self.make_schema()
|
||||
form = self.make_form(schema=schema)
|
||||
|
|
|
@ -18,11 +18,11 @@ from tests.views.utils import WebTestCase
|
|||
class TestMasterView(WebTestCase):
|
||||
|
||||
def test_defaults(self):
|
||||
master.MasterView.model_name = 'Widget'
|
||||
with patch.object(master.MasterView, 'viewable', new=False):
|
||||
# TODO: should inspect pyramid routes after this, to be certain
|
||||
with patch.multiple(master.MasterView, create=True,
|
||||
model_name='Widget',
|
||||
viewable=False,
|
||||
editable=False):
|
||||
master.MasterView.defaults(self.pyramid_config)
|
||||
del master.MasterView.model_name
|
||||
|
||||
##############################
|
||||
# class methods
|
||||
|
@ -374,17 +374,75 @@ class TestMasterView(WebTestCase):
|
|||
def test_view(self):
|
||||
|
||||
# sanity/coverage check using /settings/XXX
|
||||
master.MasterView.model_name = 'Setting'
|
||||
master.MasterView.grid_columns = ['name', 'value']
|
||||
master.MasterView.form_fields = ['name', 'value']
|
||||
view = master.MasterView(self.request)
|
||||
setting = {'name': 'foo.bar', 'value': 'baz'}
|
||||
self.request.matchdict = {'name': 'foo.bar'}
|
||||
with patch.object(view, 'get_instance', return_value=setting):
|
||||
response = view.view()
|
||||
del master.MasterView.model_name
|
||||
del master.MasterView.grid_columns
|
||||
del master.MasterView.form_fields
|
||||
with patch.multiple(master.MasterView, create=True,
|
||||
model_name='Setting',
|
||||
model_key='name',
|
||||
grid_columns=['name', 'value'],
|
||||
form_fields=['name', 'value']):
|
||||
view = master.MasterView(self.request)
|
||||
with patch.object(view, 'get_instance', return_value=setting):
|
||||
response = view.view()
|
||||
|
||||
def test_edit(self):
|
||||
model = self.app.model
|
||||
self.app.save_setting(self.session, 'foo.bar', 'frazzle')
|
||||
self.session.commit()
|
||||
|
||||
def get_instance():
|
||||
setting = self.session.query(model.Setting).get('foo.bar')
|
||||
return {
|
||||
'name': setting.name,
|
||||
'value': setting.value,
|
||||
}
|
||||
|
||||
# sanity/coverage check using /settings/XXX/edit
|
||||
self.request.matchdict = {'name': 'foo.bar'}
|
||||
with patch.multiple(master.MasterView, create=True,
|
||||
model_name='Setting',
|
||||
model_key='name',
|
||||
form_fields=['name', 'value']):
|
||||
view = master.MasterView(self.request)
|
||||
with patch.object(view, 'get_instance', new=get_instance):
|
||||
|
||||
# get the form page
|
||||
response = view.edit()
|
||||
self.assertIsInstance(response, Response)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('frazzle', response.text)
|
||||
# nb. no error
|
||||
self.assertNotIn('Required', response.text)
|
||||
|
||||
def persist(setting):
|
||||
self.app.save_setting(self.session, setting['name'], setting['value'])
|
||||
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.assertIsInstance(response, HTTPFound)
|
||||
# setting should be updated in DB
|
||||
self.assertEqual(self.app.get_setting(self.session, 'foo.bar'), 'froogle')
|
||||
|
||||
# try another post with invalid data (name is required)
|
||||
self.request.method = 'POST'
|
||||
self.request.POST = {
|
||||
'value': 'gargoyle',
|
||||
}
|
||||
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')
|
||||
|
||||
def test_configure(self):
|
||||
model = self.app.model
|
||||
|
|
|
@ -65,3 +65,30 @@ class TestSettingView(WebTestCase):
|
|||
view = self.make_view()
|
||||
title = view.get_instance_title(setting)
|
||||
self.assertEqual(title, 'foo')
|
||||
|
||||
def test_make_model_form(self):
|
||||
view = self.make_view()
|
||||
view.editing = True
|
||||
form = view.make_model_form()
|
||||
self.assertEqual(form.fields, ['name', 'value'])
|
||||
self.assertIn('name', form)
|
||||
self.assertIn('value', form)
|
||||
dform = form.get_deform()
|
||||
self.assertNotIn('name', dform)
|
||||
self.assertIn('value', dform)
|
||||
|
||||
def test_persist(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
||||
# setup
|
||||
self.app.save_setting(self.session, 'foo', 'bar')
|
||||
self.session.commit()
|
||||
self.assertEqual(self.session.query(model.Setting).count(), 1)
|
||||
|
||||
# setting is updated
|
||||
self.request.matchdict = {'name': 'foo'}
|
||||
view.persist({'name': 'foo', 'value': 'frazzle'}, session=self.session)
|
||||
self.session.commit()
|
||||
self.assertEqual(self.session.query(model.Setting).count(), 1)
|
||||
self.assertEqual(self.app.get_setting(self.session, 'foo'), 'frazzle')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue