diff --git a/.travis.yml b/.travis.yml index 53ad56a948..ffada0286f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ addons: - test_site_producer mariadb: 10.3 postgresql: 9.5 - chrome: stable + firefox: latest services: - xvfb diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index e9fa7217a8..13c6ca812f 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -578,7 +578,7 @@ def run_ui_tests(context, app, headless=False): frappe.commands.popen("yarn add cypress@^6 cypress-file-upload@^5 --no-lockfile") # run for headless mode - run_or_open = 'run --browser chrome --record --key 4a48f41c-11b3-425b-aa88-c58048fa69eb' if headless else 'open' + run_or_open = 'run --browser firefox --record --key 4a48f41c-11b3-425b-aa88-c58048fa69eb' if headless else 'open' command = '{site_env} {password_env} {cypress} {run_or_open}' formatted_command = command.format(site_env=site_env, password_env=password_env, cypress=cypress_path, run_or_open=run_or_open) diff --git a/frappe/core/doctype/data_import/importer.py b/frappe/core/doctype/data_import/importer.py index dde3dfaee9..388d9389f2 100644 --- a/frappe/core/doctype/data_import/importer.py +++ b/frappe/core/doctype/data_import/importer.py @@ -472,32 +472,6 @@ class ImportFile: doc = parent_doc - if self.import_type == INSERT: - # check if there is atleast one row for mandatory table fields - meta = frappe.get_meta(self.doctype) - mandatory_table_fields = [ - df - for df in meta.fields - if df.fieldtype in table_fieldtypes - and df.reqd - and len(doc.get(df.fieldname, [])) == 0 - ] - if len(mandatory_table_fields) == 1: - self.warnings.append( - { - "row": first_row.row_number, - "message": _("There should be atleast one row for {0} table").format( - frappe.bold(mandatory_table_fields[0].label) - ), - } - ) - elif mandatory_table_fields: - fields_string = ", ".join([df.label for df in mandatory_table_fields]) - message = _("There should be atleast one row for the following tables: {0}").format( - fields_string - ) - self.warnings.append({"row": first_row.row_number, "message": message}) - return doc, rows, data[len(rows) :] def get_warnings(self): @@ -626,7 +600,6 @@ class Row: new_doc.update(doc) doc = new_doc - self.check_mandatory_fields(doctype, doc, table_df) return doc def validate_value(self, value, col): @@ -727,66 +700,6 @@ class Row: pass return value - def check_mandatory_fields(self, doctype, doc, table_df=None): - """If import type is Insert: - Check for mandatory fields (except table fields) in doc - if import type is Update: - Check for name field or autoname field in doc - """ - meta = frappe.get_meta(doctype) - if self.import_type == UPDATE: - if meta.istable: - # when updating records with table rows, - # there are two scenarios: - # 1. if row 'name' is provided in the template - # the table row will be updated - # 2. if row 'name' is not provided - # then a new row will be added - # so we dont need to check for mandatory - return - - # for update, only ID (name) field is mandatory - id_field = get_id_field(doctype) - if doc.get(id_field.fieldname) in INVALID_VALUES: - self.warnings.append( - { - "row": self.row_number, - "message": _("{0} is a mandatory field").format(id_field.label), - } - ) - return - - fields = [ - df - for df in meta.fields - if df.fieldtype not in table_fieldtypes - and df.reqd - and doc.get(df.fieldname) in INVALID_VALUES - ] - - if not fields: - return - - def get_field_label(df): - return "{0}{1}".format(df.label, " ({})".format(table_df.label) if table_df else "") - - if len(fields) == 1: - field_label = get_field_label(fields[0]) - self.warnings.append( - { - "row": self.row_number, - "message": _("{0} is a mandatory field").format(frappe.bold(field_label)), - } - ) - else: - fields_string = ", ".join([frappe.bold(get_field_label(df)) for df in fields]) - self.warnings.append( - { - "row": self.row_number, - "message": _("{0} are mandatory fields").format(fields_string), - } - ) - def get_values(self, indexes): return [self.data[i] for i in indexes] diff --git a/frappe/core/doctype/data_import/test_importer.py b/frappe/core/doctype/data_import/test_importer.py index b083b9eaaa..f76d4504a4 100644 --- a/frappe/core/doctype/data_import/test_importer.py +++ b/frappe/core/doctype/data_import/test_importer.py @@ -13,7 +13,7 @@ doctype_name = 'DocType for Import' class TestImporter(unittest.TestCase): @classmethod def setUpClass(cls): - create_doctype_if_not_exists(doctype_name) + create_doctype_if_not_exists(doctype_name,) def test_data_import_from_file(self): import_file = get_import_file('sample_import_file') @@ -59,18 +59,18 @@ class TestImporter(unittest.TestCase): def test_data_import_without_mandatory_values(self): import_file = get_import_file('sample_import_file_without_mandatory') data_import = self.get_importer(doctype_name, import_file) + frappe.local.message_log = [] data_import.start_import() data_import.reload() - warnings = frappe.parse_json(data_import.template_warnings) + import_log = frappe.parse_json(data_import.import_log) + self.assertEqual(import_log[0]['row_indexes'], [2,3]) + expected_error = "Error: Child 1 of DocType for Import Row #1: Value missing for: Child Title" + self.assertEqual(frappe.parse_json(import_log[0]['messages'][0])['message'], expected_error) + expected_error = "Error: Child 1 of DocType for Import Row #2: Value missing for: Child Title" + self.assertEqual(frappe.parse_json(import_log[0]['messages'][1])['message'], expected_error) - self.assertEqual(warnings[0]['row'], 2) - self.assertEqual(warnings[0]['message'], "Child Title (Table Field 1) is a mandatory field") - - self.assertEqual(warnings[1]['row'], 3) - self.assertEqual(warnings[1]['message'], "Child Title (Table Field 1 Again) is a mandatory field") - - self.assertEqual(warnings[2]['row'], 4) - self.assertEqual(warnings[2]['message'], "Title is a mandatory field") + self.assertEqual(import_log[1]['row_indexes'], [4]) + self.assertEqual(frappe.parse_json(import_log[1]['messages'][0])['message'], "Title is required") def test_data_import_update(self): existing_doc = frappe.get_doc( @@ -104,6 +104,8 @@ class TestImporter(unittest.TestCase): data_import.reference_doctype = doctype data_import.import_file = import_file.file_url data_import.insert() + # Commit so that the first import failure does not rollback the Data Import insert. + frappe.db.commit() return data_import diff --git a/frappe/public/js/frappe/model/model.js b/frappe/public/js/frappe/model/model.js index 9ec7b0e931..7167fc3982 100644 --- a/frappe/public/js/frappe/model/model.js +++ b/frappe/public/js/frappe/model/model.js @@ -621,6 +621,7 @@ $.extend(frappe.model, { r.message || args.new_name]); if(locals[doctype] && locals[doctype][docname]) delete locals[doctype][docname]; + this.frm.reload_doc(); d.hide(); if(callback) callback(r.message); diff --git a/frappe/public/js/frappe/ui/theme_switcher.js b/frappe/public/js/frappe/ui/theme_switcher.js index 31baf697f0..317198bca5 100644 --- a/frappe/public/js/frappe/ui/theme_switcher.js +++ b/frappe/public/js/frappe/ui/theme_switcher.js @@ -14,7 +14,7 @@ frappe.ui.ThemeSwitcher = class ThemeSwitcher { } refresh() { - this.current_theme = document.body.dataset.theme; + this.current_theme = document.documentElement.getAttribute("data-theme") || "light"; this.fetch_themes().then(() => { this.render(); }); @@ -45,7 +45,6 @@ frappe.ui.ThemeSwitcher = class ThemeSwitcher { }); } - get_preview_html(theme) { const preview = $(`