0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00

fix double-render issues with validation-state mixin

This commit is contained in:
Kevin Ansfield 2017-01-31 19:27:11 +00:00 committed by Austin Burdine
parent 719aed29cf
commit 295f2cce96
4 changed files with 68 additions and 38 deletions

View file

@ -1,7 +1,8 @@
import Mixin from 'ember-metal/mixin'; import Mixin from 'ember-metal/mixin';
import computed from 'ember-computed';
import {isEmpty} from 'ember-utils'; import {isEmpty} from 'ember-utils';
import {A as emberA} from 'ember-array/utils'; import {A as emberA} from 'ember-array/utils';
import observer from 'ember-metal/observer';
import run from 'ember-runloop';
export default Mixin.create({ export default Mixin.create({
@ -9,26 +10,36 @@ export default Mixin.create({
property: '', property: '',
hasValidated: emberA(), hasValidated: emberA(),
hasError: computed('errors.[]', 'property', 'hasValidated.[]', function () { hasError: false,
setHasError() {
let property = this.get('property'); let property = this.get('property');
let errors = this.get('errors'); let errors = this.get('errors');
let hasValidated = this.get('hasValidated'); let hasValidated = this.get('hasValidated');
// if we aren't looking at a specific property we always want an error class // if we aren't looking at a specific property we always want an error class
if (!property && !isEmpty(errors)) { if (!property && errors && !errors.get('isEmpty')) {
return true; this.set('hasError', true);
return;
} }
// If we haven't yet validated this field, there is no validation class needed // If we haven't yet validated this field, there is no validation class needed
if (!hasValidated || !hasValidated.includes(property)) { if (!hasValidated || !hasValidated.includes(property)) {
return false; this.set('hasError', false);
return;
} }
if (errors) { if (errors && !isEmpty(errors.errorsFor(property))) {
return errors.get(property); this.set('hasError', true);
return;
} }
return false; this.set('hasError', false);
}) },
hasErrorObserver: observer('errors.[]', 'property', 'hasValidated.[]', function () {
run.once(this, 'setHasError');
// this.setHasError();
}).on('init')
}); });

View file

@ -4,6 +4,7 @@ import {describe, it} from 'mocha';
import {setupComponentTest} from 'ember-mocha'; import {setupComponentTest} from 'ember-mocha';
import hbs from 'htmlbars-inline-precompile'; import hbs from 'htmlbars-inline-precompile';
import NavItem from 'ghost-admin/models/navigation-item'; import NavItem from 'ghost-admin/models/navigation-item';
import wait from 'ember-test-helpers/wait';
describe('Integration: Component: gh-navitem', function () { describe('Integration: Component: gh-navitem', function () {
setupComponentTest('gh-navitem', { setupComponentTest('gh-navitem', {
@ -100,10 +101,12 @@ describe('Integration: Component: gh-navitem', function () {
this.render(hbs`{{gh-navitem navItem=navItem baseUrl=baseUrl}}`); this.render(hbs`{{gh-navitem navItem=navItem baseUrl=baseUrl}}`);
let $item = this.$('.gh-blognav-item'); let $item = this.$('.gh-blognav-item');
expect($item.hasClass('gh-blognav-item--error')).to.be.true; return wait().then(() => {
expect($item.find('.gh-blognav-label').hasClass('error')).to.be.true; expect($item.hasClass('gh-blognav-item--error')).to.be.true;
expect($item.find('.gh-blognav-label .response').text().trim()).to.equal('You must specify a label'); expect($item.find('.gh-blognav-label').hasClass('error')).to.be.true;
expect($item.find('.gh-blognav-url').hasClass('error')).to.be.true; expect($item.find('.gh-blognav-label .response').text().trim()).to.equal('You must specify a label');
expect($item.find('.gh-blognav-url .response').text().trim()).to.equal('You must specify a URL or relative path'); expect($item.find('.gh-blognav-url').hasClass('error')).to.be.true;
expect($item.find('.gh-blognav-url .response').text().trim()).to.equal('You must specify a URL or relative path');
});
}); });
}); });

View file

@ -7,6 +7,7 @@ import Service from 'ember-service';
import EmberObject from 'ember-object'; import EmberObject from 'ember-object';
import run from 'ember-runloop'; import run from 'ember-runloop';
import DS from 'ember-data'; import DS from 'ember-data';
import wait from 'ember-test-helpers/wait';
const {Errors} = DS; const {Errors} = DS;
@ -195,24 +196,26 @@ describe('Integration: Component: gh-tag-settings-form', function () {
{{gh-tag-settings-form tag=tag setProperty=(action 'setProperty')}} {{gh-tag-settings-form tag=tag setProperty=(action 'setProperty')}}
`); `);
let nameFormGroup = this.$('input[name="name"]').closest('.form-group'); return wait().then(() => {
expect(nameFormGroup.hasClass('error'), 'name form group has error state').to.be.true; let nameFormGroup = this.$('input[name="name"]').closest('.form-group');
expect(nameFormGroup.find('.response').length, 'name form group has error message').to.equal(1); expect(nameFormGroup.hasClass('error'), 'name form group has error state').to.be.true;
expect(nameFormGroup.find('.response').length, 'name form group has error message').to.equal(1);
let slugFormGroup = this.$('input[name="slug"]').closest('.form-group'); let slugFormGroup = this.$('input[name="slug"]').closest('.form-group');
expect(slugFormGroup.hasClass('error'), 'slug form group has error state').to.be.true; expect(slugFormGroup.hasClass('error'), 'slug form group has error state').to.be.true;
expect(slugFormGroup.find('.response').length, 'slug form group has error message').to.equal(1); expect(slugFormGroup.find('.response').length, 'slug form group has error message').to.equal(1);
let descriptionFormGroup = this.$('textarea[name="description"]').closest('.form-group'); let descriptionFormGroup = this.$('textarea[name="description"]').closest('.form-group');
expect(descriptionFormGroup.hasClass('error'), 'description form group has error state').to.be.true; expect(descriptionFormGroup.hasClass('error'), 'description form group has error state').to.be.true;
let metaTitleFormGroup = this.$('input[name="metaTitle"]').closest('.form-group'); let metaTitleFormGroup = this.$('input[name="metaTitle"]').closest('.form-group');
expect(metaTitleFormGroup.hasClass('error'), 'metaTitle form group has error state').to.be.true; expect(metaTitleFormGroup.hasClass('error'), 'metaTitle form group has error state').to.be.true;
expect(metaTitleFormGroup.find('.response').length, 'metaTitle form group has error message').to.equal(1); expect(metaTitleFormGroup.find('.response').length, 'metaTitle form group has error message').to.equal(1);
let metaDescriptionFormGroup = this.$('textarea[name="metaDescription"]').closest('.form-group'); let metaDescriptionFormGroup = this.$('textarea[name="metaDescription"]').closest('.form-group');
expect(metaDescriptionFormGroup.hasClass('error'), 'metaDescription form group has error state').to.be.true; expect(metaDescriptionFormGroup.hasClass('error'), 'metaDescription form group has error state').to.be.true;
expect(metaDescriptionFormGroup.find('.response').length, 'metaDescription form group has error message').to.equal(1); expect(metaDescriptionFormGroup.find('.response').length, 'metaDescription form group has error message').to.equal(1);
});
}); });
it('displays char count for text fields', function () { it('displays char count for text fields', function () {

View file

@ -5,6 +5,7 @@ import {setupComponentTest} from 'ember-mocha';
import hbs from 'htmlbars-inline-precompile'; import hbs from 'htmlbars-inline-precompile';
import EmberObject from 'ember-object'; import EmberObject from 'ember-object';
import DS from 'ember-data'; import DS from 'ember-data';
import wait from 'ember-test-helpers/wait';
const {Errors} = DS; const {Errors} = DS;
@ -27,9 +28,12 @@ describe('Integration: Component: gh-validation-status-container', function () {
{{#gh-validation-status-container class="gh-test" property="name" errors=testObject.errors hasValidated=testObject.hasValidated}} {{#gh-validation-status-container class="gh-test" property="name" errors=testObject.errors hasValidated=testObject.hasValidated}}
{{/gh-validation-status-container}} {{/gh-validation-status-container}}
`); `);
expect(this.$('.gh-test')).to.have.length(1);
expect(this.$('.gh-test').hasClass('success')).to.be.false; return wait().then(() => {
expect(this.$('.gh-test').hasClass('error')).to.be.false; expect(this.$('.gh-test')).to.have.length(1);
expect(this.$('.gh-test').hasClass('success')).to.be.false;
expect(this.$('.gh-test').hasClass('error')).to.be.false;
});
}); });
it('has success class when valid', function () { it('has success class when valid', function () {
@ -39,9 +43,12 @@ describe('Integration: Component: gh-validation-status-container', function () {
{{#gh-validation-status-container class="gh-test" property="name" errors=testObject.errors hasValidated=testObject.hasValidated}} {{#gh-validation-status-container class="gh-test" property="name" errors=testObject.errors hasValidated=testObject.hasValidated}}
{{/gh-validation-status-container}} {{/gh-validation-status-container}}
`); `);
expect(this.$('.gh-test')).to.have.length(1);
expect(this.$('.gh-test').hasClass('success')).to.be.true; return wait().then(() => {
expect(this.$('.gh-test').hasClass('error')).to.be.false; expect(this.$('.gh-test')).to.have.length(1);
expect(this.$('.gh-test').hasClass('success')).to.be.true;
expect(this.$('.gh-test').hasClass('error')).to.be.false;
});
}); });
it('has error class when invalid', function () { it('has error class when invalid', function () {
@ -52,9 +59,12 @@ describe('Integration: Component: gh-validation-status-container', function () {
{{#gh-validation-status-container class="gh-test" property="name" errors=testObject.errors hasValidated=testObject.hasValidated}} {{#gh-validation-status-container class="gh-test" property="name" errors=testObject.errors hasValidated=testObject.hasValidated}}
{{/gh-validation-status-container}} {{/gh-validation-status-container}}
`); `);
expect(this.$('.gh-test')).to.have.length(1);
expect(this.$('.gh-test').hasClass('success')).to.be.false; return wait().then(() => {
expect(this.$('.gh-test').hasClass('error')).to.be.true; expect(this.$('.gh-test')).to.have.length(1);
expect(this.$('.gh-test').hasClass('success')).to.be.false;
expect(this.$('.gh-test').hasClass('error')).to.be.true;
});
}); });
it('still renders if hasValidated is undefined', function () { it('still renders if hasValidated is undefined', function () {
@ -64,6 +74,9 @@ describe('Integration: Component: gh-validation-status-container', function () {
{{#gh-validation-status-container class="gh-test" property="name" errors=testObject.errors hasValidated=testObject.hasValidated}} {{#gh-validation-status-container class="gh-test" property="name" errors=testObject.errors hasValidated=testObject.hasValidated}}
{{/gh-validation-status-container}} {{/gh-validation-status-container}}
`); `);
expect(this.$('.gh-test')).to.have.length(1);
return wait().then(() => {
expect(this.$('.gh-test')).to.have.length(1);
});
}); });
}); });