const noop = function () {}; const return_true = function () { return true; }; set_global("$", global.make_zjquery()); const _settings_notifications = { update_page: () => {}, }; set_global("settings_notifications", _settings_notifications); zrequire("people"); zrequire("stream_data"); zrequire("stream_events"); zrequire("Filter", "js/filter"); zrequire("narrow_state"); zrequire("tab_bar"); const with_overrides = global.with_overrides; const george = { email: "george@zulip.com", full_name: "George", user_id: 103, }; people.add_active_user(george); const frontend = { subscribed: false, color: "yellow", name: "frontend", stream_id: 1, is_muted: true, invite_only: false, }; stream_data.add_sub(frontend); const frontend_filter_terms = [{operator: "stream", operand: "frontend"}]; const frontend_filter = new Filter(frontend_filter_terms); run_test("update_property", () => { // Invoke error for non-existent stream/property with_overrides((override) => { let errors = 0; override("blueslip.warn", () => { errors += 1; }); stream_events.update_property(99, "color", "blue"); assert.equal(errors, 1); stream_events.update_property(1, "not_real", 42); assert.equal(errors, 2); }); // Test update color with_overrides((override) => { global.with_stub((stub) => { override("stream_color.update_stream_color", stub.f); stream_events.update_property(1, "color", "blue"); const args = stub.get_args("sub", "val"); assert.equal(args.sub.stream_id, 1); assert.equal(args.val, "blue"); }); }); // Test in home view with_overrides((override) => { global.with_stub((stub) => { override("stream_muting.update_is_muted", stub.f); stream_events.update_property(1, "in_home_view", false); const args = stub.get_args("sub", "val"); assert.equal(args.sub.stream_id, 1); assert.equal(args.val, true); }); }); // Test desktop notifications stream_events.update_property(1, "desktop_notifications", true); assert.equal(frontend.desktop_notifications, true); let checkbox = $("#desktop_notifications_1"); assert.equal(checkbox.prop("checked"), true); // Tests audible notifications stream_events.update_property(1, "audible_notifications", true); assert.equal(frontend.audible_notifications, true); checkbox = $("#audible_notifications_1"); assert.equal(checkbox.prop("checked"), true); // Tests push notifications stream_events.update_property(1, "push_notifications", true); assert.equal(frontend.push_notifications, true); checkbox = $("#push_notifications_1"); assert.equal(checkbox.prop("checked"), true); // Tests email notifications stream_events.update_property(1, "email_notifications", true); assert.equal(frontend.email_notifications, true); checkbox = $("#email_notifications_1"); assert.equal(checkbox.prop("checked"), true); // Tests wildcard_mentions_notify notifications stream_events.update_property(1, "wildcard_mentions_notify", true); assert.equal(frontend.wildcard_mentions_notify, true); checkbox = $("#wildcard_mentions_notify_1"); assert.equal(checkbox.prop("checked"), true); // Test name change with_overrides((override) => { global.with_stub((stub) => { override("subs.update_stream_name", stub.f); stream_events.update_property(1, "name", "the frontend"); const args = stub.get_args("sub", "val"); assert.equal(args.sub.stream_id, 1); assert.equal(args.val, "the frontend"); }); }); // Test description change with_overrides((override) => { global.with_stub((stub) => { override("subs.update_stream_description", stub.f); stream_events.update_property(1, "description", "we write code", { rendered_description: "we write code", }); const args = stub.get_args("sub", "val"); assert.equal(args.sub.stream_id, 1); assert.equal(args.val, "we write code"); }); }); // Test email address change stream_events.update_property(1, "email_address", "zooly@zulip.com"); assert.equal(frontend.email_address, "zooly@zulip.com"); // Test pin to top with_overrides((override) => { override("stream_list.refresh_pinned_or_unpinned_stream", noop); stream_events.update_property(1, "pin_to_top", true); checkbox = $("#pin_to_top_1"); assert.equal(checkbox.prop("checked"), true); }); // Test stream privacy change event with_overrides((override) => { global.with_stub((stub) => { override("subs.update_stream_privacy", stub.f); stream_events.update_property(1, "invite_only", true, { history_public_to_subscribers: true, }); const args = stub.get_args("sub", "val"); assert.equal(args.sub.stream_id, 1); assert.deepEqual(args.val, { invite_only: true, history_public_to_subscribers: true, }); }); }); // Test stream stream_post_policy change event with_overrides((override) => { global.with_stub((stub) => { override("subs.update_stream_post_policy", stub.f); stream_events.update_property( 1, "stream_post_policy", stream_data.stream_post_policy_values.admins.code, ); const args = stub.get_args("sub", "val"); assert.equal(args.sub.stream_id, 1); assert.equal(args.val, stream_data.stream_post_policy_values.admins.code); }); }); // Test stream message_retention_days change event with_overrides((override) => { global.with_stub((stub) => { override("subs.update_message_retention_setting", stub.f); stream_events.update_property(1, "message_retention_days", 20); const args = stub.get_args("sub", "val"); assert.equal(args.sub.stream_id, 1); assert.equal(args.val, 20); }); }); }); run_test("marked_subscribed", () => { // Test undefined error with_overrides((override) => { let errors = 0; override("stream_color.update_stream_color", noop); override("blueslip.error", () => { errors += 1; }); stream_events.mark_subscribed(undefined, [], "yellow"); assert.equal(errors, 1); }); // Test early return if subscribed with_overrides((override) => { let completed = false; override("message_util.do_unread_count_updates", () => { completed = true; // This gets run if we continue and don't early return }); const subscribed = {subscribed: true}; stream_events.mark_subscribed(subscribed, [], "yellow"); assert.equal(completed, false); }); set_global("message_list", { all: { all_messages: function () { return ["msg"]; }, }, }); stream_data.subscribe_myself = noop; stream_data.set_subscribers = noop; stream_data.get_colors = noop; stream_data.update_calculated_fields = noop; set_global("subs", {update_settings_for_subscribed: noop}); set_global("overlays", {streams_open: return_true}); // Test basic dispatching and updating stream color narrow_state.set_current_filter(frontend_filter); with_overrides((override) => { let args; let list_updated = false; const stream_list_stub = global.make_stub(); const tab_bar_stub = global.make_stub(); const message_util_stub = global.make_stub(); override("stream_color.update_stream_color", noop); override("stream_list.add_sidebar_row", stream_list_stub.f); override("message_util.do_unread_count_updates", message_util_stub.f); override("tab_bar.render_title_area", tab_bar_stub.f); override("current_msg_list.update_trailing_bookend", () => { list_updated = true; }); stream_events.mark_subscribed(frontend, [], "blue"); args = message_util_stub.get_args("messages"); assert.deepEqual(args.messages, ["msg"]); args = stream_list_stub.get_args("sub"); assert.equal(args.sub.stream_id, 1); assert.equal(tab_bar_stub.num_calls, 1); assert.equal(list_updated, true); assert.equal(frontend.color, "blue"); }); narrow_state.reset_current_filter(); // Test assigning generated color with_overrides((override) => { frontend.color = undefined; override("color_data.pick_color", () => "green"); let warnings = 0; override("blueslip.warn", () => { warnings += 1; }); // narrow state is undefined global.with_stub((stub) => { override("message_util.do_unread_count_updates", noop); override("stream_list.add_sidebar_row", noop); override("stream_color.update_stream_color", noop); override("subs.set_color", stub.f); stream_events.mark_subscribed(frontend, [], undefined); const args = stub.get_args("id", "color"); assert.equal(args.id, 1); assert.equal(args.color, "green"); assert.equal(warnings, 1); }); }); // Test assigning subscriber emails // narrow state is undefined with_overrides((override) => { override("stream_color.update_stream_color", noop); override("message_util.do_unread_count_updates", noop); override("stream_list.add_sidebar_row", noop); global.with_stub((stub) => { override("stream_data.set_subscribers", stub.f); const user_ids = [15, 20, 25]; stream_events.mark_subscribed(frontend, user_ids, ""); const args = stub.get_args("sub", "subscribers"); assert.deepEqual(frontend, args.sub); assert.deepEqual(user_ids, args.subscribers); }); // assign self as well global.with_stub((stub) => { override("stream_data.subscribe_myself", stub.f); stream_events.mark_subscribed(frontend, [], ""); const args = stub.get_args("sub"); assert.deepEqual(frontend, args.sub); }); // and finally update subscriber settings global.with_stub((stub) => { override("subs.update_settings_for_subscribed", stub.f); stream_events.mark_subscribed(frontend, [], ""); const args = stub.get_args("sub"); assert.deepEqual(frontend, args.sub); }); }); }); run_test("mark_unsubscribed", () => { with_overrides((override) => { let removed_sub = false; override("stream_list.remove_sidebar_row", () => { removed_sub = true; }); // take no action if no sub specified stream_events.mark_unsubscribed(); assert.equal(removed_sub, false); // take no action if already unsubscribed frontend.subscribed = false; stream_events.mark_unsubscribed(frontend); assert.equal(removed_sub, false); }); // Test unsubscribe frontend.subscribed = true; with_overrides((override) => { global.with_stub((stub) => { override("stream_data.unsubscribe_myself", stub.f); override("subs.update_settings_for_unsubscribed", noop); override("stream_list.remove_sidebar_row", noop); stream_events.mark_unsubscribed(frontend); const args = stub.get_args("sub"); assert.deepEqual(args.sub, frontend); }); }); // Test update settings after unsubscribe with_overrides((override) => { global.with_stub((stub) => { override("subs.update_settings_for_unsubscribed", stub.f); override("stream_data.unsubscribe_myself", noop); override("stream_list.remove_sidebar_row", noop); stream_events.mark_unsubscribed(frontend); const args = stub.get_args("sub"); assert.deepEqual(args.sub, frontend); }); }); // Test update bookend and remove done event narrow_state.set_current_filter(frontend_filter); with_overrides((override) => { const tab_bar_stub = global.make_stub(); override("tab_bar.render_title_area", tab_bar_stub.f); override("stream_data.unsubscribe_myself", noop); override("subs.update_settings_for_unsubscribed", noop); let updated = false; override("current_msg_list.update_trailing_bookend", () => { updated = true; }); let event_triggered = false; override("stream_list.remove_sidebar_row", (stream_id) => { assert.equal(stream_id, frontend.stream_id); event_triggered = true; }); stream_events.mark_unsubscribed(frontend); assert.equal(tab_bar_stub.num_calls, 1); assert.equal(updated, true); assert.equal(event_triggered, true); }); narrow_state.reset_current_filter(); }); stream_data.clear_subscriptions(); const dev_help = { subscribed: true, color: "blue", name: "dev help", stream_id: 2, is_muted: true, invite_only: false, }; stream_data.add_sub(dev_help); run_test("remove_deactivated_user_from_all_streams", () => { const subs_stub = global.make_stub(); subs.update_subscribers_ui = subs_stub.f; dev_help.can_access_subscribers = true; // verify that deactivating user should unsubscribe user from all streams assert(stream_data.add_subscriber(dev_help.stream_id, george.user_id)); assert(dev_help.subscribers.has(george.user_id)); stream_events.remove_deactivated_user_from_all_streams(george.user_id); // verify that we issue a call to update subscriber count/list UI assert.equal(subs_stub.num_calls, 1); });