Files
zulip/frontend_tests/node_tests/reactions.js
Steve Howell bd59b91faa reactions: Simplify markup related to message ids.
Because of local echo, message ids can change in message rows.
Having reactions use markup to indicate their message id just
creates more moving parts, since we would need to handle
message_id_changed events.

Now our handlers just call row.get_message_id() as needed.
2017-07-21 11:38:25 -07:00

506 lines
13 KiB
JavaScript

set_global('document', 'document-stub');
set_global('$', global.make_zjquery());
add_dependencies({
people: 'js/people.js',
});
set_global('emoji', {
emojis_name_to_css_class: {
frown: 'frown-css',
octopus: 'octopus-css',
smile: 'smile-css',
},
emojis_by_name: {
alien: '1f47d',
smile: '1f604',
},
all_realm_emojis: {
realm_emoji: {
emoji_name: 'realm_emoji',
emoji_url: 'TBD',
deactivated: false,
},
},
active_realm_emojis: {
realm_emoji: {
emoji_name: 'realm_emoji',
emoji_url: 'TBD',
},
},
});
set_global('blueslip', {
warn: function () {},
});
set_global('page_params', {user_id: 5});
set_global('channel', {});
set_global('templates', {});
set_global('emoji_picker', {
hide_emoji_popover: function () {},
});
var reactions = require("js/reactions.js");
var alice = {
email: 'alice@example.com',
user_id: 5,
full_name: 'Alice',
};
var bob = {
email: 'bob@example.com',
user_id: 6,
full_name: 'Bob van Roberts',
};
var cali = {
email: 'cali@example.com',
user_id: 7,
full_name: 'Cali',
};
people.add_in_realm(alice);
people.add_in_realm(bob);
people.add_in_realm(cali);
var message = {
id: 1001,
reactions: [
{emoji_name: 'smile', user: {id: 5}},
{emoji_name: 'smile', user: {id: 6}},
{emoji_name: 'frown', user: {id: 7}},
// add some bogus user_ids
{emoji_name: 'octopus', user: {id: 8888}},
{emoji_name: 'frown', user: {id: 9999}},
],
};
set_global('message_store', {
get: function (message_id) {
assert.equal(message_id, 1001);
return message;
},
});
(function test_basics() {
var result = reactions.get_message_reactions(message);
assert(reactions.current_user_has_reacted_to_emoji(message, 'smile'));
assert(!reactions.current_user_has_reacted_to_emoji(message, 'frown'));
result.sort(function (a, b) { return a.count - b.count; });
var expected_result = [
{
emoji_name: 'frown',
emoji_name_css_class: 'frown-css',
count: 1,
title: 'Cali reacted with :frown:',
emoji_alt_code: undefined,
class: 'message_reaction',
},
{
emoji_name: 'smile',
emoji_name_css_class: 'smile-css',
count: 2,
title: 'You (click to remove) and Bob van Roberts reacted with :smile:',
emoji_alt_code: undefined,
class: 'message_reaction reacted',
},
];
assert.deepEqual(result, expected_result);
}());
(function test_sending() {
var message_id = 1001; // see above for setup
var emoji_name = 'smile'; // should be a current reaction
global.with_stub(function (stub) {
global.channel.del = stub.f;
reactions.toggle_emoji_reaction(message_id, emoji_name);
var args = stub.get_args('args').args;
assert.equal(args.url, '/json/messages/1001/emoji_reactions/smile');
// args.success() does nothing; just make sure it doesn't crash
args.success();
// similarly, we only exercise the failure codepath
global.channel.xhr_error_message = function () {};
args.error();
});
emoji_name = 'alien'; // not set yet
global.with_stub(function (stub) {
global.channel.put = stub.f;
reactions.toggle_emoji_reaction(message_id, emoji_name);
var args = stub.get_args('args').args;
assert.equal(args.url, '/json/messages/1001/emoji_reactions/alien');
});
emoji_name = 'unknown-emoji';
reactions.toggle_emoji_reaction(message_id, emoji_name);
}());
(function test_set_reaction_count() {
var count_element = $.create('count-stub');
var reaction_element = $.create('reaction-stub');
reaction_element.set_find_results('.message_reaction_count', count_element);
reactions.set_reaction_count(reaction_element, 5);
assert.equal(count_element.html(), '5');
}());
(function test_get_reaction_section() {
var message_table = $.create('.message_table');
var message_row = $.create('some-message-row');
var message_reactions = $.create('our-reactions-section');
message_table.set_find_results("[zid='555']", message_row);
message_row.set_find_results('.message_reactions', message_reactions);
var section = reactions.get_reaction_section(555);
assert.equal(section, message_reactions);
}());
(function test_add_and_remove_reaction() {
// Insert 8ball for Alice.
var alice_event = {
message_id: 1001,
emoji_name: '8ball',
user: {
user_id: alice.user_id,
},
};
var message_reactions = $.create('our-reactions');
reactions.get_reaction_section = function (message_id) {
assert.equal(message_id, 1001);
return message_reactions;
};
message_reactions.find = function (selector) {
assert.equal(selector, '.reaction_button');
return 'reaction-button-stub';
};
var template_called;
global.templates.render = function (template_name, data) {
template_called = true;
assert.equal(template_name, 'message_reaction');
assert.equal(data.class, 'message_reaction reacted');
assert(!data.is_realm_emoji);
assert.equal(data.message_id, 1001);
assert.equal(data.title, 'You (click to remove) reacted with :8ball:');
return '<new reaction html>';
};
var insert_called;
$('<new reaction html>').insertBefore = function (element) {
assert.equal(element, 'reaction-button-stub');
insert_called = true;
};
reactions.add_reaction(alice_event);
assert(template_called);
assert(insert_called);
// Now, have Bob react to the same emoji (update).
var bob_event = {
message_id: 1001,
emoji_name: '8ball',
user: {
user_id: bob.user_id,
},
};
var count_element = $.create('count-element');
var reaction_element = $.create('reaction-element');
reaction_element.set_find_results('.message_reaction_count', count_element);
var title_set;
reaction_element.prop = function (prop_name, value) {
assert.equal(prop_name, 'title');
var expected_msg = 'You (click to remove)' +
' and Bob van Roberts reacted with :8ball:';
assert.equal(value, expected_msg);
title_set = true;
};
message_reactions.find = function (selector) {
assert.equal(selector, "[data-emoji-name='8ball']");
return reaction_element;
};
reactions.add_reaction(bob_event);
assert(title_set);
assert.equal(count_element.html(), '2');
// Now, remove Bob's 8ball emoji. The event has the same exact
// structure as the add event.
title_set = false;
reaction_element.prop = function (prop_name, value) {
assert.equal(prop_name, 'title');
var expected_msg = 'You (click to remove) reacted with :8ball:';
assert.equal(value, expected_msg);
title_set = true;
};
reactions.remove_reaction(bob_event);
assert(title_set);
assert.equal(count_element.html(), '1');
var current_emojis = reactions.get_emojis_used_by_user_for_message_id(1001);
assert.deepEqual(current_emojis, ['smile', '8ball']);
// Next, remove Alice's reaction, which exercises removing the
// emoji icon.
var removed;
reaction_element.remove = function () {
removed = true;
};
reactions.remove_reaction(alice_event);
assert(removed);
current_emojis = reactions.get_emojis_used_by_user_for_message_id(1001);
assert.deepEqual(current_emojis, ['smile']);
// Now add Cali's realm_emoji reaction.
var cali_event = {
message_id: 1001,
emoji_name: 'realm_emoji',
user: {
user_id: cali.user_id,
},
};
template_called = false;
global.templates.render = function (template_name, data) {
assert.equal(data.class, 'message_reaction');
assert(data.is_realm_emoji);
template_called = true;
return '<new reaction html>';
};
message_reactions.find = function (selector) {
assert.equal(selector, '.reaction_button');
return 'reaction-button-stub';
};
reactions.add_reaction(cali_event);
assert(template_called);
assert(!reaction_element.hasClass('reacted'));
// And then have Alice update it.
alice_event = {
message_id: 1001,
emoji_name: 'realm_emoji',
user: {
user_id: alice.user_id,
},
};
message_reactions.find = function (selector) {
assert.equal(selector, "[data-emoji-name='realm_emoji']");
return reaction_element;
};
reaction_element.prop = function () {};
reactions.add_reaction(alice_event);
assert(reaction_element.hasClass('reacted'));
var result = reactions.get_message_reactions(message);
var realm_emoji_data = _.filter(result, function (v) {
return v.emoji_name === 'realm_emoji';
})[0];
assert.equal(realm_emoji_data.count, 2);
assert.equal(realm_emoji_data.is_realm_emoji, true);
// And then remove Alice's reaction.
reactions.remove_reaction(alice_event);
assert(!reaction_element.hasClass('reacted'));
}());
(function test_with_view_stubs() {
// This function tests reaction events by mocking out calls to
// the view.
var message = {
id: 2001,
reactions: [],
};
message_store.get = function () {
return message;
};
function test_view_calls(test_params) {
var calls = [];
function add_call_func(name) {
return function (opts) {
calls.push({
name: name,
opts: opts,
});
};
}
reactions.view = {
insert_new_reaction: add_call_func('insert_new_reaction'),
update_existing_reaction: add_call_func('update_existing_reaction'),
remove_reaction: add_call_func('remove_reaction'),
};
test_params.run_code();
assert.deepEqual(calls, test_params.expected_view_calls);
}
var alice_8ball_event = {
message_id: 2001,
emoji_name: '8ball',
user: {
user_id: alice.user_id,
},
};
var bob_8ball_event = {
message_id: 2001,
emoji_name: '8ball',
user: {
user_id: bob.user_id,
},
};
var cali_airplane_event = {
message_id: 2001,
emoji_name: 'airplane',
user: {
user_id: cali.user_id,
},
};
test_view_calls({
run_code: function () {
reactions.add_reaction(alice_8ball_event);
},
expected_view_calls: [
{
name: 'insert_new_reaction',
opts: {
message_id: 2001,
emoji_name: '8ball',
user_id: alice.user_id,
},
},
],
});
test_view_calls({
run_code: function () {
reactions.add_reaction(bob_8ball_event);
},
expected_view_calls: [
{
name: 'update_existing_reaction',
opts: {
message_id: 2001,
emoji_name: '8ball',
user_id: bob.user_id,
user_list: [alice.user_id, bob.user_id],
},
},
],
});
test_view_calls({
run_code: function () {
reactions.add_reaction(cali_airplane_event);
},
expected_view_calls: [
{
name: 'insert_new_reaction',
opts: {
message_id: 2001,
emoji_name: 'airplane',
user_id: cali.user_id,
},
},
],
});
test_view_calls({
run_code: function () {
reactions.remove_reaction(bob_8ball_event);
},
expected_view_calls: [
{
name: 'remove_reaction',
opts: {
message_id: 2001,
emoji_name: '8ball',
user_id: bob.user_id,
user_list: [alice.user_id],
},
},
],
});
test_view_calls({
run_code: function () {
reactions.remove_reaction(alice_8ball_event);
},
expected_view_calls: [
{
name: 'remove_reaction',
opts: {
message_id: 2001,
emoji_name: '8ball',
user_id: alice.user_id,
user_list: [],
},
},
],
});
}());
(function test_error_handling() {
var error_msg;
global.message_store.get = function () {
return;
};
global.blueslip.error = function (msg) {
error_msg = msg;
};
var bogus_event = {
message_id: 55,
emoji_name: 'realm_emoji',
user: {
user_id: 99,
},
};
reactions.toggle_emoji_reaction(55);
assert.equal(error_msg, 'reactions: Bad message id: 55');
error_msg = undefined;
reactions.add_reaction(bogus_event);
assert.equal(error_msg, undefined);
reactions.remove_reaction(bogus_event);
assert.equal(error_msg, undefined);
}());