",
'name': "Odoo Studio: %s customization" % (self.testView.name)
})
self.start_tour("/web?debug=tests", 'web_studio_test_edit_with_xml_editor', login="admin", timeout=200)
self.assertEqual(studioView.arch, "
")
def test_enter_x2many_edition_and_add_field(self):
doesNotHaveGroup = self.env["res.groups"].create({
"name": "studio does not have"
})
doesNotHaveGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_doesnothavegroup",
"model": "res.groups",
"module": "web_studio",
"res_id": doesNotHaveGroup.id,
})
userView = self.env["ir.ui.view"].create({
"name": "simple user",
"model": "res.users",
"type": "form",
"arch": '''
'''.format(doesnothavegroup=doesNotHaveGroupXmlId.complete_name)
})
userViewXmlId = self.env["ir.model.data"].create({
"name": "studio_test_user_view",
"model": "ir.ui.view",
"module": "web_studio",
"res_id": userView.id,
})
self.testView.arch = '''
''' % userViewXmlId.complete_name
studioView = _get_studio_view(self.testView)
self.assertFalse(studioView.exists())
self.start_tour("/web?debug=tests", 'web_studio_enter_x2many_edition_and_add_field', login="admin", timeout=200)
studioView = _get_studio_view(self.testView)
assertViewArchEqual(self, studioView.arch, """
""".format(doesnothavegroup=doesNotHaveGroupXmlId.complete_name))
def test_enter_x2many_auto_inlined_subview(self):
userView = self.env["ir.ui.view"].create({
"name": "simple user",
"model": "res.users",
"type": "tree",
"arch": '''
'''
})
userViewXmlId = self.env["ir.model.data"].create({
"name": "studio_test_user_view",
"model": "ir.ui.view",
"module": "web_studio",
"res_id": userView.id,
})
self.testView.arch = '''
''' % userViewXmlId.complete_name
studioView = _get_studio_view(self.testView)
self.assertFalse(studioView.exists())
self.start_tour("/web?debug=tests", 'web_studio_enter_x2many_auto_inlined_subview', login="admin", timeout=200)
studioView = _get_studio_view(self.testView)
assertViewArchEqual(self, studioView.arch, """
""")
def test_enter_x2many_auto_inlined_subview_with_multiple_field_matching(self):
user_view = self.env["ir.ui.view"].create({
"name": "simple user",
"model": "res.users",
"type": "tree",
"arch": '''
'''
})
user_view_xml_id = self.env["ir.model.data"].create({
"name": "studio_test_user_view",
"model": "ir.ui.view",
"module": "web_studio",
"res_id": user_view.id,
})
self.testView.arch = '''
''' % (user_view_xml_id.complete_name, user_view_xml_id.complete_name)
studio_view = _get_studio_view(self.testView)
self.assertFalse(studio_view.exists())
self.start_tour("/web?debug=tests", 'web_studio_enter_x2many_auto_inlined_subview_with_multiple_field_matching',
login="admin", timeout=200)
studio_view = _get_studio_view(self.testView)
assertViewArchEqual(self, studio_view.arch, """
""")
def test_field_with_group(self):
operations = []
def edit_view_mocked(*args, **kwargs):
operations.extend(kwargs["operations"] if "operations" in kwargs else args[3])
watch_edit_view(self, edit_view_mocked)
doesNotHaveGroup = self.env["res.groups"].create({
"name": "studio does not have"
})
doesNotHaveGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_doesnothavegroup",
"model": "res.groups",
"module": "web_studio",
"res_id": doesNotHaveGroup.id,
})
self.testView.write({
"type": "tree",
"arch": '''
'''.format(doesnothavegroup=doesNotHaveGroupXmlId.complete_name)
})
self.testAction.write({
"view_ids": [Command.clear(), Command.create({"view_id": self.testView.id, "view_mode": "tree"})]
})
self.start_tour("/web?debug=tests", 'web_studio_field_with_group', login="admin", timeout=200)
self.assertEqual(len(operations), 1)
self.assertEqual(operations[0]["target"]["xpath_info"], [{'tag': 'tree', 'indice': 1}, {'tag': 'field', 'indice': 3}])
studioView = _get_studio_view(self.testView)
assertViewArchEqual(self, studioView.arch, """
""")
def test_studio_no_fetch_subview(self):
doesNotHaveGroup = self.env["res.groups"].create({
"name": "studio does not have"
})
doesNotHaveGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_doesnothavegroup",
"model": "res.groups",
"module": "web_studio",
"res_id": doesNotHaveGroup.id,
})
def create_new_field_mocked(*args, **kwargs):
# For this test we need to patch groups from the phone field. Unfortunately it seems
# that the patch is erased each time we create a new field so we have to patch after.
self.patch(type(self.env["res.partner"]).phone, "groups", doesNotHaveGroupXmlId.complete_name)
watch_create_new_field(self, create_new_field_mocked)
self.patch(type(self.env["res.partner"]).phone, "groups", doesNotHaveGroupXmlId.complete_name)
self.testView.write({
"arch": '''
'''
})
self.start_tour("/web", 'web_studio_no_fetch_subview', login="admin")
def test_elements_with_groups_form(self):
operations = []
def edit_view_mocked(*args, **kwargs):
operations.extend(kwargs["operations"] if "operations" in kwargs else args[3])
watch_edit_view(self, edit_view_mocked)
doesNotHaveGroup = self.env["res.groups"].create({
"name": "studio does not have"
})
doesNotHaveGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_doesnothavegroup",
"model": "res.groups",
"module": "web_studio",
"res_id": doesNotHaveGroup.id,
})
hasGroup = self.env["res.groups"].create({
"name": "studio has group",
"users": [Command.link(2)]
})
hasGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_hasgroup",
"model": "res.groups",
"module": "web_studio",
"res_id": hasGroup.id,
})
self.patch(type(self.env["res.partner"]).function, "groups", doesNotHaveGroupXmlId.complete_name)
self.testView.write({
"arch": '''
'''.format(doesnothavegroup=doesNotHaveGroupXmlId.complete_name, hasgroup=hasGroupXmlId.complete_name)
})
self.start_tour("/web", 'web_studio_elements_with_groups_form', login="admin", timeout=600000)
self.assertEqual(len(operations), 1)
self.assertEqual(operations[0]["target"]["xpath_info"], [{'indice': 1, 'tag': 'form'}, {'indice': 1, 'tag': 'group'}, {'indice': 3, 'tag': 'field'}])
studioView = _get_studio_view(self.testView)
assertViewArchEqual(self, studioView.arch, """
""")
def test_element_group_in_sidebar(self):
group = self.env["res.groups"].create({
"name": "Test Group",
"users": [Command.link(2)]
})
groupXmlId = self.env["ir.model.data"].create({
"name": "test_group",
"model": "res.groups",
"module": "web_studio",
"res_id": group.id,
})
self.testView.write({
"arch": '''
'''.format(group=groupXmlId.complete_name)
})
self.start_tour("/web?debug=tests", 'test_element_group_in_sidebar', login="admin", timeout=600000)
def test_create_one2many_lines_then_edit_name(self):
self.testView.arch = '''
'''
custom_fields_before_studio = self.env["ir.model.fields"].search([
("state", "=", "manual"),
])
self.start_tour("/web?debug=tests", 'web_studio_test_create_one2many_lines_then_edit_name', login="admin", timeout=30000)
custom_fields = self.env["ir.model.fields"].search_read([
("state", "=", "manual"),
("id", "not in", custom_fields_before_studio.ids),
], fields=["name", "ttype", "field_description"])
self.maxDiff = None
self.assertCountEqual(
[{key: val for key, val in field.items() if key != 'id'} for field in custom_fields],
[
{"name": "x_studio_new_name", 'ttype': 'one2many', 'field_description': 'new name'},
{"name": "x_name", 'ttype': 'char', 'field_description': 'Description'},
{"name": "x_res_partner_id", 'ttype': 'many2one', 'field_description': 'X Res Partner'},
{"name": "x_studio_sequence", 'ttype': 'integer', 'field_description': 'Sequence'},
]
)
def test_address_view_id_no_edit(self):
self.testView.write({
"arch": '''
'''
})
self.env.company.country_id.address_view_id = self.env.ref('base.view_partner_address_form')
self.start_tour("/web?debug=tests", 'web_studio_test_address_view_id_no_edit', login="admin", timeout=200)
studio_view = _get_studio_view(self.testView)
assertViewArchEqual(self, studio_view.arch, """
True
""")
def test_custom_selection_field_edit_values(self):
self.testView.arch = '''
'''
self.start_tour("/web?debug=tests", 'web_studio_custom_selection_field_edit_values', login="admin", timeout=200)
selection_field = self.env["ir.model.fields"].search(
[
("state", "=", "manual"),
("model", "=", "res.partner"),
("ttype", "=", "selection")
],
limit=1
)
self.assertEqual(selection_field.selection_ids.mapped("name"), ["some value", "another value"])
def test_create_new_model_from_existing_view(self):
self.testView.write({
"model": "res.users",
"type": "kanban",
"arch": '''
'''
})
self.testAction.view_ids.view_mode = "kanban"
self.start_tour("/web?debug=tests", 'web_studio_test_create_new_model_from_existing_view', login="admin",
timeout=200)
def test_create_model_with_clickable_stages(self):
self.start_tour("/web?debug=tests", 'web_studio_test_create_model_with_clickable_stages', login="admin", timeout=200)
def test_enter_x2many_edition_with_multiple_subviews(self):
doesNotHaveGroup = self.env["res.groups"].create({
"name": "studio does not have"
})
doesNotHaveGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_doesnothavegroup",
"model": "res.groups",
"module": "web_studio",
"res_id": doesNotHaveGroup.id,
})
hasGroup = self.env["res.groups"].create({
"name": "studio has group",
"users": [Command.link(2)]
})
hasGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_hasgroup",
"model": "res.groups",
"module": "web_studio",
"res_id": hasGroup.id,
})
self.testView.arch = '''
'''.format(doesnothavegroup=doesNotHaveGroupXmlId.complete_name, hasgroup=hasGroupXmlId.complete_name)
self.start_tour("/web?debug=tests", 'web_studio_test_enter_x2many_edition_with_multiple_subviews',
login="admin", timeout=200)
def test_enter_x2many_edition_with_multiple_subviews_correct_xpath(self):
operations = []
def edit_view_mocked(*args, **kwargs):
operations.extend(kwargs["operations"] if "operations" in kwargs else args[3])
watch_edit_view(self, edit_view_mocked)
doesNotHaveGroup = self.env["res.groups"].create({
"name": "studio does not have"
})
doesNotHaveGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_doesnothavegroup",
"model": "res.groups",
"module": "web_studio",
"res_id": doesNotHaveGroup.id,
})
hasGroup = self.env["res.groups"].create({
"name": "studio has group",
"users": [Command.link(2)]
})
hasGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_hasgroup",
"model": "res.groups",
"module": "web_studio",
"res_id": hasGroup.id,
})
self.testView.arch = '''
'''.format(doesnothavegroup=doesNotHaveGroupXmlId.complete_name, hasgroup=hasGroupXmlId.complete_name)
self.start_tour("/web?debug=tests", 'web_studio_test_enter_x2many_edition_with_multiple_subviews_correct_xpath',
login="admin", timeout=200)
studioView = _get_studio_view(self.testView)
assertViewArchEqual(self, studioView.arch, """
""")
self.assertEqual(len(operations), 1)
self.assertDictEqual(operations[0], {
'type': 'add',
'target': {
'tag': 'field',
'attrs': {
'name': 'name'
},
'xpath_info': [
{
'tag': 'tree',
'indice': 2
},
{
'tag': 'field',
'indice': 1
},
],
'subview_xpath': "/form[1]/field[2]/tree[2]",
},
'position': 'before',
'node': {
'tag': 'field',
'attrs': {
'name': 'active',
'optional': 'show'
}
}
})
def test_studio_arch_has_measure_field_ids(self):
view = self.env["ir.ui.view"].create({
"name": "simple view",
"model": "res.partner",
"type": "pivot",
"arch": '''
'''
})
studio_view = self.env[view.model].with_context(studio=True).get_view(view.id, view.type)
field_id = self.env['ir.model.fields'].search([('model', '=', view.model), ('name', 'in', ['display_name'])]).ids[0]
assertViewArchEqual(self, studio_view["arch"], '''
'''.format(field_id=field_id))
@mute_logger('odoo.addons.base.models.ir_ui_view')
def test_postprocess_empty_groups_attribute(self):
view = self.env["ir.ui.view"].create({
"name": "simple view",
"model": "res.partner",
"type": "form",
"arch": '''
'''
})
studio_view = self.env[view.model].with_context(studio=True).get_view(view.id, view.type)
assertViewArchEqual(self, studio_view["arch"], '''
''')
def test_field_with_groups_in_tree_node_has_groups_too(self):
# The field has a group in python in which the user is
# The node has also a group in which the user is not
hasGroup = self.env["res.groups"].create({
"name": "studio has group",
"users": [Command.link(self.env.user.id)]
})
hasGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_hasgroup",
"model": "res.groups",
"module": "web_studio",
"res_id": hasGroup.id,
})
doesNotHaveGroup = self.env["res.groups"].create({
"name": "studio does not have"
})
doesNotHaveGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_doesnothavegroup",
"model": "res.groups",
"module": "web_studio",
"res_id": doesNotHaveGroup.id,
})
self.patch(type(self.env["res.partner"]).title, "groups", hasGroupXmlId.complete_name)
view = self.env["ir.ui.view"].create({
"name": "simple view",
"model": "res.partner",
"type": "tree",
"arch": '''
'''.format(doesnothavegroup=doesNotHaveGroupXmlId.complete_name)
})
arch = self.env[view.model].with_context(studio=True).get_view(view.id, view.type)["arch"]
studio_groups = json.dumps([{
"id": doesNotHaveGroup.id,
"name": doesNotHaveGroup.name,
"display_name": doesNotHaveGroup.display_name,
"forbid": False,
}])
xml_temp = E.field(name="title", column_invisible="True", groups=doesNotHaveGroupXmlId.complete_name, studio_groups=studio_groups)
expected = '''
{xml_stringified}
'''.format(xml_stringified=etree.tostring(xml_temp).decode("utf-8"))
assertViewArchEqual(self, arch, expected)
def test_set_tree_column_conditional_invisibility(self):
self.testViewList = self.env["ir.ui.view"].create({
"name": "simple partner",
"model": "res.partner",
"type": "tree",
"arch": '''
'''
})
self.testAction.write({
"view_ids": [
Command.clear(),
Command.create({"view_id": self.testViewList.id, "view_mode": "tree"}),
]
})
self.start_tour("/web?debug=tests", 'web_studio_set_tree_node_conditional_invisibility', login="admin", timeout=200)
arch = self.env[self.testViewList.model].with_context(studio=True).get_view(self.testViewList.id, self.testViewList.type)["arch"]
expected = '''
'''.format(title_modifiers="display_name == "Robert"")
assertViewArchEqual(self, arch, expected)
def test_studio_view_is_last(self):
# The studio view created should have, in all cases, a priority greater than all views
# that are part of the inheritance
self.testView.arch = '''
'''
self.env["ir.ui.view"].create({
"name": "simple view inherit",
"inherit_id": self.testView.id,
"mode": "extension",
"priority": 123,
"model": "res.partner",
"type": "form",
"arch": '''
'''
})
self.start_tour("/web?debug=tests", 'web_studio_test_studio_view_is_last', login="admin", timeout=200)
studioView = _get_studio_view(self.testView)
self.assertEqual(studioView.priority, 1230)
self.maxDiff = None
assertViewArchEqual(self, studioView["arch"], '''
''')
def test_edit_form_subview_attributes(self):
self.testView.arch = '''
'''
self.start_tour("/web?debug=tests", 'web_studio_test_edit_form_subview_attributes', login="admin", timeout=200)
studioView = _get_studio_view(self.testView)
assertViewArchEqual(self, studioView.arch, """
false
""")
def test_x2many_two_levels_edition(self):
self.testView.arch = '''
'''
self.start_tour("/web?debug=tests", 'web_studio_x2many_two_levels_edition', login="admin", timeout=200)
studioView = _get_studio_view(self.testView)
assertViewArchEqual(self, studioView.arch, '''
''')
def test_field_group_studio_no_fetch(self):
doesNotHaveGroup = self.env["res.groups"].create({
"name": "studio does not have"
})
doesNotHaveGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_doesnothavegroup",
"model": "res.groups",
"module": "web_studio",
"res_id": doesNotHaveGroup.id,
})
self.patch(type(self.env["res.partner"]).function, "groups", doesNotHaveGroupXmlId.complete_name)
self.testViewForm = self.env["ir.ui.view"].create({
"name": "simple partner",
"model": "res.partner",
"type": "form",
"arch": '''
'''
})
self.testViewList = self.env["ir.ui.view"].create({
"name": "simple partner",
"model": "res.partner",
"type": "tree",
"arch": '''
'''
})
self.testViewKanban = self.env["ir.ui.view"].create({
"name": "simple partner",
"model": "res.partner",
"type": "kanban",
"arch": '''
'''
})
self.testAction.write({
"view_ids": [
Command.clear(),
Command.create({"view_id": self.testViewForm.id, "view_mode": "form"}),
Command.create({"view_id": self.testViewList.id, "view_mode": "tree"}),
Command.create({"view_id": self.testViewKanban.id, "view_mode": "kanban"}),
]
})
self.start_tour("/web?debug=tests", 'web_studio_field_group_studio_no_fetch', login="admin", timeout=200)
def test_monetary_create(self):
self.create_empty_app()
self.newView.arch = '''
'''
self.start_tour("/web?debug=tests", 'web_studio_monetary_create', login="admin")
# There is a new currency and there is a new monetary
fields = self.env[self.newModel.model]._fields
currency_name_list = list(filter(lambda key: fields[key]._description_type == 'many2one' and fields[key]._description_relation == 'res.currency', fields.keys()))
monetary_name_list = list(filter(lambda key: fields[key].type == 'monetary', fields.keys()))
self.assertEqual(len(currency_name_list), 1)
self.assertEqual(len(monetary_name_list), 1)
# The studio arch contains the new monetary and the new currency
studioView = _get_studio_view(self.newView)
assertViewArchEqual(self, studioView.arch, f"""
""")
def test_monetary_change_currency_name(self):
self.create_empty_app()
currency = self.env["ir.model.fields"].create({
"name": "x_studio_currency_test",
"model": "x_test_model",
"model_id": self.newModel.id,
"ttype": "many2one",
"relation": "res.currency",
})
self.env["ir.model.fields"].create({
"name": "x_studio_monetary_test",
"model": "x_test_model",
"model_id": self.newModel.id,
"ttype": "monetary",
"currency_field": "x_studio_currency_test",
})
self.newView.arch = '''
'''
self.start_tour("/web?debug=tests", 'web_studio_monetary_change_currency_name', login="admin")
self.assertEqual(currency.field_description, "NewCurrency")
def test_related_monetary_creation(self):
res_partner_model_id = self.env["ir.model"].search([("model", "=", "res.partner")]).id
self.create_empty_app()
self.env["ir.model.fields"].create({
"name": "x_studio_currency_test",
"model": "res.partner",
"model_id": res_partner_model_id,
"ttype": "many2one",
"relation": "res.currency",
})
self.env["ir.model.fields"].create({
"name": "x_studio_monetary_test",
"model": "res.partner",
"model_id": res_partner_model_id,
"ttype": "monetary",
"currency_field": "x_studio_currency_test",
})
self.testView.arch = '''
'''
self.env["ir.model.fields"].create({
"name": "x_test",
"model": "x_test_model",
"model_id": self.newModel.id,
"ttype": "many2one",
"relation": "res.partner",
})
self.newView.arch = '''
'''
self.start_tour("/web?debug=tests", 'web_studio_related_monetary_creation', login="admin")
# There is only one currency and there is a new monetary
fields = self.env["x_test_model"]._fields
currency_name_list = list(filter(lambda key: fields[key]._description_type == 'many2one' and fields[key]._description_relation == 'res.currency', fields.keys()))
monetary_name_list = list(filter(lambda key: fields[key].type == 'monetary', fields.keys()))
self.assertEqual(len(currency_name_list), 1)
self.assertEqual(len(monetary_name_list), 1)
# The monetary has been created and is a related field
self.assertEqual(self.env['x_test_model']._fields[monetary_name_list[0]].related, "x_test.x_studio_monetary_test")
# A currency has been created because there was none in the model/view
self.assertEqual(currency_name_list[0], 'x_studio_currency_id')
def test_monetary_change_currency_field(self):
self.create_empty_app()
self.env["ir.model.fields"].create({
"name": "x_studio_currency_test",
"model": "x_test_model",
"model_id": self.newModel.id,
"ttype": "many2one",
"relation": "res.currency",
})
self.env["ir.model.fields"].create({
"name": "x_studio_currency_test2",
"model": "x_test_model",
"model_id": self.newModel.id,
"ttype": "many2one",
"relation": "res.currency",
})
monetary = self.env["ir.model.fields"].create({
"name": "x_studio_monetary_test",
"model": "x_test_model",
"model_id": self.newModel.id,
"ttype": "monetary",
"currency_field": "x_studio_currency_test",
})
self.newView.arch = '''
'''
self.start_tour("/web?debug=tests", 'web_studio_monetary_change_currency_field', login="admin")
# The currency_field in the monetary field changed
self.assertEqual(monetary.currency_field, 'x_studio_currency_test2')
def test_monetary_change_currency_not_in_view(self):
self.create_empty_app()
self.env["ir.model.fields"].create({
"name": "x_studio_currency_test",
"model": "x_test_model",
"model_id": self.newModel.id,
"ttype": "many2one",
"relation": "res.currency",
})
self.env["ir.model.fields"].create({
"name": "x_studio_currency_test2",
"model": "x_test_model",
"model_id": self.newModel.id,
"ttype": "many2one",
"relation": "res.currency",
})
monetary = self.env["ir.model.fields"].create({
"name": "x_studio_monetary_test",
"model": "x_test_model",
"model_id": self.newModel.id,
"ttype": "monetary",
"currency_field": "x_studio_currency_test",
})
self.newView.arch = '''
'''
self.start_tour("/web?debug=tests", 'web_studio_monetary_change_currency_not_in_view', login="admin")
# The currency_field in the monetary field changed
self.assertEqual(monetary.currency_field, 'x_studio_currency_test2')
studioView = _get_studio_view(self.newView)
assertViewArchEqual(self, studioView.arch, """
""")
def test_monetary_add_existing_monetary(self):
self.create_empty_app()
self.env["ir.model.fields"].create({
"name": "x_studio_currency_test",
"model": "x_test_model",
"model_id": self.newModel.id,
"ttype": "many2one",
"relation": "res.currency",
})
self.env["ir.model.fields"].create({
"name": "x_studio_monetary_test",
"model": "x_test_model",
"model_id": self.newModel.id,
"ttype": "monetary",
"currency_field": "x_studio_currency_test",
})
self.newView.arch = '''
'''
self.start_tour("/web?debug=tests", 'web_studio_monetary_add_existing_monetary', login="admin")
# The studio arch contains the monetary and the associated currency
studioView = _get_studio_view(self.newView)
assertViewArchEqual(self, studioView.arch, """
""")
def test_monetary_create_monetary_with_existing_currency(self):
self.create_empty_app()
self.env["ir.model.fields"].create({
"name": "x_studio_currency_test",
"model": "x_test_model",
"model_id": self.newModel.id,
"ttype": "many2one",
"relation": "res.currency",
})
self.newView.arch = '''
'''
self.start_tour("/web?debug=tests", 'web_studio_monetary_create_monetary_with_existing_currency', login="admin")
# There is only one currency and there is a new monetary
fields = self.env[self.newModel.model]._fields
currency_name_list = list(filter(lambda key: fields[key]._description_type == 'many2one' and fields[key]._description_relation == 'res.currency', fields.keys()))
monetary_name_list = list(filter(lambda key: fields[key].type == 'monetary', fields.keys()))
self.assertEqual(len(currency_name_list), 1)
self.assertEqual(len(monetary_name_list), 1)
# The studio arch contains the new monetary but no currency as it exist in the original arch
studioView = _get_studio_view(self.newView)
assertViewArchEqual(self, studioView.arch, f"""
""")
def test_move_similar_field(self):
self.testView.arch = '''
'''
self.start_tour("/web?debug=tests", 'web_studio_test_move_similar_field', login="admin", timeout=400)
studioView = _get_studio_view(self.testView)
assertViewArchEqual(self, studioView.arch, '''
''')
def create_user_view(self):
self.testView.write({
"name": "simple user",
"model": "res.users",
"arch": '''
'''
})
self.testAction.write({
"name": "simple user",
"res_model": "res.users",
})
self.testActionXmlId.name = "studio_test_user_action"
self.testMenu.name = "Studio Test User"
self.testMenuXmlId.name = "studio_test_user_menu"
def test_related_binary_field_with_filename(self):
self.create_user_view()
partner_field = self.env["ir.model.fields"].create({
"field_description": "New File",
"name": "x_new_file",
"ttype": "binary",
"model": "res.partner",
"model_id": self.env["ir.model"]._get('res.partner').id,
"state": "manual",
})
self.env["ir.model.fields"].create({
"field_description": "New File filename",
"name": "x_new_file_filename",
"ttype": "char",
"model": "res.partner",
"model_id": self.env["ir.model"]._get('res.partner').id,
"state": "manual",
})
self.start_tour("/web?debug=tests", 'web_studio_test_related_file', login="admin", timeout=400)
studioView = _get_studio_view(self.testView)
binary_field = self.env["ir.model.fields"].search([('model', '=', 'res.users'), ('ttype', '=', 'binary'), ('name', 'like', 'x_studio_related')])
self.assertEqual(len(binary_field), 1)
self.assertEqual(binary_field.related_field_id, partner_field)
assertViewArchEqual(self, studioView.arch,
'''
'''.format(binary_field=binary_field))
def test_nested_related_binary_field_with_filename(self):
self.create_user_view()
self.env["ir.model.fields"].create({
"field_description": "New File",
"name": "x_new_file",
"ttype": "binary",
"model": "res.partner.category",
"model_id": self.env["ir.model"]._get('res.partner.category').id,
"state": "manual",
})
self.env["ir.model.fields"].create({
"field_description": "New File filename",
"name": "x_new_file_filename",
"ttype": "char",
"model": "res.partner.category",
"model_id": self.env["ir.model"]._get('res.partner.category').id,
"state": "manual",
})
partner_field = self.env["ir.model.fields"].create({
"field_description": "New File",
"name": "x_new_related_file",
"ttype": "binary",
"model": "res.partner",
"model_id": self.env["ir.model"]._get('res.partner').id,
"state": "manual",
"related": "category_id.x_new_file"
})
self.env["ir.model.fields"].create({
"field_description": "New File filename",
"name": "x_new_related_file_filename",
"ttype": "char",
"model": "res.partner",
"model_id": self.env["ir.model"]._get('res.partner').id,
"state": "manual",
"related": "category_id.x_new_file_filename"
})
self.start_tour("/web?debug=tests", 'web_studio_test_related_file', login="admin", timeout=400)
studioView = _get_studio_view(self.testView)
binary_field = self.env["ir.model.fields"].search([('model', '=', 'res.users'), ('ttype', '=', 'binary'), ('name', 'like', 'x_studio_related')])
self.assertEqual(len(binary_field), 1)
self.assertEqual(binary_field.related_field_id, partner_field)
assertViewArchEqual(self, studioView.arch,
'''
'''.format(binary_field=binary_field))
def test_related_binary_field_without_filename(self):
self.create_user_view()
partner_field = self.env["ir.model.fields"].create({
"field_description": "New File",
"name": "x_new_file",
"ttype": "binary",
"model": "res.partner",
"model_id": self.env["ir.model"]._get('res.partner').id,
"state": "manual",
})
self.start_tour("/web?debug=tests", 'web_studio_test_related_file', login="admin", timeout=400)
studioView = _get_studio_view(self.testView)
binary_field = self.env["ir.model.fields"].search([('model', '=', 'res.users'), ('ttype', '=', 'binary'), ('name', 'like', 'x_studio_related')])
self.assertEqual(len(binary_field), 1)
self.assertEqual(binary_field.related_field_id, partner_field)
assertViewArchEqual(self, studioView.arch,
'''
'''.format(binary_field=binary_field))
def test_undo_new_field(self):
self.testView.arch = '''
'''
self.start_tour("/web?debug=tests", "web_studio_test_undo_new_field", login="admin", timeout=200)
def test_change_lone_attr_modifier_form(self):
self.testView.arch = """
"""
self.start_tour("/web?debug=tests", "web_studio_test_change_lone_attr_modifier_form", login="admin")
studioView = _get_studio_view(self.testView)
assertViewArchEqual(self, studioView.arch, '''
False
''')
def test_drag_and_drop_boolean(self):
self.testView.arch = '''
'''
self.start_tour("/web?debug=tests", 'web_studio_boolean_field_drag_and_drop', login="admin", timeout=200)
studioView = _get_studio_view(self.testView)
boolean_field = self.env['ir.model.fields'].search([('name', 'like', 'x_studio_boolean')])[0]
assertViewArchEqual(self, studioView.arch, '''
'''.format(boolean_field=boolean_field))
def test_new_field_rename_description(self):
self.testView.arch = '''
'''
self.start_tour("/web", "web_studio_test_new_field_rename_description", login="admin")
new_field = self.env["ir.model.fields"]._get("res.partner", "x_studio_my_new_field")
self.assertEqual(new_field.field_description, "my new field")
studioView = _get_studio_view(self.testView)
self.assertXMLEqual(studioView.arch, """
""")
def test_edit_digits_option(self):
self.testView.arch = '''
'''
self.start_tour("/web?debug=tests", 'web_studio_test_edit_digits_option', login="admin", timeout=200)
studioView = _get_studio_view(self.testView)
assertViewArchEqual(self, studioView.arch, """
{"digits":[4,2]}
""")
def test_button_rainbow_effect(self):
self.testView.arch = """
Button """
self.start_tour("/web", "web_studio.test_button_rainbow_effect", login="admin")
studioView = _get_studio_view(self.testView)
attachment = self.env["ir.attachment"].search([("name", "=", "my_studio_image.png")])
self.assertXMLEqual(studioView.arch, """
{'img_url': '/web/content/%s'}
""" % attachment.id)
def test_context_write_cleaned(self):
view = self.env["ir.ui.view"].create({
"model": "res.users",
"type": "form",
"arch": """
"""
})
operations = [
{
"type": "add",
"target": {
"tag": "div",
"attrs": {
"class": "oe_button_box"
}
},
"position": "inside",
"node": {
"tag": "button",
"field": self.env["ir.model.fields"]._get("res.partner", "user_id").id,
"string": "Test studio new button",
"attrs": {
"class": "oe_stat_button",
"icon": "fa-diamond"
}
}
}
]
create_action = self.env.registry["ir.actions.actions"]._create
action_created = False
def mock_act_create(rec_set, *args, **kwargs):
nonlocal action_created
action_created = True
context = dict(rec_set.env.context)
del context["tz"]
self.assertEqual(context, {'lang': 'en_US', 'uid': 2, 'arbitrary_key': 'arbitrary', "studio": 1})
return create_action(rec_set, *args, **kwargs)
self.patch(self.env.registry["ir.actions.actions"], "_create", mock_act_create)
self.authenticate("admin", "admin")
with mute_logger("odoo.addons.base.models.ir_ui_view"):
response = self.url_open("/web_studio/edit_view",
headers={"Content-Type": "application/json"},
data=json.dumps({
"params": {
"view_id": view.id,
"studio_view_arch": "",
"model": "res.users",
"operations": operations,
"context": {
"default_type": "some_type",
"arbitrary_key": "arbitrary",
"studio": 1,
}
},
}))
action = self.env["ir.actions.act_window"].search([("res_model", "=", "res.partner")], order="create_date DESC", limit=1)
self.assertTrue(action_created, True)
self.assertEqual(action.type, "ir.actions.act_window")
self.assertEqual(action.name, "Test studio new button")
self.assertXMLEqual(response.json()["result"]["views"]["form"]["arch"], f"""
""")
def test_res_users_fake_fields(self):
user_fields = self.env["res.users"].fields_get()
assertable = [field["string"] for field in user_fields.values() if field["string"] in ("Administration", "Multi Companies")]
self.assertEqual(len(assertable), 2)
action = self.env.ref("base.action_res_users")
url = f"/web?debug=1#action=studio&mode=editor&_tab=views&_view_type=list&_action={action.id}"
self.start_tour(url, 'web_studio.test_res_users_fake_fields', login="admin")
def test_add_button_xml_id(self):
base_view = self.env["ir.ui.view"].create({
"name": "test_partner_simple",
"model": "res.partner",
"mode": "primary",
"type": "form",
"arch": """
"""
})
operations = [
{
"type": "add",
"target": {
"tag": "div",
"attrs": {
"class": "oe_button_box"
}
},
"view_id": base_view.id,
"position": "inside",
"node": {
"tag": "button",
"field": self.env["ir.model.fields"]._get("res.partner", "parent_id").id,
"string": "aa",
"attrs": {
"class": "oe_stat_button",
"icon": "fa-diamond"
}
}
}
]
with mute_logger("odoo.addons.base.models.ir_ui_view"):
self.authenticate("admin", "admin")
self.url_open("/web_studio/edit_view", data=json.dumps({
"params": {
"view_id": base_view.id,
"model": "res.partner",
"studio_view_arch": "
",
"operations": operations,
"context": {"studio": 1},
}
}), headers={"Content-Type": "application/json"})
action = self.env["ir.actions.act_window"].search([], limit=1, order="create_date DESC")
self.assertTrue(action.xml_id.startswith("studio_customization."))
form = base_view.get_combined_arch()
self.assertXMLEqual(form, f"""
""")
def test_reload_after_restoring_default_view(self):
self.start_tour("/web?debug=tests", 'web_studio_test_reload_after_restoring_default_view', login="admin")
def test_edit_reified_field(self):
# find some reified field name
reified_fname = next(
fname
for fname in self.env["res.users"].fields_get()
if fname.startswith(('in_group_', 'sel_groups_'))
)
self.testView.write({
"name": "simple user",
"model": "res.users",
"arch": '''
''' % reified_fname
})
self.testAction.res_model = "res.users"
self.start_tour("/web?debug=tests", 'web_studio_test_edit_reified_field', login="admin")
studioView = _get_studio_view(self.testView)
assertViewArchEqual(self, studioView.arch, """
new name
""" % reified_fname)
def test_approval_button_xml_id(self):
self.testView.arch = """
"""
self.start_tour("/web?debug=tests", "web_studio_test_approval_button_xml_id", login="admin")
tree = self.testView._get_combined_arch()
button = tree.xpath("//button")[0]
self.assertEqual(button.get("studio_approval"), "True")
approvals = self.env["studio.approval.rule"].get_approval_spec("res.partner", False, "base.action_model_data", False)
self.assertEqual(len(approvals["rules"]), 1)
rule = self.env["studio.approval.rule"].browse(approvals["rules"][0]["id"])
# actions have different record set, but the api of ir.actions.actions
# guarantees that the ids match across the two models.
self.assertEqual(rule.action_id.id, self.env.ref("base.action_model_data").id)
def test_negated_groups(self):
doesNotHaveGroup = self.env["res.groups"].create({
"name": "studio does not have"
})
doesNotHaveGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_doesnothavegroup",
"model": "res.groups",
"module": "web_studio",
"res_id": doesNotHaveGroup.id,
})
hasGroup = self.env["res.groups"].create({
"name": "studio has group",
})
hasGroupXmlId = self.env["ir.model.data"].create({
"name": "studio_test_hasgroup",
"model": "res.groups",
"module": "web_studio",
"res_id": hasGroup.id,
})
self.testView.arch = f"""
"""
self.start_tour("/web?debug=tests", "web_studio_test_negated_groups", login="admin")
studio_view = _get_studio_view(self.testView)
assertViewArchEqual(self, studio_view.arch, """
web_studio.studio_test_doesnothavegroup,!base.group_erp_manager
""")
def test_use_action_domain(self):
self.env["res.partner"].search([['employee', '=', True]]).action_archive()
self.env["res.partner"].create({
"name": "Michel",
"employee": True,
})
self.env["res.partner"].create({
"name": "Paul",
"employee": False,
})
self.testAction.domain = "[['employee', '=', True]]"
self.testView.write({
"type": "tree",
"arch": '''
'''
})
self.testAction.write({
"view_ids": [Command.clear(), Command.create({"view_id": self.testView.id, "view_mode": "tree"})]
})
self.start_tour("/web?debug=tests", "web_studio_test_use_action_domain", login="admin")
def test_drag_before_sheet(self):
self.testView.arch = """
"""
self.start_tour("/web?debug=tests", "web_studio_test_drag_before_sheet", login="admin")
studio_view = _get_studio_view(self.testView)
[html_field] = self.env['ir.model.fields'].search([('name', '=like', 'x_studio_html_field_%')], limit=1)
assertViewArchEqual(self, studio_view.arch, '''
'''.format(html_field=html_field))