launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #04571
[Merge] lp:~rvb/launchpad/add-comment-bug-823777 into lp:launchpad
Raphaël Victor Badin has proposed merging lp:~rvb/launchpad/add-comment-bug-823777 into lp:launchpad with lp:~rvb/launchpad/blacklist-bug-796669 as a prerequisite.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #823777 in Launchpad itself: "The Javascript methods used to manage adding a comment on the expandable row of the diff pages should be refactored into a proper YUI widget."
https://bugs.launchpad.net/launchpad/+bug/823777
For more details, see:
https://code.launchpad.net/~rvb/launchpad/add-comment-bug-823777/+merge/71171
This branch refactors all the Javascript methods to add comment to a DSD on the diff pages. All that code is now encapsulated into a YUI Widget with tests.
= Tests =
lib/lp/registry/javascript/tests/test_distroseriesdifferences_details.html
= QA =
This branch should not add any new functionality but the it's worth checking that it's still possible to:
- blacklist a DSD (and add a comment)
- add a comment using the add comment slot
--
https://code.launchpad.net/~rvb/launchpad/add-comment-bug-823777/+merge/71171
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~rvb/launchpad/add-comment-bug-823777 into lp:launchpad.
=== modified file 'lib/lp/registry/javascript/distroseriesdifferences_details.js'
--- lib/lp/registry/javascript/distroseriesdifferences_details.js 2011-08-11 11:57:42 +0000
+++ lib/lp/registry/javascript/distroseriesdifferences_details.js 2011-08-11 11:57:42 +0000
@@ -18,13 +18,6 @@
namespace.io = Y.io;
-/*
- * XXX: rvb 2011-08-01 bug=796669: At present this module it is
- * function-passing spaghetti. The duct-tape is getting frayed.
- * It ought to be recomposed as widgets or something a bit more objecty so
- * it can be unit tested without having to set-up the world each time.
- */
-
function ExpandableRowWidget(config) {
ExpandableRowWidget.superclass.constructor.apply(this, arguments);
}
@@ -95,11 +88,17 @@
// right to add comments.
var add_comment_placeholder =
container.one('div.add-comment-placeholder');
+ var comment_widget = null;
if (add_comment_placeholder !== null) {
- namespace.setup_add_comment(
- add_comment_placeholder,
- latest_comment_container,
- api_uri);
+ comment_widget = new AddCommentWidget({
+ latestCommentContainer: latest_comment_container,
+ addCommentPlaceholder: add_comment_placeholder,
+ apiUri: api_uri});
+ comment_widget.render(add_comment_placeholder);
+ //namespace.setup_add_comment(
+ // add_comment_placeholder,
+ // latest_comment_container,
+ // api_uri);
}
// The blacklist slot with a class 'blacklist-options' is only
// available when the user has the right to blacklist.
@@ -110,8 +109,8 @@
{srcNode: blacklist_slot,
sourceName: source_name,
dsdLink: api_uri,
- latestCommentContainer: latest_comment_container,
- addCommentPlaceholder: add_comment_placeholder});
+ commentWidget: comment_widget
+ });
}
// If the user has not the right to blacklist, we disable
// the blacklist slot.
@@ -218,8 +217,7 @@
initializer: function(cfg) {
this.sourceName = cfg.sourceName;
this.dsdLink = cfg.dsdLink;
- this.latestCommentContainer = cfg.latestCommentContainer;
- this.addCommentPlaceholder = cfg.addCommentPlaceholder;
+ this.commentWidget = cfg.commentWidget;
this.relatedRows = cfg.relatedRows;
this.container = cfg.container;
// We call bindUI directly here because the BlacklistWidgets
@@ -380,9 +378,9 @@
});
fade_to_gray.run();
});
- namespace.add_comment(
- updated_entry, self.addCommentPlaceholder,
- self.latestCommentContainer);
+ if (self.commentWidget !== null) {
+ self.commentWidget.display_new_comment(updated_entry);
+ }
},
failure: function(id, response) {
self.unlock();
@@ -428,168 +426,193 @@
};
/**
- * XXX: rvb 2011-08-10 bug=823777: All this Javascript code to
- * manage the "add comment" slot should be refactored into a
- * YUI widget and tests should be added.
- */
-
-/**
- * This method adds a comment in the UI. It appends a comment to the
- * list of comments and updates the latest comments slot.
- *
- * @param comment_entry {Comment} A comment as returns by the api.
- * @param add_comment_placeholder {Node} The node that contains the
- * relevant comment fields.
- * @param latest_comment_placeholder {Node} The node that contains the
- * latest comment.
- */
-namespace.add_comment = function(comment_entry, add_comment_placeholder,
- latest_comment_placeholder) {
- // Grab the XHTML representation of the comment
- // and prepend it to the list of comments.
- var config = {
- on: {
- success: function(comment_html) {
- var comment_node = Y.Node.create(comment_html);
- add_comment_placeholder.insert(comment_node, 'before');
- var reveal = Y.lazr.effects.slide_out(comment_node);
- reveal.on("end", function() {
- Y.lp.anim.green_flash(
- {node: comment_node}).run();
- });
- reveal.run();
- }
- },
- accept: Y.lp.client.XHTML
- };
- namespace.lp_client.get(comment_entry.get('self_link'), config);
- namespace.update_latest_comment(
- comment_entry, latest_comment_placeholder);
-};
-
-/**
- * Handle the add comment event triggered by the 'add comment' form.
- *
- * This method adds a comment via the API and update the UI.
- *
- * @param comment_form {Node} The node that contains the relevant comment
- * fields.
- * @param latest_comment_placeholder {Node} The node that contains the
- * latest comment.
- * @param api_uri {string} The uri for the distroseriesdifference to which
- * the comment is to be added.
- * @param cb_success {function} Called when a comment has successfully
- * been added. (Deferreds would be awesome right about now.)
- */
-namespace.add_comment_handler = function(comment_form,
- latest_comment_placeholder, api_uri,
- cb_success) {
- var comment_area = comment_form.one('textarea');
- var comment_text = comment_area.get('value');
-
- // Treat empty comments as mistakes.
- if (Y.Lang.trim(comment_text).length === 0) {
- Y.lp.anim.red_flash({node: comment_area}).run();
- return;
- }
-
- var success_handler = function(comment_entry) {
- namespace.add_comment(
- comment_entry, comment_form, latest_comment_placeholder);
- comment_form.one('textarea').set('value', '');
- cb_success();
- };
- var failure_handler = function(id, response) {
- // Re-enable field with red flash.
- Y.lp.anim.red_flash({node: comment_form}).run();
- };
-
- var config = {
- on: {
- success: success_handler,
- failure: failure_handler,
- start: function() {
- // Show a spinner.
- comment_form.one('div.widget-bd')
- .append('<img src="/@@/spinner" />');
- // Disable the textarea and button.
- comment_form.all('textarea,button')
- .setAttribute('disabled', 'disabled');
- },
- end: function() {
- // Remove the spinner.
- comment_form.all('img').remove();
- // Enable the form.
- comment_form.all('textarea,button')
- .removeAttribute('disabled');
- }
- },
- parameters: {
- comment: comment_text
- }
- };
- namespace.lp_client.named_post(api_uri, 'addComment', config);
-};
-
-/**
- * Add the comment fields ready for sliding out.
- *
- * This method adds the markup for a slide-out comment and sets
- * the event handlers.
- *
- * @param placeholder {Node} The node that is to contain the comment
- * fields.
- * @param api_uri {string} The uri for the distroseriesdifference to which
- * the comment is to be added.
- */
-namespace.setup_add_comment = function(placeholder,
- latest_comment_placeholder,
- api_uri) {
- placeholder.insert([
- '<a class="widget-hd js-action sprite add" href="">',
- ' Add comment</a>',
- '<div class="widget-bd lazr-closed" ',
- ' style="height:0;overflow:hidden">',
- ' <textarea></textarea><button>Save comment</button>',
- '</div>'
- ].join(''), 'replace');
-
- // The comment area should slide in when the 'Add comment'
- // action is clicked.
- var slide_anim = null;
- var slide = function(direction) {
- // Slide out if direction is true, slide in if direction
- // is false, otherwise do the opposite of what's being
- // animated right now.
- if (slide_anim === null) {
- slide_anim = Y.lazr.effects.slide_out(
- placeholder.one('div.widget-bd'));
- if (Y.Lang.isBoolean(direction)) {
- slide_anim.set("reverse", !direction);
- }
- }
- else {
- if (Y.Lang.isBoolean(direction)) {
- slide_anim.set("reverse", !direction);
- }
- else {
- slide_anim.set('reverse', !slide_anim.get('reverse'));
- }
- slide_anim.stop();
- }
- slide_anim.run();
- };
- var slide_in = function() { slide(false); };
-
- placeholder.one('a.widget-hd').on(
- 'click', function(e) { e.preventDefault(); slide(); });
- placeholder.one('button').on('click', function(e) {
- e.preventDefault();
- namespace.add_comment_handler(
- placeholder, latest_comment_placeholder,
- api_uri, slide_in);
- });
-};
+ * AddCommentWidget: the widget used to display a small form to enter
+ * a comment attached to a DSD.
+ */
+function AddCommentWidget(config) {
+ AddCommentWidget.superclass.constructor.apply(this, arguments);
+}
+
+AddCommentWidget.NAME = "addCommentWidget";
+
+AddCommentWidget.ATTRS = {
+ /**
+ * The content of the textarea used to add a new comment.
+ * @type String
+ */
+ comment_text: {
+ getter: function() {
+ return this.addForm.one('textarea').get('value');
+ },
+ setter: function(comment_text) {
+ this.addForm.one('textarea').set('value', comment_text);
+ }
+ }
+};
+
+Y.extend(AddCommentWidget, Y.Widget, {
+ initializer: function(cfg) {
+ this.latestCommentContainer = cfg.latestCommentContainer;
+ this.addCommentPlaceholder = cfg.addCommentPlaceholder;
+ this.apiUri = cfg.apiUri;
+
+ this.addCommentLink = Y.Node.create([
+ '<a class="widget-hd js-action sprite add" href="">',
+ ' Add comment</a>'
+ ].join(''));
+ this.addForm = Y.Node.create([
+ '<div class="widget-bd lazr-closed" ',
+ ' style="height:0;overflow:hidden">',
+ ' <textarea></textarea><button>Save comment</button>',
+ '</div>'
+ ].join(''));
+ },
+
+ renderUI: function() {
+ this.get("contentBox")
+ .append(this.addCommentLink)
+ .append(this.addForm);
+ },
+
+ _fire_anim_end: function(anim, event_name) {
+ var self = this;
+ anim.on("end", function() {
+ self.fire(event_name);
+ });
+ },
+
+ slide_in: function() {
+ var anim = Y.lazr.effects.slide_in(this.addForm);
+ this._fire_anim_end(anim, 'slided_in');
+ anim.run();
+ },
+
+ slide_out: function() {
+ var anim = Y.lazr.effects.slide_out(this.addForm);
+ this._fire_anim_end(anim, 'slided_out');
+ anim.run();
+ },
+
+ bindUI: function() {
+ Y.on("click", function(e) {
+ e.preventDefault();
+ this.slide_out();
+ }, this.addCommentLink, this);
+
+ this.on("comment_added", function(e) {
+ e.preventDefault();
+ var comment_entry = e.details[0];
+ this.display_new_comment(comment_entry);
+ }, this);
+
+ Y.on("click", function(e, comment_entry) {
+ e.preventDefault();
+ this.add_comment_handler();
+ }, this.addForm.one('button'), this);
+ },
+
+ lock: function() {
+ // Show a spinner.
+ this.addForm.append('<img src="/@@/spinner" />');
+ // Disable the textarea and button.
+ this.addForm.all('textarea,button')
+ .setAttribute('disabled', 'disabled');
+ },
+
+ unlock: function() {
+ // Remove the spinner.
+ this.addForm.all('img').remove();
+ // Enable the form and the button.
+ this.addForm.all('textarea,button')
+ .removeAttribute('disabled');
+ },
+
+ clean: function() {
+ this.set('comment_text', '');
+ },
+
+ /**
+ * This method displays a new comment in the UI. It appends a comment
+ * to the list of comments and updates the latest comments slot.
+ *
+ * @param comment_entry {Comment} A comment as returns by the api.
+ */
+ display_new_comment: function(comment_entry) {
+ // Grab the XHTML representation of the comment,
+ // prepend it to the list of comments and update the
+ // 'latest comment' slot.
+ var self = this;
+ var config = {
+ on: {
+ success: function(comment_html) {
+ var comment_node = Y.Node.create(comment_html);
+ self.addCommentPlaceholder.insert(comment_node, 'before');
+ var reveal = Y.lazr.effects.slide_out(comment_node);
+ reveal.on("end", function() {
+ Y.lp.anim.green_flash(
+ {node: comment_node}).run();
+ });
+ reveal.run();
+ namespace.update_latest_comment(
+ comment_entry, self.latestCommentContainer);
+ }
+ },
+ accept: Y.lp.client.XHTML
+ };
+ namespace.lp_client.get(comment_entry.get('self_link'), config);
+ },
+
+ /**
+ * Handle the add comment event triggered by the 'add comment' form.
+ *
+ * This method adds the content of the comment form as a comment via
+ * the API.
+ *
+ */
+ add_comment_handler: function() {
+ var comment_text = this.get('comment_text');
+
+ // Treat empty comments as mistakes.
+ if (Y.Lang.trim(comment_text).length === 0) {
+ Y.lp.anim.red_flash({
+ node: this.addForm.one('textarea')
+ }).run();
+ return;
+ }
+
+ var self = this;
+ var success_handler = function(comment_entry) {
+ self.clean();
+ self.slide_in();
+ self.fire('comment_added', comment_entry);
+ };
+ var failure_handler = function(id, response) {
+ // Re-enable field with red flash.
+ var node = self.addForm.one('textarea');
+ Y.lp.anim.red_flash({node: node}).run();
+ };
+
+ var config = {
+ on: {
+ success: success_handler,
+ failure: failure_handler,
+ start: function() {
+ self.lock();
+ },
+ end: function() {
+ self.unlock();
+ }
+ },
+ parameters: {
+ comment: comment_text
+ }
+ };
+ namespace.lp_client.named_post(this.apiUri, 'addComment', config);
+ }
+
+});
+
+namespace.AddCommentWidget = AddCommentWidget;
namespace.setup = function() {
Y.all('table.listing a.toggle-extra').each(function(toggle){
@@ -729,7 +752,6 @@
build_package_diff_update_config);
};
-
/**
* Add a button to start package diff computation.
*
=== modified file 'lib/lp/registry/javascript/tests/test_distroseriesdifferences_details.html'
--- lib/lp/registry/javascript/tests/test_distroseriesdifferences_details.html 2011-08-11 11:57:42 +0000
+++ lib/lp/registry/javascript/tests/test_distroseriesdifferences_details.html 2011-08-11 11:57:42 +0000
@@ -18,6 +18,7 @@
<script type="text/javascript" src="../../../app/javascript/lazr/lazr.js"></script>
<script type="text/javascript" src="../../../app/javascript/extras/extras.js"></script>
<script type="text/javascript" src="../../../app/javascript/anim/anim.js"></script>
+ <script type="text/javascript" src="../../../app/javascript/effects/effects.js"></script>
<script type="text/javascript" src="../../../app/javascript/overlay/overlay.js"></script>
<script type="text/javascript" src="../../../app/javascript/formoverlay/formoverlay.js"></script>
=== modified file 'lib/lp/registry/javascript/tests/test_distroseriesdifferences_details.js'
--- lib/lp/registry/javascript/tests/test_distroseriesdifferences_details.js 2011-08-11 11:57:42 +0000
+++ lib/lp/registry/javascript/tests/test_distroseriesdifferences_details.js 2011-08-11 11:57:42 +0000
@@ -3,7 +3,7 @@
YUI().use(
'lp.testing.runner', 'test', 'console', 'node-event-simulate',
- 'lp.soyuz.base', "lp.anim", "lazr.formoverlay",
+ 'lp.soyuz.base', "lp.anim", "lazr.formoverlay", "lazr.effects",
'lp.soyuz.dynamic_dom_updater', 'event-simulate', "io-base",
'lp.registry.distroseriesdifferences_details', function(Y) {
@@ -217,6 +217,32 @@
}
};
+var assertAllDisabled = function(node, selector) {
+ var all_input_status = node.all(selector).get('disabled');
+ Y.Assert.isTrue(all_input_status.every(function(val) {return val;}));
+};
+
+var assertAllEnabled = function(node, selector) {
+ var all_input_status = node.all(selector).get('disabled');
+ Y.Assert.isTrue(all_input_status.every(function(val) {return !val;}));
+};
+
+function Comment() {}
+
+Comment.prototype.get = function(key) {
+ var data = {
+ comment_date: "2011-08-08T13:15:50.636269+00:00",
+ body_text: 'This is the comment',
+ self_link: ["https://lp.net/api/devel/u/d//+source/",
+ "evolution/+difference/ubuntu/warty/comments/6"
+ ].join(''),
+ web_link: ["https://lp.net/d/d/+source/evolution/",
+ "+difference/ubuntu/warty/comments/6"
+ ].join('')
+ };
+ return data[key];
+};
+
var testBlacklistWidget = {
name: 'package-diff-update-interaction',
@@ -226,14 +252,13 @@
.empty()
.appendChild(Y.Node.create(whole_table));
this.node = Y.one('.blacklist-options');
- this.latestCommentContainer = Y.one('td.latest-comment-fragment');
- this.addCommentPlaceholder = Y.one('div.add-comment-placeholder');
+ this.commentWidget = null;
this.widget = new dsd_details.BlacklistWidget(
{srcNode: this.node,
sourceName: 'evolution',
dsdLink: '/a/link',
- latestCommentContainer: this.latestCommentContainer,
- addCommentPlaceholder: this.addCommentPlaceholder});
+ commentWidget: this.commentWidget
+ });
// Set the animation duration to 0.1 to avoid having to wait for its
// completion for too long.
this.widget.ANIM_DURATION = 0.1;
@@ -246,9 +271,7 @@
Y.Assert.areEqual(
this.latestCommentContainer,
this.widget.latestCommentContainer);
- Y.Assert.areEqual(
- this.addCommentPlaceholder,
- this.widget.addCommentPlaceholder);
+ Y.Assert.areEqual(this.commentWidget, this.widget.commentWidget);
},
test_wire_blacklist_click: function() {
@@ -393,24 +416,16 @@
Y.Assert.areEqual(input, target);
},
- assertAllDisabled: function(selector) {
- var all_input_status = Y.all(selector).get('disabled');
- Y.Assert.isTrue(all_input_status.every(function(val) {return val;}));
- },
-
- assertAllEnabled: function(selector) {
- var all_input_status = Y.all(selector).get('disabled');
- Y.Assert.isTrue(all_input_status.every(function(val) {return !val;}));
- },
-
assertIsLocked: function() {
- Y.Assert.isNotNull(Y.one('img[src="/@@/spinner"]'));
- this.assertAllDisabled('div.blacklist-options input');
+ var node = this.widget.get('srcNode');
+ Y.Assert.isNotNull(node.one('img[src="/@@/spinner"]'));
+ assertAllDisabled(node, 'div.blacklist-options input');
},
assertIsUnlocked: function() {
- Y.Assert.isNull(Y.one('img[src="/@@/spinner"]'));
- this.assertAllEnabled('div.blacklist-options input');
+ var node = this.widget.get('srcNode');
+ Y.Assert.isNull(node.one('img[src="/@@/spinner"]'));
+ assertAllEnabled(node, 'div.blacklist-options input');
},
test_lock: function() {
@@ -430,20 +445,6 @@
},
patchNamedPost: function(method_name, expected_parameters) {
- function Comment() {}
- Comment.prototype.get = function(key) {
- var data = {
- comment_date: "2011-08-08T13:15:50.636269+00:00",
- body_text: 'This is the comment',
- self_link: ["https://lp.net/api/devel/u/d//+source/",
- "evolution/+difference/ubuntu/warty/comments/6"
- ].join(''),
- web_link: ["https://lp.net/d/d/+source/evolution/",
- "+difference/ubuntu/warty/comments/6"
- ].join('')
- };
- return data[key];
- };
var comment_entry = new Comment();
var self = this;
dsd_details.lp_client.named_post = function(url, func, config) {
@@ -473,6 +474,13 @@
},
test_blacklist_submit_handler_blacklist_simple: function() {
+ var mockCommentWidget = Y.Mock();
+ Y.Mock.expect(mockCommentWidget, {
+ method: "display_new_comment",
+ args: [Y.Mock.Value.Object]
+ });
+ this.widget.commentWidget = mockCommentWidget;
+
this.patchNamedPost(
'blacklist',
{comment: 'Test comment', all: false});
@@ -492,7 +500,23 @@
}
},
+ test_blacklist_submit_handler_blacklist_null_comment_widget: function() {
+ // The widget can cope with a null commentWidget.
+ Y.Assert.isNull(this.widget.commentWidget);
+ var input = Y.one(
+ 'div.blacklist-options input[value="BLACKLISTED_CURRENT"]');
+ this.widget.blacklist_submit_handler(
+ 'blacklist', false, "Test comment", input);
+ },
+
test_blacklist_submit_handler_blacklist_all: function() {
+ var mockCommentWidget = Y.Mock();
+ Y.Mock.expect(mockCommentWidget, {
+ method: "display_new_comment",
+ args: [Y.Mock.Value.Object]
+ });
+ this.widget.commentWidget = mockCommentWidget;
+
this.patchNamedPost(
'blacklist',
{comment: 'Test comment', all: true});
@@ -513,6 +537,13 @@
},
test_blacklist_submit_handler_unblacklist: function() {
+ var mockCommentWidget = Y.Mock();
+ Y.Mock.expect(mockCommentWidget, {
+ method: "display_new_comment",
+ args: [Y.Mock.Value.Object]
+ });
+ this.widget.commentWidget = mockCommentWidget;
+
this.patchNamedPost(
'unblacklist',
{comment: 'Test comment', all: true});
@@ -545,6 +576,272 @@
}
};
+var testAddCommentWidget = {
+
+ name: 'test-add-comment-widget',
+
+ setUp: function() {
+ Y.one("#placeholder")
+ .empty()
+ .appendChild(Y.Node.create(whole_table));
+ this.latestCommentContainer = Y.one('td.latest-comment-fragment');
+ this.addCommentPlaceholder = Y.one('div.add-comment-placeholder');
+ this.apiUri = '/testuri/';
+ this.widget = new dsd_details.AddCommentWidget({
+ srcNode: this.node,
+ apiUri: this.apiUri,
+ latestCommentContainer: this.latestCommentContainer,
+ addCommentPlaceholder: this.addCommentPlaceholder
+ });
+ this.widget.render(this.addCommentPlaceholder);
+ },
+
+ tearDown: function() {
+ this.widget.destroy();
+ },
+
+ test_initializer: function() {
+ Y.Assert.areEqual(
+ this.latestCommentContainer, this.widget.latestCommentContainer);
+ Y.Assert.areEqual(
+ this.addCommentPlaceholder, this.widget.addCommentPlaceholder);
+ Y.Assert.areEqual(
+ this.apiUri, this.widget.apiUri);
+ // Widget is initially closed.
+ var node = this.widget.get('srcNode');
+ Y.Assert.areEqual(
+ '0pt',
+ node.one('div.widget-bd').getStyle('height'));
+ },
+
+ test_comment_text_getter: function() {
+ this.widget.get('srcNode').one('textarea').set('value', 'Content');
+ Y.Assert.areEqual(
+ 'Content',
+ this.widget.get('comment_text'));
+ },
+
+ test_comment_text_setter: function() {
+ this.widget.set('comment_text', 'Content');
+ Y.Assert.areEqual(
+ 'Content',
+ this.widget.get('srcNode').one('textarea').get('value'));
+ },
+
+ test_slide_in: function() {
+ // 'Manually' open the widget.
+ var node = this.widget.get('srcNode');
+ node.one('div.widget-bd').setStyle('height', '1000px');
+ var self = this;
+ var listener = function(e) {
+ self.resume(function(){
+ Y.Assert.areEqual(
+ '0px',
+ node.one('div.widget-bd').getStyle('height'));
+ });
+ };
+ this.widget.on('slided_in', listener);
+ this.widget.slide_in();
+ this.wait(1000);
+ },
+
+ test_slide_out: function() {
+ var fired = false;
+ var self = this;
+ var listener = function(e) {
+ self.resume(function(){
+ fired = true;
+ });
+ };
+ this.widget.on('slided_out', listener);
+ this.widget.slide_out();
+ this.wait(1000);
+ Y.Assert.isTrue(fired);
+ },
+
+ assertIsLocked: function() {
+ var node = this.widget.get('srcNode');
+ Y.Assert.isNotNull(node.one('img[src="/@@/spinner"]'));
+ assertAllDisabled(node, 'textarea, button');
+ },
+
+ assertIsUnlocked: function() {
+ var node = this.widget.get('srcNode');
+ Y.Assert.isNull(node.one('img[src="/@@/spinner"]'));
+ assertAllEnabled(node, 'textarea, button');
+ },
+
+ test_lock: function() {
+ this.widget.lock();
+ this.assertIsLocked();
+ },
+
+ test_unlock: function() {
+ this.widget.unlock();
+ this.assertIsUnlocked();
+ },
+
+ test_lock_unlock: function() {
+ this.widget.lock();
+ this.widget.unlock();
+ this.assertIsUnlocked();
+ },
+
+ test_wire_click_add_comment_link: function() {
+ var fired = false;
+ var input = this.widget.get('srcNode').one('a.widget-hd');
+ var self = this;
+ var listener = function(e) {
+ self.resume(function(){
+ fired = true;
+ });
+ };
+ this.widget.on('slided_out', listener);
+ input.simulate('click');
+ this.wait();
+ Y.Assert.isTrue(fired);
+ },
+
+ test_wire_comment_added_calls_display_new_comment: function() {
+ var fired = false;
+ var comment_entry = new Comment();
+
+ var display_new_comment = function(entry) {
+ fired = true;
+ Y.ObjectAssert.areEqual(comment_entry, entry);
+ };
+ this.widget.display_new_comment = display_new_comment;
+ this.widget.fire('comment_added', comment_entry);
+
+ Y.Assert.isTrue(fired);
+ },
+
+ test_wire_click_button_calls_add_comment_handler: function() {
+ var input = this.widget.get('srcNode').one('button');
+ var fired = false;
+
+ var add_comment_handler = function() {
+ fired = true;
+ };
+ this.widget.add_comment_handler = add_comment_handler;
+ input.simulate('click');
+
+ Y.Assert.isTrue(fired);
+ },
+
+ test_clean: function() {
+ var comment_text = 'Content';
+ this.widget.get('srcNode').one('textarea').set('value', comment_text);
+ var self = this;
+ var comment_entry = new Comment();
+ var post_called = false;
+ dsd_details.lp_client.named_post = function(url, method, config) {
+ post_called = true;
+ Y.Assert.areEqual('addComment', method);
+ Y.Assert.areEqual(comment_text, config.parameters.comment);
+ config.on.success(comment_entry);
+ };
+ // The event comment_added will be fired.
+ var event_fired = false;
+ event_handler = function(e) {
+ event_fired = true;
+ Y.ObjectAssert.areEqual(comment_entry, e.details[0]);
+ };
+ this.widget.on('comment_added', event_handler);
+
+ this.widget.add_comment_handler();
+
+ Y.Assert.areEqual('', this.widget.get('comment_text'));
+ Y.Assert.isTrue(post_called);
+ Y.Assert.isTrue(event_fired);
+ },
+
+ test_display_new_comment: function() {
+ var comment_html = '<span id="new_comment">Comment content.</span>';
+ var self = this;
+ var comment_entry = new Comment();
+ var get_called = false;
+ dsd_details.lp_client.get = function(url, config) {
+ get_called = true;
+ config.on.success(comment_html);
+ };
+ // The method update_latest_comment will be called with the right
+ // arguments.
+ var update_latest_called = false;
+ dsd_details.update_latest_comment = function(entry, node) {
+ update_latest_called = true;
+ Y.ObjectAssert.areEqual(comment_entry, entry);
+ Y.Assert.areEqual(self.widget.latestCommentContainer, node);
+ };
+ this.widget.display_new_comment(comment_entry);
+
+ // The new comment has been added to the list of comments.
+ Y.Assert.areEqual(
+ 'Comment content.',
+ this.widget.addCommentPlaceholder.previous().get('text'));
+ Y.Assert.isTrue(get_called);
+ Y.Assert.isTrue(update_latest_called);
+ },
+
+ test_add_comment_handler_success: function() {
+ var comment_text = 'Content';
+ this.widget.get('srcNode').one('textarea').set('value', comment_text);
+ var comment_entry = new Comment();
+ var post_called = false;
+ dsd_details.lp_client.named_post = function(url, method, config) {
+ post_called = true;
+ Y.Assert.areEqual('addComment', method);
+ Y.Assert.areEqual(comment_text, config.parameters.comment);
+ config.on.success(comment_entry);
+ };
+ // The event comment_added will be fired.
+ var event_fired = false;
+ event_handler = function(e) {
+ event_fired = true;
+ Y.ObjectAssert.areEqual(comment_entry, e.details[0]);
+ };
+ this.widget.on('comment_added', event_handler);
+
+ this.widget.add_comment_handler();
+
+ Y.Assert.areEqual('', this.widget.get('comment_text'));
+ Y.Assert.isTrue(post_called);
+ Y.Assert.isTrue(event_fired);
+ this.assertIsUnlocked();
+ },
+
+ test_add_comment_handler_failure: function() {
+ var comment_text = 'Content';
+ this.widget.get('srcNode').one('textarea').set('value', comment_text);
+ var post_called = false;
+ dsd_details.lp_client.named_post = function(url, method, config) {
+ post_called = true;
+ config.on.failure();
+ };
+ this.widget.add_comment_handler();
+
+ // The content has not been cleaned.
+ Y.Assert.areEqual('Content', this.widget.get('comment_text'));
+ Y.Assert.isTrue(post_called);
+ this.assertIsUnlocked();
+ },
+
+ test_add_comment_handler_empty: function() {
+ // An empty comment is treated as a mistake.
+ var comment_text = '';
+ this.widget.get('srcNode').one('textarea').set('value', comment_text);
+ var self = this;
+ var comment_entry = new Comment();
+ var post_called = false;
+ dsd_details.lp_client.named_post = function(url, method, config) {
+ post_called = true;
+ };
+ this.widget.add_comment_handler();
+ Y.Assert.isFalse(post_called);
+ }
+
+};
+
var testPackageDiffUpdateInteraction = {
name: 'package-diff-update-interaction',
@@ -662,6 +959,7 @@
suite.add(new Y.Test.Case(testPackageDiffUpdate));
suite.add(new Y.Test.Case(testExpandableRowWidget));
suite.add(new Y.Test.Case(testBlacklistWidget));
+suite.add(new Y.Test.Case(testAddCommentWidget));
suite.add(new Y.Test.Case(testPackageDiffUpdateInteraction));
Y.lp.testing.Runner.run(suite);