"use strict"; const {strict: assert} = require("assert"); const {mock_esm, set_global, with_overrides, zrequire} = require("../zjsunit/namespace"); const {run_test} = require("../zjsunit/test"); const blueslip = require("../zjsunit/zblueslip"); const $ = require("../zjsunit/zjquery"); const {page_params, user_settings} = require("../zjsunit/zpage_params"); const $window_stub = $.create("window-stub"); set_global("to_$", () => $window_stub); $(window).idle = () => {}; const _document = { hasFocus() { return true; }, }; const channel = mock_esm("../../static/js/channel"); const compose_state = mock_esm("../../static/js/compose_state"); const narrow = mock_esm("../../static/js/narrow"); const padded_widget = mock_esm("../../static/js/padded_widget"); const pm_list = mock_esm("../../static/js/pm_list"); const popovers = mock_esm("../../static/js/popovers"); const resize = mock_esm("../../static/js/resize"); const scroll_util = mock_esm("../../static/js/scroll_util"); const watchdog = mock_esm("../../static/js/watchdog"); set_global("document", _document); const huddle_data = zrequire("huddle_data"); const compose_fade = zrequire("compose_fade"); const keydown_util = zrequire("keydown_util"); const muted_users = zrequire("muted_users"); const presence = zrequire("presence"); const people = zrequire("people"); const buddy_data = zrequire("buddy_data"); const {buddy_list} = zrequire("buddy_list"); const user_status = zrequire("user_status"); const activity = zrequire("activity"); const me = { email: "me@zulip.com", user_id: 999, full_name: "Me Myself", }; const alice = { email: "alice@zulip.com", user_id: 1, full_name: "Alice Smith", }; const fred = { email: "fred@zulip.com", user_id: 2, full_name: "Fred Flintstone", }; const jill = { email: "jill@zulip.com", user_id: 3, full_name: "Jill Hill", }; const mark = { email: "mark@zulip.com", user_id: 4, full_name: "Marky Mark", }; const norbert = { email: "norbert@zulip.com", user_id: 5, full_name: "Norbert Oswald", }; const zoe = { email: "zoe@example.com", user_id: 6, full_name: "Zoe Yang", }; people.add_active_user(alice); people.add_active_user(fred); people.add_active_user(jill); people.add_active_user(mark); people.add_active_user(norbert); people.add_active_user(zoe); people.add_active_user(me); people.initialize_current_user(me.user_id); function clear_buddy_list() { buddy_list.populate({ keys: [], }); } function test(label, f) { run_test(label, (helpers) => { user_settings.presence_enabled = true; // Simulate a small window by having the // fill_screen_with_content render the entire // list in one pass. We will do more refined // testing in the buddy_list node tests. helpers.override(buddy_list, "fill_screen_with_content", () => { buddy_list.render_more({ chunk_size: 100, }); }); presence.presence_info.set(alice.user_id, {status: "active"}); presence.presence_info.set(fred.user_id, {status: "active"}); presence.presence_info.set(jill.user_id, {status: "active"}); presence.presence_info.set(mark.user_id, {status: "idle"}); presence.presence_info.set(norbert.user_id, {status: "active"}); presence.presence_info.set(zoe.user_id, {status: "active"}); presence.presence_info.set(me.user_id, {status: "active"}); clear_buddy_list(); muted_users.set_muted_users([]); activity.clear_for_testing(); activity.set_cursor_and_filter(); f(helpers); presence.clear_internal_data(); }); } run_test("reload_defaults", () => { activity.clear_for_testing(); blueslip.expect("warn", "get_filter_text() is called before initialization"); assert.equal(activity.get_filter_text(), ""); }); test("get_status", () => { page_params.realm_users = []; page_params.user_id = 999; assert.equal(presence.get_status(page_params.user_id), "active"); assert.equal(presence.get_status(alice.user_id), "active"); assert.equal(presence.get_status(mark.user_id), "idle"); assert.equal(presence.get_status(fred.user_id), "active"); user_settings.presence_enabled = false; assert.equal(presence.get_status(page_params.user_id), "offline"); user_settings.presence_enabled = true; assert.equal(presence.get_status(page_params.user_id), "active"); presence.presence_info.delete(zoe.user_id); assert.equal(presence.get_status(zoe.user_id), "offline"); presence.presence_info.set(alice.user_id, {status: "whatever"}); assert.equal(presence.get_status(alice.user_id), "whatever"); }); test("sort_users", () => { const user_ids = [alice.user_id, fred.user_id, jill.user_id]; presence.presence_info.delete(alice.user_id); buddy_data.sort_users(user_ids); assert.deepEqual(user_ids, [fred.user_id, jill.user_id, alice.user_id]); }); test("huddle_data.process_loaded_messages", () => { // TODO: move this to a module for just testing `huddle_data` const huddle1 = "jill@zulip.com,norbert@zulip.com"; const timestamp1 = 1382479029; // older const huddle2 = "alice@zulip.com,fred@zulip.com"; const timestamp2 = 1382479033; // newer const old_timestamp = 1382479000; const messages = [ { type: "private", display_recipient: [{id: jill.user_id}, {id: norbert.user_id}], timestamp: timestamp1, }, { type: "stream", }, { type: "private", display_recipient: [{id: me.user_id}], // PM to myself }, { type: "private", display_recipient: [{id: alice.user_id}, {id: fred.user_id}], timestamp: timestamp2, }, { type: "private", display_recipient: [{id: fred.user_id}, {id: alice.user_id}], timestamp: old_timestamp, }, ]; huddle_data.process_loaded_messages(messages); const user_ids_string1 = people.emails_strings_to_user_ids_string(huddle1); const user_ids_string2 = people.emails_strings_to_user_ids_string(huddle2); assert.deepEqual(huddle_data.get_huddles(), [user_ids_string2, user_ids_string1]); }); test("presence_list_full_update", ({override, mock_template}) => { override(padded_widget, "update_padding", () => {}); mock_template("presence_rows.hbs", false, (data) => { assert.equal(data.presence_rows.length, 7); assert.equal(data.presence_rows[0].user_id, me.user_id); }); $(".user-list-filter").trigger("focus"); compose_state.private_message_recipient = () => fred.email; compose_fade.set_focused_recipient("private"); const user_ids = activity.build_user_sidebar(); assert.deepEqual(user_ids, [ me.user_id, alice.user_id, fred.user_id, jill.user_id, norbert.user_id, zoe.user_id, mark.user_id, ]); }); function simulate_right_column_buddy_list() { $(".user-list-filter").closest = (selector) => { assert.equal(selector, ".app-main [class^='column-']"); return $.create("right-sidebar").addClass("column-right"); }; } function buddy_list_add(user_id, $stub) { if ($stub.attr) { $stub.attr("data-user-id", user_id); } $stub.length = 1; const sel = `li.user_sidebar_entry[data-user-id='${CSS.escape(user_id)}']`; $("#user_presences").set_find_results(sel, $stub); } test("PM_update_dom_counts", () => { const $count = $.create("alice-unread-count"); const pm_key = alice.user_id.toString(); const $li = $.create("alice stub"); buddy_list_add(pm_key, $li); $li.set_find_results(".unread_count", $count); $count.set_parents_result("li", $li); const counts = new Map(); counts.set(pm_key, 5); $li.addClass("user_sidebar_entry"); activity.update_dom_with_unread_counts({pm_count: counts}); assert.equal($count.text(), "5"); counts.set(pm_key, 0); activity.update_dom_with_unread_counts({pm_count: counts}); assert.equal($count.text(), ""); }); test("handlers", ({override, mock_template}) => { let filter_key_handlers; mock_template("presence_rows.hbs", false, () => {}); override(keydown_util, "handle", (opts) => { filter_key_handlers = opts.handlers; }); override(scroll_util, "scroll_element_into_container", () => {}); override(padded_widget, "update_padding", () => {}); override(popovers, "hide_all", () => {}); override(popovers, "hide_all_except_sidebars", () => {}); override(popovers, "show_userlist_sidebar", () => {}); override(resize, "resize_sidebars", () => {}); // This is kind of weak coverage; we are mostly making sure that // keys and clicks got mapped to functions that don't crash. let $me_li; let $alice_li; let $fred_li; let narrowed; override(narrow, "by", (method, email) => { assert.equal(email, "alice@zulip.com"); narrowed = true; }); function init() { $.clear_all_elements(); buddy_list.populate({ keys: [me.user_id, alice.user_id, fred.user_id], }); activity.set_cursor_and_filter(); $("#user_presences").empty = () => {}; $me_li = $.create("me stub"); $alice_li = $.create("alice stub"); $fred_li = $.create("fred stub"); buddy_list_add(me.user_id, $me_li); buddy_list_add(alice.user_id, $alice_li); buddy_list_add(fred.user_id, $fred_li); } (function test_filter_keys() { init(); activity.user_cursor.go_to(alice.user_id); filter_key_handlers.ArrowDown(); filter_key_handlers.ArrowUp(); })(); (function test_click_filter() { init(); const e = { stopPropagation: () => {}, }; const handler = $(".user-list-filter").get_on_handler("focus"); handler(e); })(); (function test_click_header_filter() { init(); const e = {}; const handler = $("#userlist-header").get_on_handler("click"); simulate_right_column_buddy_list(); handler(e); // and click again handler(e); })(); (function test_enter_key() { init(); $(".user-list-filter").val("al"); narrowed = false; activity.user_cursor.go_to(alice.user_id); filter_key_handlers.Enter(); assert.ok(narrowed); // get line coverage for cleared case activity.user_cursor.clear(); filter_key_handlers.Enter(); })(); (function test_click_handler() { init(); // We wire up the click handler in click_handlers.js, // so this just tests the called function. narrowed = false; activity.narrow_for_user({$li: $alice_li}); assert.ok(narrowed); })(); (function test_blur_filter() { init(); const e = {}; const handler = $(".user-list-filter").get_on_handler("blur"); handler(e); })(); }); test("first/prev/next", ({override, mock_template}) => { let rendered_alice; let rendered_fred; user_settings.user_list_style = 2; mock_template("presence_row.hbs", false, (data) => { switch (data.user_id) { case alice.user_id: rendered_alice = true; assert.deepEqual(data, { faded: true, href: "#narrow/pm-with/1-alice", is_current_user: false, my_user_status: undefined, name: "Alice Smith", num_unread: 0, user_circle_class: "user_circle_green", user_circle_status: "translated: Active", user_id: alice.user_id, status_emoji_info: undefined, status_text: undefined, user_list_style: { COMPACT: false, WITH_STATUS: true, WITH_AVATAR: false, }, }); break; case fred.user_id: rendered_fred = true; assert.deepEqual(data, { href: "#narrow/pm-with/2-fred", name: "Fred Flintstone", user_id: fred.user_id, my_user_status: undefined, is_current_user: false, num_unread: 0, user_circle_class: "user_circle_green", user_circle_status: "translated: Active", faded: false, status_emoji_info: undefined, status_text: undefined, user_list_style: { COMPACT: false, WITH_STATUS: true, WITH_AVATAR: false, }, }); break; /* istanbul ignore next */ default: throw new Error(`we did not expect to have to render a row for ${data.name}`); } }); override(padded_widget, "update_padding", () => {}); assert.equal(buddy_list.first_key(), undefined); assert.equal(buddy_list.prev_key(alice.user_id), undefined); assert.equal(buddy_list.next_key(alice.user_id), undefined); override(buddy_list.$container, "append", () => {}); activity.redraw_user(alice.user_id); activity.redraw_user(fred.user_id); assert.equal(buddy_list.first_key(), alice.user_id); assert.equal(buddy_list.prev_key(alice.user_id), undefined); assert.equal(buddy_list.prev_key(fred.user_id), alice.user_id); assert.equal(buddy_list.next_key(alice.user_id), fred.user_id); assert.equal(buddy_list.next_key(fred.user_id), undefined); assert.ok(rendered_alice); assert.ok(rendered_fred); }); test("insert_one_user_into_empty_list", ({override, mock_template}) => { user_settings.user_list_style = 2; mock_template("presence_row.hbs", true, (data, html) => { assert.deepEqual(data, { href: "#narrow/pm-with/1-alice", name: "Alice Smith", user_id: 1, my_user_status: undefined, is_current_user: false, num_unread: 0, user_circle_class: "user_circle_green", user_circle_status: "translated: Active", faded: true, status_emoji_info: undefined, status_text: undefined, user_list_style: { COMPACT: false, WITH_STATUS: true, WITH_AVATAR: false, }, }); assert.ok(html.startsWith("