0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-13 22:41:32 -05:00

Merge pull request #5687 from kevinansfield/fix-tags-validation

Add inline error handling and tests for tag creation/editing
This commit is contained in:
Hannah Wolfe 2015-08-21 21:31:40 +01:00
commit 55c07338d9
4 changed files with 138 additions and 26 deletions

View file

@ -40,11 +40,6 @@ export default Ember.Controller.extend(PaginationMixin, SettingsMenuMixin, {
}
}),
showErrors: function (errors) {
errors = Ember.isArray(errors) ? errors : [errors];
this.get('notifications').showErrors(errors);
},
saveActiveTagProperty: function (propKey, newValue) {
var activeTag = this.get('activeTag'),
currentValue = activeTag.get(propKey),
@ -59,10 +54,10 @@ export default Ember.Controller.extend(PaginationMixin, SettingsMenuMixin, {
activeTag.set(propKey, newValue);
this.get('notifications').closeNotifications();
activeTag.save().catch(function (errors) {
self.showErrors(errors);
activeTag.save().catch(function (error) {
if (error) {
self.notifications.showAPIError(error);
}
});
},

View file

@ -1,6 +1,6 @@
<div>
{{#gh-tabs-manager selected="showSubview" class="settings-menu-container"}}
<div class="{{if isViewingSubview 'settings-menu-pane-out-left' 'settings-menu-pane-in'}} settings-menu settings-menu-pane">
<div class="{{if isViewingSubview 'settings-menu-pane-out-left' 'settings-menu-pane-in'}} settings-menu settings-menu-pane tag-settings-pane">
<div class="settings-menu-header">
<h4>Tag Settings</h4>
<button class="close icon-x settings-menu-header-action" {{action "closeMenus"}}>
@ -10,25 +10,26 @@
<div class="settings-menu-content">
{{gh-uploader uploaded="setCoverImage" canceled="clearCoverImage" description="Add tag image" image=activeTag.image initUploader="setUploaderReference" tagName="section"}}
<form>
<div class="form-group">
<label>Name</label>
{{gh-input class="gh-input" type="text" value=activeTagNameScratch focus-out="saveActiveTagName"}}
</div>
{{#gh-form-group errors=activeTag.errors property="name"}}
<label for="tag-name">Name</label>
{{gh-input id="tag-name" name="name" type="text" value=activeTagNameScratch focus-out="saveActiveTagName"}}
{{gh-error-message errors=activeTag.errors property="name"}}
{{/gh-form-group}}
<div class="form-group">
<label>URL</label>
{{gh-input class="gh-input" type="text" value=activeTagSlugScratch focus-out="saveActiveTagSlug"}}
<label for="tag-url">URL</label>
{{gh-input id="tag-url" name="url" type="text" value=activeTagSlugScratch focus-out="saveActiveTagSlug"}}
{{gh-url-preview prefix="tag" slug=activeTagSlugScratch tagName="p" classNames="description"}}
</div>
<div class="form-group">
<label>Description</label>
{{gh-textarea class="gh-input" value=activeTagDescriptionScratch focus-out="saveActiveTagDescription"}}
<label for="tag-description">Description</label>
{{gh-textarea id="tag-description" name="description" value=activeTagDescriptionScratch focus-out="saveActiveTagDescription"}}
</div>
<ul class="nav-list nav-list-block">
{{#gh-tab tagName="li" classNames="nav-list-item"}}
<button type="button">
<button type="button" class="meta-data-button">
<b>Meta Data</b>
<span>Extra content for SEO and social media.</span>
</button>
@ -43,7 +44,7 @@
</div>
</div>{{! .settings-menu-pane }}
<div class="{{if isViewingSubview 'settings-menu-pane-in' 'settings-menu-pane-out-right'}} settings-menu settings-menu-pane">
<div class="{{if isViewingSubview 'settings-menu-pane-in' 'settings-menu-pane-out-right'}} settings-menu settings-menu-pane tag-meta-settings-pane">
{{#gh-tab-pane}}
<div class="settings-menu-header subview">
<button {{action "closeSubview"}} class="back icon-arrow-left settings-menu-header-action"><span class="hidden">Back</span></button>
@ -53,17 +54,19 @@
<div class="settings-menu-content">
<form>
<div class="form-group">
{{#gh-form-group errors=activeTag.errors property="meta_title"}}
<label for="meta-title">Meta Title</label>
{{gh-input class="gh-input" type="text" value=activeTagMetaTitleScratch focus-out="saveActiveTagMetaTitle"}}
{{gh-input id="meta-title" name="meta_title" type="text" value=activeTagMetaTitleScratch focus-out="saveActiveTagMetaTitle"}}
{{gh-error-message errors=activeTag.errors property="meta_title"}}
<p>Recommended: <b>70</b> characters. Youve used {{gh-count-down-characters activeTagMetaTitleScratch 70}}</p>
</div>
{{/gh-form-group}}
<div class="form-group">
{{#gh-form-group errors=activeTag.errors property="meta_description"}}
<label for="meta-description">Meta Description</label>
{{gh-textarea class="gh-input" value=activeTagMetaDescriptionScratch focus-out="saveActiveTagMetaDescription"}}
{{gh-textarea id="meta-description" name="meta_description" value=activeTagMetaDescriptionScratch focus-out="saveActiveTagMetaDescription"}}
{{gh-error-message errors=activeTag.errors property="meta_description"}}
<p>Recommended: <b>156</b> characters. Youve used {{gh-count-down-characters activeTagMetaDescriptionScratch 156}}</p>
</div>
{{/gh-form-group}}
<div class="form-group">
<label>Search Engine Result Preview</label>

View file

@ -89,6 +89,10 @@ screens = {
url: 'ghost/settings/general',
selector: '.gh-nav-settings-general.active'
},
'settings.tags': {
url: 'ghost/settings/tags',
selector: '.gh-nav-settings-tags.active'
},
team: {
url: 'ghost/team',
linkSelector: '.gh-nav-main-users',

View file

@ -0,0 +1,110 @@
// # Settings Test
// Test the various tabs on the settings page
/*globals CasperTest, casper */
CasperTest.begin('Tags screen is correct', 6, function suite(test) {
casper.thenOpenAndWaitForPageLoad('settings.tags', function testTitleAndUrl() {
test.assertTitle('Settings - Tags - Test Blog', 'Ghost admin has incorrect title');
test.assertUrlMatch(/ghost\/settings\/tags\/$/, 'Landed on the correct URL');
});
casper.then(function tagsScreenHasContent() {
test.assertExists('.settings-tags .settings-tag', 'Has a tag');
test.assertSelectorHasText('.settings-tag .tag-title', 'Getting Started', 'Tag title is displayed');
test.assertSelectorHasText('.settings-tag .label', '/getting-started', 'Tag slug is displayed');
test.assertSelectorHasText('.settings-tag .tags-count', '1', 'Number of posts using tag is displayed');
});
});
CasperTest.begin('Tag creation', 14, function suite(test) {
casper.thenOpenAndWaitForPageLoad('settings.tags');
casper.thenClick('.view-actions .btn-green');
casper.waitForOpaque('.tag-settings-pane', function onSuccess() {
test.assert(true, 'tag settings menu is visible after clicking New Tag button');
});
casper.then(function enterName() {
casper.sendKeys('#tag-name', 'Test Tag', {keepFocus: true});
});
casper.thenClick('#tag-description');
casper.waitForResource(/\/tags\//, function onSuccess() {
test.assert(true, 'Losing focus on the name field triggered a save request');
}, function doneWaiting() {
test.fail('Name field did not trigger a save request on blur');
});
casper.waitForText('/test-tag').then(function verifyUIUpdates() {
test.assertField('url', 'test-tag');
test.assertSelectorHasText('.ghost-url-preview', '127.0.0.1:2369/tag/test-tag');
test.assertSelectorHasText('.settings-tags .tag-title', 'Test Tag');
test.assertSelectorHasText('.settings-tags .label', '/test-tag');
test.assertSelectorHasText('.settings-tags .tags-count', '0');
});
casper.then(function testNameValidation() {
casper.fill('.tag-settings-pane form', {
name: ''
});
casper.waitForText('You must specify a name for the tag.', function onSuccess() {
test.assertExists('.form-group.error input[name="name"]');
test.assert(true, 'Error displayed for missing tag name');
}, function doneWaiting() {
test.fail('Error not displayed for missing tag name');
});
});
casper.thenClick('.meta-data-button');
casper.waitForOpaque('.tag-meta-settings-pane', function onSuccess() {
test.assert(true, 'tags meta settings menu is visible after clicking Meta Data button');
});
casper.then(function testMetaTitleValidation() {
casper.fill('.tag-meta-settings-pane form', {
meta_title: new Array(152).join('a')
});
casper.waitForText('Meta Title cannot be longer than 150 characters.', function onSuccess() {
test.assertExists('.form-group.error input[name="meta_title"]');
test.assert(true, 'Error displayed when meta title is too long');
}, function doneWaiting() {
test.fail('Error not displayed when meta title is too long');
});
});
casper.then(function testMetaDescriptionValidation() {
casper.fill('.tag-meta-settings-pane form', {
meta_description: new Array(202).join('a')
});
casper.waitForText('Meta Description cannot be longer than 200 characters.', function onSuccess() {
test.assertExists('.form-group.error textarea[name="meta_description"]');
test.assert(true, 'Error displayed when meta description is too long');
}, function doneWaiting() {
test.fail('Error not displayed when meta description is too long');
});
});
});
CasperTest.begin('Tag editing', 3, function suite(test) {
casper.thenOpenAndWaitForPageLoad('settings.tags');
casper.thenClick('.settings-tags .settings-tag .tag-edit-button');
casper.waitForOpaque('.tag-settings-pane', function onSuccess() {
test.assert(true, 'tag settings menu is visible after clicking tag');
});
casper.then(function testNameValidation() {
casper.fill('.tag-settings-pane form', {
name: ''
});
casper.waitForText('You must specify a name for the tag.', function onSuccess() {
test.assertExists('.form-group.error input[name="name"]');
test.assert(true, 'Error displayed for missing tag name');
}, function doneWaiting() {
test.fail('Error not displayed for missing tag name');
});
});
});