Files
zulip/frontend_tests/node_tests/reactions.js
Harshit Bansal 5aa8629a10 reactions: Migrate emoji_code to store id for realm emoji.
Till now, we had been storing realm emoji's name in emoji code field
in reactions' model. This commit migrates it to store realm emoji's id.
It is a part of effort to migrate realm emojis to be referenced by their
id and not by name.
2018-03-09 13:46:27 -08:00

732 lines
21 KiB
JavaScript

set_global('document', 'document-stub');
set_global('$', global.make_zjquery());
zrequire('people');
zrequire('reactions');
set_global('emoji', {
emojis_by_name: {
alien: '1f47d',
smile: '1f604',
},
all_realm_emojis: {
realm_emoji: {
id: '991',
emoji_name: 'realm_emoji',
emoji_url: 'TBD',
deactivated: false,
},
inactive_realm_emoji: {
id: '992',
emoji_name: 'inactive_realm_emoji',
emoji_url: 'TBD',
deactivated: true,
},
zulip: {
id: 'zulip',
emoji_name: 'zulip',
emoji_url: 'TBD',
deactivated: false,
},
},
active_realm_emojis: {
realm_emoji: {
id: '991',
emoji_name: 'realm_emoji',
emoji_url: 'TBD',
},
zulip: {
id: 'zulip',
emoji_name: 'zulip',
emoji_url: 'TBD',
},
},
deactivated_realm_emojis: {
inactive_realm_emoji: {
emoji_name: 'inactive_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_codes', {
name_to_codepoint: {
alien: '1f47d',
smile: '1f604',
frown: '1f626',
octopus: '1f419',
},
});
set_global('emoji_picker', {
hide_emoji_popover: function () {},
});
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}, reaction_type: 'unicode_emoji', emoji_code: '1f604'},
{emoji_name: 'smile', user: {id: 6}, reaction_type: 'unicode_emoji', emoji_code: '1f604'},
{emoji_name: 'frown', user: {id: 7}, reaction_type: 'unicode_emoji', emoji_code: '1f626'},
{emoji_name: 'inactive_realm_emoji', user: {id: 5}, reaction_type: 'realm_emoji',
emoji_code: '992'},
// add some bogus user_ids
{emoji_name: 'octopus', user: {id: 8888}, reaction_type: 'unicode_emoji', emoji_code: '1f419'},
{emoji_name: 'frown', user: {id: 9999}, reaction_type: 'unicode_emoji', emoji_code: '1f626'},
],
};
set_global('message_store', {
get: function (message_id) {
assert.equal(message_id, 1001);
return message;
},
});
set_global('current_msg_list', {
selected_message: function () {
return { sent_by_me: true };
},
selected_row: function () {
return $('.selected-row');
},
selected_id: function () {
return 42;
},
});
(function test_open_reactions_popover() {
$('.selected-row').set_find_results('.actions_hover', $('.target-action'));
$('.selected-row').set_find_results('.reaction_button', $('.target-reaction'));
var called = false;
emoji_picker.toggle_emoji_popover = function (target, id) {
called = true;
assert.equal(id, 42);
assert.equal(target, $('.target-reaction')[0]);
};
assert(reactions.open_reactions_popover());
assert(called);
current_msg_list.selected_message = function () { return { sent_by_me: false }; };
called = false;
emoji_picker.toggle_emoji_popover = function (target, id) {
called = true;
assert.equal(id, 42);
assert.equal(target, $('.target-action')[0]);
};
assert(reactions.open_reactions_popover());
assert(called);
}());
(function test_basics() {
var result = reactions.get_message_reactions(message);
assert(reactions.current_user_has_reacted_to_emoji(message, '1f604', 'unicode_emoji'));
assert(!reactions.current_user_has_reacted_to_emoji(message, '1f626', 'unicode_emoji'));
result.sort(function (a, b) { return a.count - b.count; });
var expected_result = [
{
emoji_name: 'frown',
reaction_type: 'unicode_emoji',
emoji_code: '1f626',
local_id: 'unicode_emoji,frown,1f626',
count: 1,
user_ids: [7],
title: 'Cali reacted with :frown:',
emoji_alt_code: false,
class: 'message_reaction',
},
{
emoji_name: 'inactive_realm_emoji',
reaction_type: 'realm_emoji',
emoji_code: '992',
local_id: 'realm_emoji,inactive_realm_emoji,992',
count: 1,
user_ids: [5],
title: 'You (click to remove) reacted with :inactive_realm_emoji:',
emoji_alt_code: false,
is_realm_emoji: true,
url: 'TBD',
class: 'message_reaction reacted',
},
{
emoji_name: 'smile',
reaction_type: 'unicode_emoji',
emoji_code: '1f604',
local_id: 'unicode_emoji,smile,1f604',
count: 2,
user_ids: [5, 6],
title: 'You (click to remove) and Bob van Roberts reacted with :smile:',
emoji_alt_code: false,
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
var orig_remove_reaction = reactions.remove_reaction;
var orig_add_reaction = reactions.add_reaction;
reactions.remove_reaction = function () {};
reactions.add_reaction = function () {};
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/reactions');
assert.deepEqual(args.data, {
reaction_type: 'unicode_emoji',
emoji_name: 'smile',
emoji_code: '1f604',
});
// 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.post = stub.f;
reactions.toggle_emoji_reaction(message_id, emoji_name);
var args = stub.get_args('args').args;
assert.equal(args.url, '/json/messages/1001/reactions');
assert.deepEqual(args.data, {
reaction_type: 'unicode_emoji',
emoji_name: 'alien',
emoji_code: '1f47d',
});
});
emoji_name = 'inactive_realm_emoji';
global.with_stub(function (stub) {
// Test removing a deactivated realm emoji. An user can interact with a
// deactivated realm emoji only by clicking on a reaction, hence, only
// `process_reaction_click()` codepath supports deleting/adding a deactivated
// realm emoji.
global.channel.del = stub.f;
reactions.process_reaction_click(message_id, 'realm_emoji,inactive_realm_emoji,992');
var args = stub.get_args('args').args;
assert.equal(args.url, '/json/messages/1001/reactions');
assert.deepEqual(args.data, {
reaction_type: 'realm_emoji',
emoji_name: 'inactive_realm_emoji',
emoji_code: '992',
});
});
emoji_name = 'zulip'; // Test adding zulip emoji.
global.with_stub(function (stub) {
global.channel.post = stub.f;
reactions.toggle_emoji_reaction(message_id, emoji_name);
var args = stub.get_args('args').args;
assert.equal(args.url, '/json/messages/1001/reactions');
assert.deepEqual(args.data, {
reaction_type: 'zulip_extra_emoji',
emoji_name: 'zulip',
emoji_code: 'zulip',
});
});
var orig_func = global.blueslip.warn;
var error_msg;
global.blueslip.warn = function (msg) {
error_msg = msg;
};
emoji_name = 'unknown-emoji'; // Test sending an emoji unknown to frontend.
reactions.toggle_emoji_reaction(message_id, emoji_name);
assert.equal(error_msg, 'Bad emoji name: ' + emoji_name);
global.blueslip.warn = orig_func;
reactions.add_reaction = orig_add_reaction;
reactions.remove_reaction = orig_remove_reaction;
}());
(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,
reaction_type: 'unicode_emoji',
emoji_name: '8ball',
emoji_code: '1f3b1',
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);
// Running add_reaction again should not result in any changes
template_called = false;
insert_called = false;
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,
reaction_type: 'unicode_emoji',
emoji_name: '8ball',
emoji_code: '1f3b1',
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-reaction-id='unicode_emoji,8ball,1f3b1']");
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', 'inactive_realm_emoji', '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);
// Running remove_reaction again should not result in any changes
removed = false;
reactions.remove_reaction(alice_event);
assert(!removed);
current_emojis = reactions.get_emojis_used_by_user_for_message_id(1001);
assert.deepEqual(current_emojis, ['smile', 'inactive_realm_emoji']);
// Now add Cali's realm_emoji reaction.
var cali_event = {
message_id: 1001,
reaction_type: 'realm_emoji',
emoji_name: 'realm_emoji',
emoji_code: '991',
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,
reaction_type: 'realm_emoji',
emoji_name: 'realm_emoji',
emoji_code: '991',
user: {
user_id: alice.user_id,
},
};
message_reactions.find = function (selector) {
assert.equal(selector, "[data-reaction-id='realm_emoji,realm_emoji,991']");
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,
reaction_type: 'unicode_emoji',
emoji_name: '8ball',
emoji_code: '1f3b1',
user: {
user_id: alice.user_id,
},
};
var bob_8ball_event = {
message_id: 2001,
reaction_type: 'unicode_emoji',
emoji_name: '8ball',
emoji_code: '1f3b1',
user: {
user_id: bob.user_id,
},
};
var cali_airplane_event = {
message_id: 2001,
reaction_type: 'unicode_emoji',
emoji_name: 'airplane',
emoji_code: '2708',
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,
reaction_type: 'unicode_emoji',
emoji_name: '8ball',
emoji_code: '1f3b1',
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,
reaction_type: 'unicode_emoji',
emoji_name: '8ball',
emoji_code: '1f3b1',
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,
reaction_type: 'unicode_emoji',
emoji_name: 'airplane',
emoji_code: '2708',
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,
reaction_type: 'unicode_emoji',
emoji_name: '8ball',
emoji_code: '1f3b1',
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,
reaction_type: 'unicode_emoji',
emoji_name: '8ball',
emoji_code: '1f3b1',
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,
reaction_type: 'realm_emoji',
emoji_name: 'realm_emoji',
emoji_code: '991',
user: {
user_id: 99,
},
};
var original_func = reactions.current_user_has_reacted_to_emoji;
reactions.current_user_has_reacted_to_emoji = function () { return true; };
reactions.toggle_emoji_reaction(55, bogus_event.emoji_name);
assert.equal(error_msg, 'reactions: Bad message id: 55');
reactions.current_user_has_reacted_to_emoji = original_func;
error_msg = undefined;
reactions.add_reaction(bogus_event);
assert.equal(error_msg, undefined);
reactions.remove_reaction(bogus_event);
assert.equal(error_msg, undefined);
}());
(function test_local_reaction_id() {
var reaction_info = {
reaction_type: 'unicode_emoji',
emoji_name: 'thumbs_up',
emoji_code: '1f44d',
};
var local_id = reactions.get_local_reaction_id(reaction_info);
assert.equal(local_id, 'unicode_emoji,thumbs_up,1f44d');
var reverse_info = reactions.get_reaction_info(local_id);
assert.deepEqual(reverse_info, reaction_info);
}());
(function test_process_reaction_click() {
var message_id = 1001;
var expected_reaction_info = {
reaction_type: 'unicode_emoji',
emoji_name: '8ball',
emoji_code: '1f3b1',
};
global.message_store.get = function (message_id) {
assert.equal(message_id, 1001);
return message;
};
global.with_stub(function (stub) {
global.channel.post = stub.f;
reactions.process_reaction_click(message_id, 'unicode_emoji,8ball,1f3b1');
var args = stub.get_args('args').args;
assert.equal(args.url, '/json/messages/1001/reactions');
assert.deepEqual(args.data, expected_reaction_info);
});
expected_reaction_info = {
reaction_type: 'unicode_emoji',
emoji_name: 'smile',
emoji_code: '1f604',
};
global.with_stub(function (stub) {
global.channel.del = stub.f;
reactions.process_reaction_click(message_id, 'unicode_emoji,smile,1f604');
var args = stub.get_args('args').args;
assert.equal(args.url, '/json/messages/1001/reactions');
assert.deepEqual(args.data, expected_reaction_info);
});
}());