From 4d8a7313dce1256d6cfb41afd154e0d18791efe6 Mon Sep 17 00:00:00 2001 From: Bas Kamer Date: Mon, 3 Aug 2020 12:45:38 +0200 Subject: [PATCH 1/4] prevent array in array --- addon/components/bs-form/element.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/components/bs-form/element.js b/addon/components/bs-form/element.js index 675ce97..8ec2a80 100755 --- a/addon/components/bs-form/element.js +++ b/addon/components/bs-form/element.js @@ -7,8 +7,8 @@ export default class BsFormElementWithChangesetValidationsSupport extends BsForm @dependentKeyCompat get errors() { - let error = get(this, `model.error.${this.property}.validation`); - return error ? [error] : []; + let errors = get(this, `model.error.${this.property}.validation`); + return errors ? errors : []; } get hasValidator() { From 0bfc1b167ab25bfce2f820bc3c485ef61f12a88d Mon Sep 17 00:00:00 2001 From: Bas Kamer Date: Mon, 10 Aug 2020 16:14:08 +0200 Subject: [PATCH 2/4] handle more explicitly --- addon/components/bs-form/element.js | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/addon/components/bs-form/element.js b/addon/components/bs-form/element.js index 8ec2a80..d7c3339 100755 --- a/addon/components/bs-form/element.js +++ b/addon/components/bs-form/element.js @@ -1,14 +1,38 @@ import BsFormElement from 'ember-bootstrap/components/bs-form/element'; import { action, get } from '@ember/object'; import { dependentKeyCompat } from '@ember/object/compat'; +import { isNone, typeOf } from '@ember/utils'; export default class BsFormElementWithChangesetValidationsSupport extends BsFormElement { '__ember-bootstrap_subclass' = true; + // We convert + // + // `model.error.${this.property}.validation` which could be either a string or an array + // see https://github.com/validated-changeset/validated-changeset/#error + // + // into + // + // Ember Bootstrap expects errors property of FormElement to be an array of validation messages: + // see https://www.ember-bootstrap.com/api/classes/Components.FormElement.html#property_errors + // + // If the if the property is valid but no validation is present `model.error.[this.property] could also be undefined. @dependentKeyCompat get errors() { let errors = get(this, `model.error.${this.property}.validation`); - return errors ? errors : []; + + // no messages + if (isNone(errors)) { + return []; + } + + // a single messages + if (typeOf(errors) === 'string') { + return [errors]; + } + + // assume it's an array of messages + return errors; } get hasValidator() { From a41b3d476f4e2020e91a2a9e49cbe88daebecd45 Mon Sep 17 00:00:00 2001 From: Bas Kamer Date: Wed, 12 Aug 2020 16:27:38 +0200 Subject: [PATCH 3/4] adds tests for each case addressed in this PR --- .../components/bs-form-element-test.js | 76 ++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/tests/integration/components/bs-form-element-test.js b/tests/integration/components/bs-form-element-test.js index 9637a95..ef3a3d9 100755 --- a/tests/integration/components/bs-form-element-test.js +++ b/tests/integration/components/bs-form-element-test.js @@ -213,8 +213,80 @@ module('Integration | Component | bs form element', function(hooks) { assert.dom('input').doesNotHaveClass('is-invalid'); await triggerEvent('form', 'submit'); - assert.dom('input').doesNotHaveClass('is-valid'); - assert.dom('input').doesNotHaveClass('is-invalid'); + assert.dom('input') + .doesNotHaveClass('is-valid'); + assert.dom('input') + .doesNotHaveClass('is-invalid'); assert.verifySteps(['submit action has been called']); }); + + test('invalid-feedback is shown from single validation', async function (assert) { + let model = { + name: '', + }; + + this.set('model', model); + this.set('validation', { + name: validatePresence(true) + }); + + await render(hbs` + + + + `); + + await triggerEvent('form', 'submit'); + assert.dom('.invalid-feedback') + .hasText('Name can\'t be blank'); + }); + + test('invalid-feedback is shown in order from multiple validations', async function (assert) { + let model = { + name: '', + }; + + this.set('model', model); + this.set('validation', { + name: [ + validatePresence(true), + validateLength({ min: 4 }) + ] + }); + + await render(hbs` + + + + `); + + await triggerEvent('form', 'submit'); + assert.dom('.invalid-feedback') + .hasText('Name can\'t be blank'); + + await fillIn('input', 'R'); + await triggerEvent('form', 'submit'); + assert.dom('.invalid-feedback') + .hasText('Name is too short (minimum is 4 characters)'); + }); + + test('no feedback is shown for nonexistant validations', async function (assert) { + let model = { + name: '', + }; + + this.set('model', model); + this.set('validation', { + nombre: validatePresence(true) + }); + + await render(hbs` + + + + `); + + await triggerEvent('form', 'submit'); + assert.dom('.invalid-feedback').doesNotExist(); + }); }); From 1a457c8bbe79c6c70ae6fdeb4209e64ead2b90a9 Mon Sep 17 00:00:00 2001 From: Bas Kamer Date: Thu, 13 Aug 2020 11:19:54 +0200 Subject: [PATCH 4/4] test for @showMultipleErrors --- .../components/bs-form-element-test.js | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/tests/integration/components/bs-form-element-test.js b/tests/integration/components/bs-form-element-test.js index ef3a3d9..f859ba2 100755 --- a/tests/integration/components/bs-form-element-test.js +++ b/tests/integration/components/bs-form-element-test.js @@ -1,6 +1,6 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; -import { render, triggerEvent, fillIn, focus, blur } from '@ember/test-helpers'; +import { render, triggerEvent, fillIn, focus, blur, findAll } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import { validatePresence, @@ -270,6 +270,36 @@ module('Integration | Component | bs form element', function(hooks) { .hasText('Name is too short (minimum is 4 characters)'); }); + test('invalid-feedback is shown (multiple messages) in order from multiple validations', async function (assert) { + let model = { + name: '', + }; + + this.set('model', model); + this.set('validation', { + name: [ + validatePresence(true), + validateLength({ min: 4 }) + ] + }); + + await render(hbs` + + + + `); + + await triggerEvent('form', 'submit'); + + let feedbackElements = findAll('.invalid-feedback'); + let results = Array.from(feedbackElements, element => element.textContent.trim()) + let expected = ["Name can't be blank", "Name is too short (minimum is 4 characters)"]; + + expected.forEach((message) => { + assert.ok(results.includes(message)) + }) + }); + test('no feedback is shown for nonexistant validations', async function (assert) { let model = { name: '',