fix(tests): add test cases for custom_link and custom_action
This commit is contained in:
parent
8a198f363b
commit
a0a3606a7f
7 changed files with 173 additions and 75 deletions
|
|
@ -159,7 +159,10 @@ def handle_exception(e):
|
|||
response = None
|
||||
http_status_code = getattr(e, "http_status_code", 500)
|
||||
return_as_message = False
|
||||
# print(frappe.get_traceback())
|
||||
|
||||
if frappe.conf.get('developer_mode'):
|
||||
# don't fail silently
|
||||
print(frappe.get_traceback())
|
||||
|
||||
if frappe.get_request_header('Accept') and (frappe.local.is_ajax or 'application/json' in frappe.get_request_header('Accept')):
|
||||
# handle ajax responses first
|
||||
|
|
|
|||
|
|
@ -12,41 +12,22 @@ from frappe.core.doctype.doctype.doctype import UniqueFieldnameError, IllegalMan
|
|||
|
||||
|
||||
class TestDocType(unittest.TestCase):
|
||||
def new_doctype(self, name, unique=0, depends_on=''):
|
||||
return frappe.get_doc({
|
||||
"doctype": "DocType",
|
||||
"module": "Core",
|
||||
"custom": 1,
|
||||
"fields": [{
|
||||
"label": "Some Field",
|
||||
"fieldname": "some_fieldname",
|
||||
"fieldtype": "Data",
|
||||
"unique": unique,
|
||||
"depends_on": depends_on,
|
||||
}],
|
||||
"permissions": [{
|
||||
"role": "System Manager",
|
||||
"read": 1,
|
||||
}],
|
||||
"name": name
|
||||
})
|
||||
|
||||
def test_validate_name(self):
|
||||
self.assertRaises(frappe.NameError, self.new_doctype("_Some DocType").insert)
|
||||
self.assertRaises(frappe.NameError, self.new_doctype("8Some DocType").insert)
|
||||
self.assertRaises(frappe.NameError, self.new_doctype("Some (DocType)").insert)
|
||||
self.assertRaises(frappe.NameError, new_doctype("_Some DocType").insert)
|
||||
self.assertRaises(frappe.NameError, new_doctype("8Some DocType").insert)
|
||||
self.assertRaises(frappe.NameError, new_doctype("Some (DocType)").insert)
|
||||
for name in ("Some DocType", "Some_DocType"):
|
||||
if frappe.db.exists("DocType", name):
|
||||
frappe.delete_doc("DocType", name)
|
||||
|
||||
doc = self.new_doctype(name).insert()
|
||||
doc = new_doctype(name).insert()
|
||||
doc.delete()
|
||||
|
||||
def test_doctype_unique_constraint_dropped(self):
|
||||
if frappe.db.exists("DocType", "With_Unique"):
|
||||
frappe.delete_doc("DocType", "With_Unique")
|
||||
|
||||
dt = self.new_doctype("With_Unique", unique=1)
|
||||
dt = new_doctype("With_Unique", unique=1)
|
||||
dt.insert()
|
||||
|
||||
doc1 = frappe.new_doc("With_Unique")
|
||||
|
|
@ -67,7 +48,7 @@ class TestDocType(unittest.TestCase):
|
|||
doc2.delete()
|
||||
|
||||
def test_validate_search_fields(self):
|
||||
doc = self.new_doctype("Test Search Fields")
|
||||
doc = new_doctype("Test Search Fields")
|
||||
doc.search_fields = "some_fieldname"
|
||||
doc.insert()
|
||||
self.assertEqual(doc.name, "Test Search Fields")
|
||||
|
|
@ -85,7 +66,7 @@ class TestDocType(unittest.TestCase):
|
|||
self.assertRaises(frappe.ValidationError, doc.save)
|
||||
|
||||
def test_depends_on_fields(self):
|
||||
doc = self.new_doctype("Test Depends On", depends_on="eval:doc.__islocal == 0")
|
||||
doc = new_doctype("Test Depends On", depends_on="eval:doc.__islocal == 0")
|
||||
doc.insert()
|
||||
|
||||
# check if the assignment operation is allowed in depends_on
|
||||
|
|
@ -261,7 +242,7 @@ class TestDocType(unittest.TestCase):
|
|||
frappe.flags.allow_doctype_export = 0
|
||||
|
||||
def test_unique_field_name_for_two_fields(self):
|
||||
doc = self.new_doctype('Test Unique Field')
|
||||
doc = new_doctype('Test Unique Field')
|
||||
field_1 = doc.append('fields', {})
|
||||
field_1.fieldname = 'some_fieldname_1'
|
||||
field_1.fieldtype = 'Data'
|
||||
|
|
@ -273,7 +254,7 @@ class TestDocType(unittest.TestCase):
|
|||
self.assertRaises(UniqueFieldnameError, doc.insert)
|
||||
|
||||
def test_fieldname_is_not_name(self):
|
||||
doc = self.new_doctype('Test Name Field')
|
||||
doc = new_doctype('Test Name Field')
|
||||
field_1 = doc.append('fields', {})
|
||||
field_1.label = 'Name'
|
||||
field_1.fieldtype = 'Data'
|
||||
|
|
@ -283,7 +264,7 @@ class TestDocType(unittest.TestCase):
|
|||
self.assertRaises(InvalidFieldNameError, doc.save)
|
||||
|
||||
def test_illegal_mandatory_validation(self):
|
||||
doc = self.new_doctype('Test Illegal mandatory')
|
||||
doc = new_doctype('Test Illegal mandatory')
|
||||
field_1 = doc.append('fields', {})
|
||||
field_1.fieldname = 'some_fieldname_1'
|
||||
field_1.fieldtype = 'Section Break'
|
||||
|
|
@ -292,7 +273,7 @@ class TestDocType(unittest.TestCase):
|
|||
self.assertRaises(IllegalMandatoryError, doc.insert)
|
||||
|
||||
def test_link_with_wrong_and_no_options(self):
|
||||
doc = self.new_doctype('Test link')
|
||||
doc = new_doctype('Test link')
|
||||
field_1 = doc.append('fields', {})
|
||||
field_1.fieldname = 'some_fieldname_1'
|
||||
field_1.fieldtype = 'Link'
|
||||
|
|
@ -304,7 +285,7 @@ class TestDocType(unittest.TestCase):
|
|||
self.assertRaises(WrongOptionsDoctypeLinkError, doc.insert)
|
||||
|
||||
def test_hidden_and_mandatory_without_default(self):
|
||||
doc = self.new_doctype('Test hidden and mandatory')
|
||||
doc = new_doctype('Test hidden and mandatory')
|
||||
field_1 = doc.append('fields', {})
|
||||
field_1.fieldname = 'some_fieldname_1'
|
||||
field_1.fieldtype = 'Data'
|
||||
|
|
@ -314,7 +295,7 @@ class TestDocType(unittest.TestCase):
|
|||
self.assertRaises(HiddenAndMandatoryWithoutDefaultError, doc.insert)
|
||||
|
||||
def test_field_can_not_be_indexed_validation(self):
|
||||
doc = self.new_doctype('Test index')
|
||||
doc = new_doctype('Test index')
|
||||
field_1 = doc.append('fields', {})
|
||||
field_1.fieldname = 'some_fieldname_1'
|
||||
field_1.fieldtype = 'Long Text'
|
||||
|
|
@ -327,14 +308,14 @@ class TestDocType(unittest.TestCase):
|
|||
from frappe.desk.form.linked_with import get_submitted_linked_docs, cancel_all_linked_docs
|
||||
|
||||
#create doctype
|
||||
link_doc = self.new_doctype('Test Linked Doctype')
|
||||
link_doc = new_doctype('Test Linked Doctype')
|
||||
link_doc.is_submittable = 1
|
||||
for data in link_doc.get('permissions'):
|
||||
data.submit = 1
|
||||
data.cancel = 1
|
||||
link_doc.insert()
|
||||
|
||||
doc = self.new_doctype('Test Doctype')
|
||||
doc = new_doctype('Test Doctype')
|
||||
doc.is_submittable = 1
|
||||
field_2 = doc.append('fields', {})
|
||||
field_2.label = 'Test Linked Doctype'
|
||||
|
|
@ -377,12 +358,12 @@ class TestDocType(unittest.TestCase):
|
|||
doc.delete()
|
||||
frappe.db.commit()
|
||||
|
||||
def test_ignore_cancelation_of_linked_doctype_during_cancell(self):
|
||||
def test_ignore_cancelation_of_linked_doctype_during_cancel(self):
|
||||
import json
|
||||
from frappe.desk.form.linked_with import get_submitted_linked_docs, cancel_all_linked_docs
|
||||
|
||||
#create linked doctype
|
||||
link_doc = self.new_doctype('Test Linked Doctype 1')
|
||||
link_doc = new_doctype('Test Linked Doctype 1')
|
||||
link_doc.is_submittable = 1
|
||||
for data in link_doc.get('permissions'):
|
||||
data.submit = 1
|
||||
|
|
@ -390,7 +371,7 @@ class TestDocType(unittest.TestCase):
|
|||
link_doc.insert()
|
||||
|
||||
#create first parent doctype
|
||||
test_doc_1 = self.new_doctype('Test Doctype 1')
|
||||
test_doc_1 = new_doctype('Test Doctype 1')
|
||||
test_doc_1.is_submittable = 1
|
||||
|
||||
field_2 = test_doc_1.append('fields', {})
|
||||
|
|
@ -405,7 +386,7 @@ class TestDocType(unittest.TestCase):
|
|||
test_doc_1.insert()
|
||||
|
||||
#crete second parent doctype
|
||||
doc = self.new_doctype('Test Doctype 2')
|
||||
doc = new_doctype('Test Doctype 2')
|
||||
doc.is_submittable = 1
|
||||
|
||||
field_2 = doc.append('fields', {})
|
||||
|
|
@ -469,3 +450,28 @@ class TestDocType(unittest.TestCase):
|
|||
doc.delete()
|
||||
test_doc_1.delete()
|
||||
frappe.db.commit()
|
||||
|
||||
def new_doctype(name, unique=0, depends_on='', fields=None):
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "DocType",
|
||||
"module": "Core",
|
||||
"custom": 1,
|
||||
"fields": [{
|
||||
"label": "Some Field",
|
||||
"fieldname": "some_fieldname",
|
||||
"fieldtype": "Data",
|
||||
"unique": unique,
|
||||
"depends_on": depends_on,
|
||||
}],
|
||||
"permissions": [{
|
||||
"role": "System Manager",
|
||||
"read": 1,
|
||||
}],
|
||||
"name": name
|
||||
})
|
||||
|
||||
if fields:
|
||||
for f in fields:
|
||||
doc.append('fields', f)
|
||||
|
||||
return doc
|
||||
|
|
@ -94,19 +94,19 @@ frappe.ui.form.on("Customize Form", {
|
|||
|
||||
frm.add_custom_button(__('Go to {0} List', [frm.doc.doc_type]), function() {
|
||||
frappe.set_route('List', frm.doc.doc_type);
|
||||
});
|
||||
}, __('Actions'));
|
||||
|
||||
frm.add_custom_button(__('Refresh Form'), function() {
|
||||
frm.add_custom_button(__('Reload'), function() {
|
||||
frm.script_manager.trigger("doc_type");
|
||||
}, "fa fa-refresh", "btn-default");
|
||||
}, __('Actions'));
|
||||
|
||||
frm.add_custom_button(__('Reset to defaults'), function() {
|
||||
frappe.customize_form.confirm(__('Remove all customizations?'), frm);
|
||||
}, "fa fa-eraser", "btn-default");
|
||||
}, __('Actions'));
|
||||
|
||||
frm.add_custom_button(__('Set Permissions'), function() {
|
||||
frappe.set_route('permission-manager', frm.doc.doc_type);
|
||||
}, "fa fa-lock", "btn-default");
|
||||
}, __('Actions'));
|
||||
|
||||
if (frappe.boot.developer_mode) {
|
||||
frm.add_custom_button(__('Export Customizations'), function() {
|
||||
|
|
@ -131,7 +131,7 @@ frappe.ui.form.on("Customize Form", {
|
|||
});
|
||||
},
|
||||
__("Select Module"));
|
||||
});
|
||||
}, __('Actions'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ class CustomizeForm(Document):
|
|||
'''
|
||||
Check if the doctype is allowed to be customized.
|
||||
'''
|
||||
#if self.doc_type in core_doctypes_list:
|
||||
# frappe.throw(_("Core DocTypes cannot be customized."))
|
||||
if self.doc_type in core_doctypes_list:
|
||||
frappe.throw(_("Core DocTypes cannot be customized."))
|
||||
|
||||
if meta.issingle:
|
||||
frappe.throw(_("Single DocTypes cannot be customized."))
|
||||
|
|
@ -71,7 +71,7 @@ class CustomizeForm(Document):
|
|||
|
||||
for fieldname in ('links', 'actions'):
|
||||
for d in meta.get(fieldname):
|
||||
self.append(fieldname, d)
|
||||
d1 = self.append(fieldname, d)
|
||||
|
||||
def create_auto_repeat_custom_field_if_requried(self, meta):
|
||||
if self.allow_auto_repeat:
|
||||
|
|
@ -242,35 +242,52 @@ class CustomizeForm(Document):
|
|||
('DocType Action', 'actions', doctype_action_properties)
|
||||
):
|
||||
has_custom = False
|
||||
for d in self.get(fieldname):
|
||||
if not (d.custom and frappe.db.exists(doctype, d.name)):
|
||||
items = []
|
||||
for i, d in enumerate(self.get(fieldname) or []):
|
||||
d.idx = i
|
||||
if frappe.db.exists(doctype, d.name) and not d.custom:
|
||||
# check property and apply property setter
|
||||
original = frappe.get_doc(doctype, d.name)
|
||||
for prop, prop_type in field_map.items():
|
||||
if d.get(prop) != original.get(prop):
|
||||
self.make_property_setter(prop, d.get(prop), prop_type,
|
||||
apply_on=doctype, row_name=d.name)
|
||||
items.append(d.name)
|
||||
else:
|
||||
# add or update custom object
|
||||
if frappe.db.exists(doctype, d.name):
|
||||
doc = frappe.get_doc(doctype, d.name)
|
||||
else:
|
||||
doc = frappe.new_doc(doctype)
|
||||
doc.parent = self.doc_type
|
||||
doc.parenttype = '_Custom' # dummy parenttype since its mandatory
|
||||
doc.custom = 1
|
||||
|
||||
for prop, prop_type in field_map.items():
|
||||
doc.set(prop, d.get(prop))
|
||||
|
||||
doc.save(ignore_permissions=True)
|
||||
# custom - just insert/update
|
||||
d.parent = self.doc_type
|
||||
d.custom = 1
|
||||
d.save(ignore_permissions=True)
|
||||
has_custom = True
|
||||
items.append(d.name)
|
||||
|
||||
if has_custom:
|
||||
# save the order of the actions and links
|
||||
self.make_property_setter('{}_order'.format(fieldname),
|
||||
json.dumps([d.name for d in self.get(fieldname)]), 'Small Text')
|
||||
self.update_order_property_setter(has_custom, fieldname)
|
||||
self.clear_removed_items(doctype, items)
|
||||
|
||||
def update_order_property_setter(self, has_custom, fieldname):
|
||||
'''
|
||||
We need to maintain the order of the link/actions if the user has shuffled them.
|
||||
So we create a new property (ex `links_order`) to keep a list of items.
|
||||
'''
|
||||
property_name = '{}_order'.format(fieldname)
|
||||
if has_custom:
|
||||
# save the order of the actions and links
|
||||
self.make_property_setter(property_name,
|
||||
json.dumps([d.name for d in self.get(fieldname)]), 'Small Text')
|
||||
else:
|
||||
frappe.db.delete('Property Setter', dict(property=property_name,
|
||||
doc_type=self.doc_type))
|
||||
|
||||
|
||||
def clear_removed_items(self, doctype, items):
|
||||
'''
|
||||
Clear rows that do not appear in `items`. These have been removed by the user.
|
||||
'''
|
||||
if items:
|
||||
frappe.db.delete(doctype, dict(parent=self.doc_type, custom=1,
|
||||
name=('not in', items)))
|
||||
else:
|
||||
frappe.db.delete(doctype, dict(parent=self.doc_type, custom=1))
|
||||
|
||||
def update_custom_fields(self):
|
||||
for i, df in enumerate(self.get("fields")):
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from __future__ import unicode_literals
|
|||
import frappe, unittest, json
|
||||
from frappe.test_runner import make_test_records_for_doctype
|
||||
from frappe.core.doctype.doctype.doctype import InvalidFieldNameError
|
||||
from frappe.core.doctype.doctype.test_doctype import new_doctype
|
||||
|
||||
test_dependencies = ["Custom Field", "Property Setter"]
|
||||
class TestCustomizeForm(unittest.TestCase):
|
||||
|
|
@ -191,3 +192,73 @@ class TestCustomizeForm(unittest.TestCase):
|
|||
# core doctype is invalid, hence no attributes are set
|
||||
self.assertEquals(d.get("fields"), [])
|
||||
self.assertEquals(e.get("fields"), [])
|
||||
|
||||
def test_custom_link(self):
|
||||
try:
|
||||
# create a dummy doctype linked to Event
|
||||
testdt_name = 'Test Link for Event'
|
||||
testdt = new_doctype(testdt_name, fields=[
|
||||
dict(fieldtype='Link', fieldname='event', options='Event')
|
||||
]).insert()
|
||||
|
||||
testdt_name1 = 'Test Link for Event 1'
|
||||
testdt1 = new_doctype(testdt_name1, fields=[
|
||||
dict(fieldtype='Link', fieldname='event', options='Event')
|
||||
]).insert()
|
||||
|
||||
# add a custom link
|
||||
d = self.get_customize_form("Event")
|
||||
|
||||
d.append('links', dict(link_doctype=testdt_name, link_fieldname='event', group='Tests'))
|
||||
d.append('links', dict(link_doctype=testdt_name1, link_fieldname='event', group='Tests'))
|
||||
d.run_method("save_customization")
|
||||
|
||||
frappe.clear_cache()
|
||||
event = frappe.get_meta('Event')
|
||||
|
||||
# check links exist
|
||||
self.assertTrue([d.name for d in event.links if d.link_doctype == testdt_name])
|
||||
self.assertTrue([d.name for d in event.links if d.link_doctype == testdt_name1])
|
||||
|
||||
# check order
|
||||
order = json.loads(event.links_order)
|
||||
self.assertListEqual(order, [d.name for d in event.links])
|
||||
|
||||
# remove the link
|
||||
d = self.get_customize_form("Event")
|
||||
d.links = []
|
||||
d.run_method("save_customization")
|
||||
|
||||
frappe.clear_cache()
|
||||
event = frappe.get_meta('Event')
|
||||
self.assertFalse([d.name for d in (event.links or []) if d.link_doctype == testdt_name])
|
||||
finally:
|
||||
testdt.delete()
|
||||
testdt1.delete()
|
||||
|
||||
def test_custom_action(self):
|
||||
test_route = '#List/DocType'
|
||||
|
||||
# create a dummy action (route)
|
||||
d = self.get_customize_form("Event")
|
||||
d.append('actions', dict(label='Test Action', action_type='Route', action=test_route))
|
||||
d.run_method("save_customization")
|
||||
|
||||
frappe.clear_cache()
|
||||
event = frappe.get_meta('Event')
|
||||
|
||||
# check if added to meta
|
||||
action = [d for d in event.actions if d.label=='Test Action']
|
||||
self.assertEqual(len(action), 1)
|
||||
self.assertEqual(action[0].action, test_route)
|
||||
|
||||
# clear the action
|
||||
d = self.get_customize_form("Event")
|
||||
d.actions = []
|
||||
d.run_method("save_customization")
|
||||
|
||||
frappe.clear_cache()
|
||||
event = frappe.get_meta('Event')
|
||||
|
||||
action = [d for d in event.actions if d.label=='Test Action']
|
||||
self.assertEqual(len(action), 0)
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ class Database(object):
|
|||
value = filters.get(key)
|
||||
values[key] = value
|
||||
if isinstance(value, (list, tuple)):
|
||||
# value is a tuble like ("!=", 0)
|
||||
# value is a tuple like ("!=", 0)
|
||||
_operator = value[0]
|
||||
values[key] = value[1]
|
||||
if isinstance(value[1], (tuple, list)):
|
||||
|
|
@ -959,13 +959,13 @@ class Database(object):
|
|||
query = sql_dict.get(current_dialect)
|
||||
return self.sql(query, values, **kwargs)
|
||||
|
||||
def delete(self, doctype, conditions):
|
||||
def delete(self, doctype, conditions, debug=False):
|
||||
if conditions:
|
||||
conditions, values = self.build_conditions(conditions)
|
||||
return self.sql("DELETE FROM `tab{doctype}` where {conditions}".format(
|
||||
doctype=doctype,
|
||||
conditions=conditions
|
||||
), values)
|
||||
), values, debug=debug)
|
||||
else:
|
||||
frappe.throw(_('No conditions provided'))
|
||||
|
||||
|
|
|
|||
|
|
@ -343,8 +343,8 @@ class Meta(Document):
|
|||
|
||||
def add_custom_links_and_actions(self):
|
||||
for doctype, fieldname in (('DocType Link', 'links'), ('DocType Action', 'actions')):
|
||||
for d in frappe.get_all(doctype, dict(parent=self.name, custom=1)):
|
||||
self.get(fieldname).append(d)
|
||||
for d in frappe.get_all(doctype, fields='*', filters=dict(parent=self.name, custom=1)):
|
||||
self.append(fieldname, d)
|
||||
|
||||
# set the fields in order if specified
|
||||
# order is saved as `links_order`
|
||||
|
|
@ -353,14 +353,15 @@ class Meta(Document):
|
|||
name_map = {d.name:d for d in self.get(fieldname)}
|
||||
new_list = []
|
||||
for name in order:
|
||||
new_list.append(name_map[name])
|
||||
name_map[name].__added = True
|
||||
if name in name_map:
|
||||
new_list.append(name_map[name])
|
||||
|
||||
# add the missing items that have not be added
|
||||
# maybe these items were added to the standard product
|
||||
# after the customization was done
|
||||
for d in self.get(fieldname):
|
||||
if not d.__added: new_list.append(d)
|
||||
if not d in new_list:
|
||||
new_list.append(d)
|
||||
|
||||
self.set(fieldname, new_list)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue