diff --git a/e2e/helper/addInitInvalidFileInputObject.js b/e2e/helper/addInitInvalidFileInputObject.js new file mode 100644 index 00000000000..2da20e44e7b --- /dev/null +++ b/e2e/helper/addInitInvalidFileInputObject.js @@ -0,0 +1,57 @@ +class DomainObjectViewProvider { + constructor(openmct) { + this.key = 'doViewProvider'; + this.name = 'Domain Object View Provider'; + this.openmct = openmct; + } + + canView(domainObject) { + return domainObject.type === 'imageFileInput' || domainObject.type === 'jsonFileInput'; + } + + view(domainObject, objectPath) { + let content; + + return { + show: function (element) { + const body = domainObject.selectFile.body; + const type = typeof body; + + content = document.createElement('div'); + content.id = 'file-input-type'; + content.textContent = JSON.stringify(type); + element.appendChild(content); + }, + destroy: function (element) { + element.removeChild(content); + content = undefined; + } + }; + } +} + +document.addEventListener('DOMContentLoaded', () => { + const openmct = window.openmct; + + openmct.types.addType('jsonFileInput', { + key: 'jsonFileInput', + name: 'JSON File Input Object', + creatable: true, + form: [ + { + name: 'Upload File', + key: 'selectFile', + control: 'file-input', + required: true, + text: 'Select File...', + type: 'application/json', + validate: function (data, fail) { + return fail('Test error json'); + }, + property: ['selectFile'] + } + ] + }); + + openmct.objectViews.addProvider(new DomainObjectViewProvider(openmct)); +}); diff --git a/e2e/tests/functional/forms.e2e.spec.js b/e2e/tests/functional/forms.e2e.spec.js index bda12a48944..fcbd6cc75a8 100644 --- a/e2e/tests/functional/forms.e2e.spec.js +++ b/e2e/tests/functional/forms.e2e.spec.js @@ -104,6 +104,33 @@ test.describe('Form File Input Behavior', () => { }); }); +test.describe('Form File Invalid Input Behavior', () => { + test.beforeEach(async ({ page }) => { + await page.addInitScript({ + path: fileURLToPath(new URL('../../helper/addInitInvalidFileInputObject.js', import.meta.url)) + }); + }); + + test('An invalid file will display an error', async ({ page }) => { + await page.goto('./', { waitUntil: 'domcontentloaded' }); + + await page.getByRole('button', { name: 'Create' }).click(); + await page.getByRole('menuitem', { name: 'JSON File Input Object' }).click(); + + await page.setInputFiles('#fileElem', jsonFilePath); + + await expect(page.getByLabel('Save')).toBeDisabled(); + + await expect( + page + .locator('.form-error', { + hasText: 'Test error json' + }) + .first() + ).toBeVisible(); + }); +}); + test.describe('Persistence operations @addInit', () => { // add non persistable root item test.beforeEach(async ({ page }) => { diff --git a/src/api/forms/components/FormRow.vue b/src/api/forms/components/FormRow.vue index ce1c88e403d..a1ccb510c78 100644 --- a/src/api/forms/components/FormRow.vue +++ b/src/api/forms/components/FormRow.vue @@ -26,7 +26,10 @@ {{ row.name }}
-
+
+
+
{{ errorMessage }}
+
@@ -54,6 +57,7 @@ export default { emits: ['on-change'], data() { return { + errorMessage: null, formControl: this.openmct.forms.getFormControl(this.row.control), valid: undefined, visited: false @@ -105,6 +109,7 @@ export default { this.$emit('on-change', data); }, validateRow(data) { + this.errorMessage = null; let valid = true; if (this.row.required) { valid = data.value !== undefined && data.value !== null && data.value !== ''; @@ -122,7 +127,10 @@ export default { const validate = data.model.validate; if (valid && validate) { - valid = validate(data); + valid = validate(data, (errorMessage = null) => { + this.errorMessage = errorMessage; + return false; + }); } return Boolean(valid); diff --git a/src/plugins/importFromJSONAction/ImportFromJSONAction.js b/src/plugins/importFromJSONAction/ImportFromJSONAction.js index 77fa1dfda91..5beec80b4d0 100644 --- a/src/plugins/importFromJSONAction/ImportFromJSONAction.js +++ b/src/plugins/importFromJSONAction/ImportFromJSONAction.js @@ -383,7 +383,7 @@ class ImportFromJSONAction { * @param {Object} data * @returns {boolean} */ - _validateJSON(data) { + _validateJSON(data, fail) { const value = data.value; const objectTree = value && value.body; let json; @@ -399,7 +399,7 @@ class ImportFromJSONAction { } if (!success) { - this.openmct.notifications.error( + fail( 'Invalid File: The selected file was either invalid JSON or was not formatted properly for import into Open MCT.' ); }