From 3d181a8ee1499ef2d825959ffaa53d7773a72a80 Mon Sep 17 00:00:00 2001 From: Sahil Batra Date: Wed, 6 Dec 2023 15:12:25 +0530 Subject: [PATCH] settings: Remove "User groups" panel from settings overlay. The "User groups" panel is now removed from settings overlay and we instead use new "#groups" UI. This commit also makes some changes to tests to ensure coverage for pill_typeahead.js which was previously done by settings_user_group_legacy.test.js. We have still not got complete coverage on user_pill.ts as we have removed settings_user_group_legacy.test.js, but we just add the file to EXEMPT_FILS list for now and will handle it in future. Fixes #28012. --- tools/test-js-with-node | 2 +- web/src/admin.js | 3 - web/src/server_events_dispatch.js | 2 - web/src/settings_sections.js | 3 - web/src/settings_user_groups_legacy.js | 407 --------- web/styles/dark_theme.css | 1 - web/styles/settings.css | 109 --- web/templates/settings/admin_tab.hbs | 2 - .../settings/admin_user_group_list.hbs | 27 - web/templates/settings/user_groups_admin.hbs | 28 - web/templates/settings_overlay.hbs | 6 - web/tests/dispatch.test.js | 5 +- web/tests/pill_typeahead.test.js | 9 +- web/tests/settings_user_groups_legacy.test.js | 854 ------------------ web/tests/user_pill.test.js | 4 + 15 files changed, 14 insertions(+), 1448 deletions(-) delete mode 100644 web/src/settings_user_groups_legacy.js delete mode 100644 web/templates/settings/admin_user_group_list.hbs delete mode 100644 web/templates/settings/user_groups_admin.hbs delete mode 100644 web/tests/settings_user_groups_legacy.test.js diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 1a4f5b22a4..d0af69e20e 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -215,7 +215,6 @@ EXEMPT_FILES = make_set( "web/src/settings_streams.js", "web/src/settings_toggle.js", "web/src/settings_ui.ts", - "web/src/settings_user_groups_legacy.js", "web/src/settings_user_topics.js", "web/src/settings_users.js", "web/src/setup.ts", @@ -269,6 +268,7 @@ EXEMPT_FILES = make_set( "web/src/user_group_popover.js", "web/src/user_group_ui_updates.js", "web/src/user_groups.ts", + "web/src/user_pill.ts", "web/src/user_profile.js", "web/src/user_settings.ts", "web/src/user_sort.ts", diff --git a/web/src/admin.js b/web/src/admin.js index b3b7e911ca..8cdda5dbdf 100644 --- a/web/src/admin.js +++ b/web/src/admin.js @@ -77,7 +77,6 @@ function insert_tip_box() { $(".organization-box") .find(".settings-section") .not("#emoji-settings") - .not("#user-groups-admin") .not("#organization-auth-settings") .not("#admin-bot-list") .not("#admin-invites-list") @@ -116,7 +115,6 @@ export function build_page() { realm_inline_url_embed_preview: page_params.realm_inline_url_embed_preview, server_inline_url_embed_preview: page_params.server_inline_url_embed_preview, realm_authentication_methods: page_params.realm_authentication_methods, - realm_user_group_edit_policy: page_params.realm_user_group_edit_policy, realm_name_changes_disabled: page_params.realm_name_changes_disabled, realm_email_changes_disabled: page_params.realm_email_changes_disabled, realm_avatar_changes_disabled: page_params.realm_avatar_changes_disabled, @@ -174,7 +172,6 @@ export function build_page() { can_create_multiuse_invite: settings_data.user_can_create_multiuse_invite(), can_invite_users_by_email: settings_data.user_can_invite_users_by_email(), realm_invite_required: page_params.realm_invite_required, - can_edit_user_groups: settings_data.user_can_edit_user_groups(), policy_values: settings_config.common_policy_values, realm_delete_own_message_policy: page_params.realm_delete_own_message_policy, DELETE_OWN_MESSAGE_POLICY_ADMINS_ONLY: diff --git a/web/src/server_events_dispatch.js b/web/src/server_events_dispatch.js index e3e51b88ab..f466ff3ea6 100644 --- a/web/src/server_events_dispatch.js +++ b/web/src/server_events_dispatch.js @@ -62,7 +62,6 @@ import * as settings_profile_fields from "./settings_profile_fields"; import * as settings_realm_domains from "./settings_realm_domains"; import * as settings_realm_user_settings_defaults from "./settings_realm_user_settings_defaults"; import * as settings_streams from "./settings_streams"; -import * as settings_user_groups_legacy from "./settings_user_groups_legacy"; import * as settings_users from "./settings_users"; import * as sidebar_ui from "./sidebar_ui"; import * as starred_messages from "./starred_messages"; @@ -882,7 +881,6 @@ export function dispatch_normal_event(event) { blueslip.error("Unexpected event type user_group/" + event.op); break; } - settings_user_groups_legacy.reload(); break; case "user_status": diff --git a/web/src/settings_sections.js b/web/src/settings_sections.js index 1fbc6aef3d..e82a0c45cc 100644 --- a/web/src/settings_sections.js +++ b/web/src/settings_sections.js @@ -15,7 +15,6 @@ import * as settings_playgrounds from "./settings_playgrounds"; import * as settings_profile_fields from "./settings_profile_fields"; import * as settings_realm_user_settings_defaults from "./settings_realm_user_settings_defaults"; import * as settings_streams from "./settings_streams"; -import * as settings_user_groups_legacy from "./settings_user_groups_legacy"; import * as settings_user_topics from "./settings_user_topics"; import * as settings_users from "./settings_users"; @@ -72,7 +71,6 @@ export function initialize() { load_func_dict.set("linkifier-settings", settings_linkifiers.set_up); load_func_dict.set("playground-settings", settings_playgrounds.set_up); load_func_dict.set("invites-list-admin", settings_invites.set_up); - load_func_dict.set("user-groups-admin", settings_user_groups_legacy.set_up); load_func_dict.set("profile-field-settings", settings_profile_fields.set_up); load_func_dict.set("data-exports-admin", settings_exports.set_up); load_func_dict.set( @@ -112,7 +110,6 @@ export function reset_sections() { settings_org.reset(); settings_profile_fields.reset(); settings_streams.reset(); - settings_user_groups_legacy.reset(); settings_user_topics.reset(); settings_muted_users.reset(); alert_words_ui.reset(); diff --git a/web/src/settings_user_groups_legacy.js b/web/src/settings_user_groups_legacy.js deleted file mode 100644 index 925316ce7a..0000000000 --- a/web/src/settings_user_groups_legacy.js +++ /dev/null @@ -1,407 +0,0 @@ -import $ from "jquery"; -import _ from "lodash"; - -import render_confirm_delete_user from "../templates/confirm_dialog/confirm_delete_user.hbs"; -import render_add_user_group_modal from "../templates/settings/add_user_group_modal.hbs"; -import render_admin_user_group_list from "../templates/settings/admin_user_group_list.hbs"; - -import * as channel from "./channel"; -import * as confirm_dialog from "./confirm_dialog"; -import * as dialog_widget from "./dialog_widget"; -import {$t, $t_html} from "./i18n"; -import * as keydown_util from "./keydown_util"; -import {page_params} from "./page_params"; -import * as people from "./people"; -import * as pill_typeahead from "./pill_typeahead"; -import * as settings_data from "./settings_data"; -import * as ui_report from "./ui_report"; -import * as user_groups from "./user_groups"; -import * as user_pill from "./user_pill"; - -const meta = { - loaded: false, -}; - -export function reset() { - meta.loaded = false; -} - -export function reload() { - if (!meta.loaded) { - return; - } - - const $user_groups_section = $("#user-groups").expectOne(); - $user_groups_section.empty(); - populate_user_groups(); -} - -export function can_edit(group_id) { - if (!settings_data.user_can_edit_user_groups()) { - return false; - } - - // Admins and moderators are allowed to edit user groups even if they - // are not a member of that user group. Members can edit user groups - // only if they belong to that group. - if (page_params.is_admin || page_params.is_moderator) { - return true; - } - - return user_groups.is_direct_member_of(people.my_current_user_id(), group_id); -} - -export function populate_user_groups() { - const $user_groups_section = $("#user-groups").expectOne(); - const user_groups_array = user_groups.get_realm_user_groups(); - - for (const data of user_groups_array) { - $user_groups_section.append( - render_admin_user_group_list({ - user_group: { - name: data.name, - id: data.id, - description: data.description, - }, - }), - ); - - const pill_config = { - show_user_status_emoji: false, - }; - - const $pill_container = $(`.pill-container[data-group-pills="${CSS.escape(data.id)}"]`); - const pills = user_pill.create_pills($pill_container, pill_config); - - function get_pill_user_ids() { - return user_pill.get_user_ids(pills); - } - - const $userg = $(`div.user-group[id="${CSS.escape(data.id)}"]`); - for (const user_id of data.members) { - const user = people.get_by_user_id(user_id); - user_pill.append_user(user, pills); - } - - function update_membership(group_id) { - if (can_edit(group_id)) { - return; - } - $userg.find(".name").attr("contenteditable", "false"); - $userg.find(".description").attr("contenteditable", "false"); - $userg.addClass("ntm"); - $pill_container.find(".input").attr("contenteditable", "false"); - $pill_container.find(".input").css("display", "none"); - $pill_container.addClass("not-editable"); - $pill_container.off("keydown", ".pill"); - $pill_container.off("keydown", ".input"); - $pill_container.off("click"); - $pill_container.on("click", (e) => { - e.stopPropagation(); - }); - $pill_container.find(".pill").on("mouseenter", () => { - $pill_container.find(".pill").find(".exit").css("opacity", "0.5"); - }); - } - update_membership(data.id); - - function is_user_group_changed() { - const draft_group = get_pill_user_ids(); - const group_data = user_groups.get_user_group_from_id(data.id); - const original_group = [...group_data.members]; - const same_groups = _.isEqual(_.sortBy(draft_group), _.sortBy(original_group)); - const description = $(`#user-groups #${CSS.escape(data.id)} .description`) - .text() - .trim(); - const name = $(`#user-groups #${CSS.escape(data.id)} .name`) - .text() - .trim(); - const $user_group_status = $(`#user-groups #${CSS.escape(data.id)} .user-group-status`); - - if ($user_group_status.is(":visible")) { - return false; - } - - if ( - group_data.description === description && - group_data.name === name && - (!draft_group.length || same_groups) - ) { - return false; - } - return true; - } - - function update_cancel_button() { - if (!can_edit(data.id)) { - return; - } - const $cancel_button = $( - `#user-groups #${CSS.escape(data.id)} .save-status.btn-danger`, - ); - const $saved_button = $(`#user-groups #${CSS.escape(data.id)} .save-status.sea-green`); - const $save_instructions = $(`#user-groups #${CSS.escape(data.id)} .save-instructions`); - - if (is_user_group_changed() && !$cancel_button.is(":visible")) { - $saved_button.fadeOut(0); - $cancel_button.css({display: "inline-block", opacity: "0"}).fadeTo(400, 1); - $save_instructions.css({display: "block", opacity: "0"}).fadeTo(400, 1); - } else if (!is_user_group_changed() && $cancel_button.is(":visible")) { - $cancel_button.fadeOut(); - $save_instructions.fadeOut(); - } - } - - function show_saved_button() { - const $cancel_button = $( - `#user-groups #${CSS.escape(data.id)} .save-status.btn-danger`, - ); - const $saved_button = $(`#user-groups #${CSS.escape(data.id)} .save-status.sea-green`); - const $save_instructions = $(`#user-groups #${CSS.escape(data.id)} .save-instructions`); - if (!$saved_button.is(":visible")) { - $cancel_button.fadeOut(0); - $save_instructions.fadeOut(0); - $saved_button - .css({display: "inline-block", opacity: "0"}) - .fadeTo(400, 1) - .delay(2000) - .fadeTo(400, 0); - } - } - - function save_members() { - const draft_group = get_pill_user_ids(); - const group_data = user_groups.get_user_group_from_id(data.id); - const original_group = [...group_data.members]; - const same_groups = _.isEqual(_.sortBy(draft_group), _.sortBy(original_group)); - if (!draft_group.length || same_groups) { - return; - } - const added = _.difference(draft_group, original_group); - const removed = _.difference(original_group, draft_group); - channel.post({ - url: "/json/user_groups/" + data.id + "/members", - data: { - add: JSON.stringify(added), - delete: JSON.stringify(removed), - }, - success() { - setTimeout(show_saved_button, 200); - }, - }); - } - - function save_name_desc() { - const $user_group_status = $(`#user-groups #${CSS.escape(data.id)} .user-group-status`); - const group_data = user_groups.get_user_group_from_id(data.id); - const description = $(`#user-groups #${CSS.escape(data.id)} .description`) - .text() - .trim(); - const name = $(`#user-groups #${CSS.escape(data.id)} .name`) - .text() - .trim(); - - if (group_data.description === description && group_data.name === name) { - return; - } - - channel.patch({ - url: "/json/user_groups/" + data.id, - data: { - name, - description, - }, - success() { - $user_group_status.hide(); - setTimeout(show_saved_button, 200); - }, - error(xhr) { - ui_report.error($t_html({defaultMessage: "Failed"}), xhr, $user_group_status); - update_cancel_button(); - $(`#user-groups #${CSS.escape(data.id)} .name`).text(group_data.name); - $(`#user-groups #${CSS.escape(data.id)} .description`).text( - group_data.description, - ); - }, - }); - } - - function do_not_blur(except_class, event) { - // Event generated from or inside the typeahead. - if ($(event.relatedTarget).closest(".typeahead").length) { - return true; - } - - if ($(event.relatedTarget).closest(`#user-groups #${CSS.escape(data.id)}`).length) { - return [".pill-container", ".name", ".description", ".input", ".delete"].some( - (class_name) => - class_name !== except_class && - $(event.relatedTarget).closest(class_name).length, - ); - } - return false; - } - - function auto_save(class_name, event) { - if (!can_edit(data.id)) { - return; - } - - if (do_not_blur(class_name, event)) { - return; - } - if ( - $(event.relatedTarget).closest(`#user-groups #${CSS.escape(data.id)}`) && - $(event.relatedTarget).closest(".save-status.btn-danger").length - ) { - reload(); - return; - } - save_name_desc(); - save_members(); - } - - $(`#user-groups #${CSS.escape(data.id)}`).on("blur", ".input", (event) => { - auto_save(".input", event); - }); - - $(`#user-groups #${CSS.escape(data.id)}`).on("blur", ".name", (event) => { - auto_save(".name", event); - }); - $(`#user-groups #${CSS.escape(data.id)}`).on("input", ".name", () => { - update_cancel_button(); - }); - - $(`#user-groups #${CSS.escape(data.id)}`).on("blur", ".description", (event) => { - auto_save(".description", event); - }); - $(`#user-groups #${CSS.escape(data.id)}`).on("input", ".description", () => { - update_cancel_button(); - }); - - const $input = $pill_container.children(".input"); - if (can_edit(data.id)) { - const opts = {update_func: update_cancel_button, user: true}; - pill_typeahead.set_up($input, pills, opts); - } - - if (can_edit(data.id)) { - pills.onPillRemove(() => { - // onPillRemove is fired before the pill is removed from - // the DOM. - update_cancel_button(); - setTimeout(() => { - $input.trigger("focus"); - }, 100); - }); - } - } -} - -export function add_user_group() { - const $user_group_status = $("#dialog_error"); - - const group = { - members: JSON.stringify([people.my_current_user_id()]), - }; - - for (const obj of $("#add-user-group-form").serializeArray()) { - if (obj.value.trim() === "") { - continue; - } - group[obj.name] = obj.value; - } - - channel.post({ - url: "/json/user_groups/create", - data: group, - success() { - $user_group_status.hide(); - ui_report.success($t_html({defaultMessage: "User group added!"}), $user_group_status); - dialog_widget.close(); - }, - error(xhr) { - $user_group_status.hide(); - ui_report.error($t_html({defaultMessage: "Failed"}), xhr, $user_group_status); - }, - }); -} - -function show_add_user_group_modal() { - const html_body = render_add_user_group_modal(); - - function add_user_group_post_render() { - const $add_user_group_input_element = $("#user_group_name"); - const $add_user_group_submit_button = $("#add-user-group-modal .dialog_submit_button"); - $add_user_group_submit_button.prop("disabled", true); - - $add_user_group_input_element.on("input", () => { - $add_user_group_submit_button.prop( - "disabled", - $add_user_group_input_element.val() === "", - ); - }); - } - - dialog_widget.launch({ - html_heading: $t_html({defaultMessage: "Add new user group"}), - html_body, - html_submit_button: $t_html({defaultMessage: "Save"}), - help_link: "/help/user-groups", - form_id: "add-user-group-form", - id: "add-user-group-modal", - on_click: add_user_group, - on_shown: () => $("#user_group_name").trigger("focus"), - post_render: add_user_group_post_render, - }); -} - -export function set_up() { - meta.loaded = true; - populate_user_groups(); - - $("#show-add-user-group-modal").on("click", (e) => { - e.preventDefault(); - e.stopPropagation(); - show_add_user_group_modal(); - }); - - $("#user-groups").on("click", ".delete", function () { - const group_id = Number.parseInt($(this).parents(".user-group").attr("id"), 10); - if (!can_edit(group_id)) { - return; - } - const user_group = user_groups.get_user_group_from_id(group_id); - const $btn = $(this); - - function delete_user_group() { - channel.del({ - url: "/json/user_groups/" + group_id, - data: { - id: group_id, - }, - error() { - $btn.text($t({defaultMessage: "Failed!"})); - }, - }); - } - - const html_body = render_confirm_delete_user({ - group_name: user_group.name, - }); - - const user_group_name = user_group.name; - - confirm_dialog.launch({ - html_heading: $t_html({defaultMessage: "Delete {user_group_name}?"}, {user_group_name}), - html_body, - on_click: delete_user_group, - }); - }); - - $("#user-groups").on("keypress", ".user-group h4 > span", (e) => { - if (keydown_util.is_enter_event(e)) { - e.preventDefault(); - } - }); -} diff --git a/web/styles/dark_theme.css b/web/styles/dark_theme.css index e1b9ce9180..924ac9371d 100644 --- a/web/styles/dark_theme.css +++ b/web/styles/dark_theme.css @@ -651,7 +651,6 @@ .clear_search_button:focus, .clear_search_button:active, .clear_search_button:disabled:hover, - #user-groups .save-instructions, .close { color: hsl(236deg 33% 80%); } diff --git a/web/styles/settings.css b/web/styles/settings.css index 44d230ed8a..79f6a6b737 100644 --- a/web/styles/settings.css +++ b/web/styles/settings.css @@ -687,19 +687,6 @@ input[type="checkbox"] { text-align: right; } -#show-add-user-group-modal { - margin-bottom: 10px; -} - -#add-user-group-form { - margin: 0; - - /* This 14px is the border and padding of the input element */ - #user_group_description { - width: calc(100% - 14px); - } -} - .add-new-export-box { margin: 10px 0; } @@ -1220,102 +1207,6 @@ $option_title_width: 180px; margin-right: 5px; } -#user-groups { - .user-group { - margin-bottom: 20px; - padding: 10px; - border-radius: 5px; - - & h4 { - font-weight: normal; - margin: 0; - display: flex; - align-items: center; - justify-content: left; - } - - & span[contenteditable] { - display: inline-block; - word-break: break-all; - - &:empty::before { - opacity: 0.5; - display: inline-block; - content: attr(data-placeholder); - } - } - - & span[contenteditable]:focus, - span[contenteditable="true"]:hover { - border-bottom: 1px solid hsl(0deg 0% 80%); - margin-bottom: -1px; - outline: none; - } - - .pill-container .input[contenteditable]:empty::after { - content: attr(data-placeholder); - opacity: 0.5; - } - } - - .user-group-status { - margin-bottom: 10px; - } - - & p { - line-height: 2; - margin: 0; - } - - .spacer { - margin: 0 2px; - } - - .subscribers, - .user-group h4 > .name { - font-weight: bold; - } - - .ntm { - cursor: not-allowed; - - & h4 > .button { - cursor: not-allowed; - display: none; - - &:hover { - border-color: hsl(4deg 56% 82%); - } - } - } - - .save-status { - background-color: transparent; - padding: 2px 5px; - border-radius: 4px; - margin-left: 10px; - border-style: solid; - border-width: 1px; - display: none; - opacity: 0; - } - - .checkmark { - height: 12px; - } - - .delete { - margin-left: auto; - } - - .save-instructions { - display: none; - opacity: 0; - color: hsl(0deg 0% 20%); - font-size: 0.9em; - } -} - /* -- new settings overlay -- */ #settings_page { height: 95vh; diff --git a/web/templates/settings/admin_tab.hbs b/web/templates/settings/admin_tab.hbs index 5548ad101e..6cfed7300b 100644 --- a/web/templates/settings/admin_tab.hbs +++ b/web/templates/settings/admin_tab.hbs @@ -29,8 +29,6 @@ {{> invites_list_admin }} -{{> user_groups_admin }} - {{> profile_field_settings_admin }} {{> data_exports_admin }} diff --git a/web/templates/settings/admin_user_group_list.hbs b/web/templates/settings/admin_user_group_list.hbs deleted file mode 100644 index f50389de19..0000000000 --- a/web/templates/settings/admin_user_group_list.hbs +++ /dev/null @@ -1,27 +0,0 @@ -{{#with user_group}} -
-
-

- {{name}} - — - {{description}} - - - -

-

{{t 'Subscribers' }}

-
-
-
-

- {{t "Click outside the input box to save. We'll automatically notify anyone that was added or removed."}} -

-
-{{/with}} diff --git a/web/templates/settings/user_groups_admin.hbs b/web/templates/settings/user_groups_admin.hbs deleted file mode 100644 index 92fe55656f..0000000000 --- a/web/templates/settings/user_groups_admin.hbs +++ /dev/null @@ -1,28 +0,0 @@ -
-
- {{#if (eq realm_user_group_edit_policy policy_values.by_members.code) }} -
{{t 'This organization is configured so that administrators, moderators and group members can modify user groups.' }}
- {{else if (eq realm_user_group_edit_policy policy_values.by_full_members.code) }} -
{{t 'This organization is configured so that administrators, moderators and full members belonging to the group can modify user groups.' }}
- {{else if (eq realm_user_group_edit_policy policy_values.by_moderators_only.code) }} -
{{t 'This organization is configured so that administrators and moderators can modify user groups.' }}
- {{else}} -
{{t 'This organization is configured so that only administrators can modify user groups.' }}
- {{/if}} -
- {{#unless is_guest}} -

- {{#tr}} - User groups allow you to mention multiple users at once. When you mention a user group, everyone in the group is notified as if they were individually mentioned. - {{#*inline "z-link"}}{{> @partial-block}}{{/inline}} - {{/tr}} -

- {{#if can_edit_user_groups}} - - {{/if}} - {{/unless}} - -
-
diff --git a/web/templates/settings_overlay.hbs b/web/templates/settings_overlay.hbs index bcafdf4d6a..f7ef6354e5 100644 --- a/web/templates/settings_overlay.hbs +++ b/web/templates/settings_overlay.hbs @@ -86,12 +86,6 @@ {{#unless is_guest}} -
  • - -
    {{t "User groups" }}
    -
  • - {{/unless}} - {{#unless is_guest}}
  • {{t "Users" }}
    diff --git a/web/tests/dispatch.test.js b/web/tests/dispatch.test.js index cc3e04f5c6..9751d7004e 100644 --- a/web/tests/dispatch.test.js +++ b/web/tests/dispatch.test.js @@ -63,7 +63,6 @@ const settings_realm_user_settings_defaults = mock_esm( ); const settings_realm_domains = mock_esm("../src/settings_realm_domains"); const settings_streams = mock_esm("../src/settings_streams"); -const settings_user_groups_legacy = mock_esm("../src/settings_user_groups_legacy"); const settings_users = mock_esm("../src/settings_users"); const sidebar_ui = mock_esm("../src/sidebar_ui"); const stream_data = mock_esm("../src/stream_data"); @@ -171,7 +170,6 @@ run_test("attachments", ({override}) => { run_test("user groups", ({override}) => { let event = event_fixtures.user_group__add; - override(settings_user_groups_legacy, "reload", noop); { const stub = make_stub(); const user_group_settings_ui_stub = make_stub(); @@ -1165,7 +1163,7 @@ run_test("realm_export", ({override}) => { assert.equal(args.exports, event.exports); }); -run_test("server_event_dispatch_op_errors", ({override}) => { +run_test("server_event_dispatch_op_errors", () => { blueslip.expect("error", "Unexpected event type subscription/other"); server_events_dispatch.dispatch_normal_event({type: "subscription", op: "other"}); blueslip.expect("error", "Unexpected event type reaction/other"); @@ -1190,7 +1188,6 @@ run_test("server_event_dispatch_op_errors", ({override}) => { sender: {user_id: 5}, op: "other", }); - override(settings_user_groups_legacy, "reload", noop); blueslip.expect("error", "Unexpected event type user_group/other"); server_events_dispatch.dispatch_normal_event({type: "user_group", op: "other"}); }); diff --git a/web/tests/pill_typeahead.test.js b/web/tests/pill_typeahead.test.js index b32916160a..03649acf2c 100644 --- a/web/tests/pill_typeahead.test.js +++ b/web/tests/pill_typeahead.test.js @@ -124,6 +124,11 @@ run_test("set_up", ({mock_template}) => { get_text_from_item: noop, }); + let update_func_called = false; + function update_func() { + update_func_called = true; + } + let opts = {}; $fake_input.typeahead = (config) => { assert.equal(config.items, 5); @@ -297,6 +302,8 @@ run_test("set_up", ({mock_template}) => { assert.equal(number_of_pills(), 2); config.updater.call(fake_group_this, testers); assert.equal(number_of_pills(), 3); + + assert.ok(update_func_called); } })(); @@ -324,7 +331,7 @@ run_test("set_up", ({mock_template}) => { {user_group: true, stream: true}, {user_group: true, user: true}, {user: true, stream: true}, - {user_group: true, stream: true, user: true}, + {user_group: true, stream: true, user: true, update_func}, ]; for (const config of all_possible_opts) { diff --git a/web/tests/settings_user_groups_legacy.test.js b/web/tests/settings_user_groups_legacy.test.js deleted file mode 100644 index dedcce4bfd..0000000000 --- a/web/tests/settings_user_groups_legacy.test.js +++ /dev/null @@ -1,854 +0,0 @@ -"use strict"; - -const {strict: assert} = require("assert"); - -const {$t} = require("./lib/i18n"); -const {mock_esm, set_global, zrequire} = require("./lib/namespace"); -const {run_test} = require("./lib/test"); -const blueslip = require("./lib/zblueslip"); -const $ = require("./lib/zjquery"); -const {page_params} = require("./lib/zpage_params"); - -const noop = () => {}; - -const pills = { - pill: {}, -}; - -let create_item_handler; - -const channel = mock_esm("../src/channel"); -const confirm_dialog = mock_esm("../src/confirm_dialog"); -const dialog_widget = mock_esm("../src/dialog_widget"); -const input_pill = mock_esm("../src/input_pill"); -const settings_data = mock_esm("../src/settings_data"); -const typeahead_helper = mock_esm("../src/typeahead_helper"); -const user_groups = mock_esm("../src/user_groups", { - get_user_group_from_id: noop, - remove: noop, - add: noop, -}); -const ui_report = mock_esm("../src/ui_report"); - -const people = zrequire("people"); -const settings_user_groups_legacy = zrequire("settings_user_groups_legacy"); -const user_pill = zrequire("user_pill"); - -function reset_test_setup($pill_container_stub) { - function input_pill_stub(opts) { - assert.equal(opts.$container, $pill_container_stub); - create_item_handler = opts.create_item_from_text; - assert.ok(create_item_handler); - return pills; - } - input_pill.create = input_pill_stub; -} - -function test_ui(label, f) { - // The sloppy_$ flag lets us reuse setup from prior tests. - run_test(label, f, {sloppy_$: true}); -} - -test_ui("can_edit", ({override}) => { - override(settings_data, "user_can_edit_user_groups", () => false); - assert.ok(!settings_user_groups_legacy.can_edit(1)); - - override(settings_data, "user_can_edit_user_groups", () => true); - user_groups.is_direct_member_of = (user_id, group_id) => { - assert.equal(group_id, 1); - assert.equal(user_id, undefined); - return false; - }; - assert.ok(!settings_user_groups_legacy.can_edit(1)); - - page_params.is_admin = true; - assert.ok(settings_user_groups_legacy.can_edit(1)); - - page_params.is_admin = false; - page_params.is_moderator = true; - assert.ok(settings_user_groups_legacy.can_edit(1)); - - page_params.is_admin = false; - page_params.is_moderator = false; - user_groups.is_direct_member_of = (user_id, group_id) => { - assert.equal(group_id, 1); - assert.equal(user_id, undefined); - return true; - }; - assert.ok(settings_user_groups_legacy.can_edit(1)); -}); - -const user_group_selector = `#user-groups #${CSS.escape(1)}`; -const cancel_selector = `#user-groups #${CSS.escape(1)} .save-status.btn-danger`; -const saved_selector = `#user-groups #${CSS.escape(1)} .save-status.sea-green`; -const name_selector = `#user-groups #${CSS.escape(1)} .name`; -const description_selector = `#user-groups #${CSS.escape(1)} .description`; -const instructions_selector = `#user-groups #${CSS.escape(1)} .save-instructions`; - -test_ui("populate_user_groups", ({mock_template, override, override_rewire}) => { - override(settings_data, "user_can_edit_user_groups", () => true); - - const realm_user_group = { - id: 1, - name: "Mobile", - description: "All mobile people", - members: new Set([2, 4]), - }; - const iago = { - email: "iago@zulip.com", - user_id: 2, - full_name: "Iago", - }; - const alice = { - email: "alice@example.com", - user_id: 31, - full_name: "Alice", - }; - const bob = { - email: "bob@example.com", - user_id: 32, - full_name: "Bob", - }; - - people.add_active_user(iago); - people.add_active_user(alice); - people.add_active_user(bob); - - override_rewire(people, "get_realm_users", () => [iago, alice, bob]); - - user_groups.get_realm_user_groups = () => [realm_user_group]; - - let templates_render_called = false; - const $fake_rendered_temp = $.create("fake_admin_user_group_list_template_rendered"); - mock_template("settings/admin_user_group_list.hbs", false, (args) => { - assert.equal(args.user_group.id, 1); - assert.equal(args.user_group.name, "Mobile"); - assert.equal(args.user_group.description, "All mobile people"); - templates_render_called = true; - return $fake_rendered_temp; - }); - - let user_groups_list_append_called = false; - $("#user-groups").append = (rendered_temp) => { - assert.equal(rendered_temp, $fake_rendered_temp); - user_groups_list_append_called = true; - }; - - let get_by_user_id_called = false; - override_rewire(people, "get_by_user_id", (user_id) => { - if (user_id === iago.user_id) { - return iago; - } - assert.equal(user_id, 4); - blueslip.expect("warn", "Undefined user in function append_user"); - get_by_user_id_called = true; - return undefined; - }); - override_rewire( - people, - "is_known_user", - () => people.get_by_user_id !== undefined && people.get_by_user_id !== noop, - ); - - page_params.is_admin = true; - - const all_pills = new Map(); - - const $pill_container_stub = $(`.pill-container[data-group-pills="${CSS.escape(1)}"]`); - pills.appendValidatedData = (item) => { - const id = item.user_id; - assert.ok(!all_pills.has(id)); - all_pills.set(id, item); - }; - pills.items = () => [...all_pills.values()]; - - let text_cleared; - pills.clear_text = () => { - text_cleared = true; - }; - - const $input_field_stub = $.create("fake-input-field"); - $pill_container_stub.children = () => $input_field_stub; - - let input_typeahead_called = false; - $input_field_stub.typeahead = (config) => { - assert.equal(config.items, 5); - assert.ok(config.fixed); - assert.ok(config.dropup); - assert.ok(config.stopAdvance); - assert.equal(typeof config.source, "function"); - assert.equal(typeof config.highlighter, "function"); - assert.equal(typeof config.matcher, "function"); - assert.equal(typeof config.sorter, "function"); - assert.equal(typeof config.updater, "function"); - - (function test_highlighter() { - const $fake_person = $.create("fake-person"); - typeahead_helper.render_person = () => $fake_person; - assert.equal(config.highlighter(), $fake_person); - })(); - - const fake_context = { - query: "ali", - }; - - const fake_context_for_email = { - query: "am", - }; - - (function test_source() { - const result = config.source.call(fake_context, iago); - const emails = result.map((user) => user.email).sort(); - assert.deepEqual(emails, [alice.email, bob.email]); - })(); - - (function test_matcher() { - /* Here the query doesn't begin with an '@' because typeahead is triggered - by the '@' sign and thus removed in the query. */ - let result = config.matcher.call(fake_context, iago); - assert.ok(!result); - - result = config.matcher.call(fake_context, alice); - assert.ok(result); - - bob.delivery_email = null; - result = config.matcher.call(fake_context_for_email, bob); - assert.ok(!result); - - bob.delivery_email = "bob-delivery@example.com"; - result = config.matcher.call(fake_context_for_email, bob); - assert.ok(result); - })(); - - (function test_sorter() { - let sort_recipients_typeahead_called = false; - typeahead_helper.sort_recipients = function () { - sort_recipients_typeahead_called = true; - }; - config.sorter.call(fake_context, []); - assert.ok(sort_recipients_typeahead_called); - })(); - - (function test_updater() { - $input_field_stub.text("@ali"); - user_groups.get_user_group_from_id = () => realm_user_group; - - let saved_fade_out_called = false; - let cancel_fade_to_called = false; - let instructions_fade_to_called = false; - $(saved_selector).fadeOut = () => { - saved_fade_out_called = true; - }; - $(cancel_selector).css = (data) => { - assert.equal(typeof data, "object"); - assert.equal(data.display, "inline-block"); - assert.equal(data.opacity, "0"); - return $(cancel_selector); - }; - $(cancel_selector).fadeTo = () => { - cancel_fade_to_called = true; - }; - $(instructions_selector).css = (data) => { - assert.equal(typeof data, "object"); - assert.equal(data.display, "block"); - assert.equal(data.opacity, "0"); - return $(instructions_selector); - }; - $(instructions_selector).fadeTo = () => { - instructions_fade_to_called = true; - }; - - text_cleared = false; - config.updater(alice); - // update_cancel_button is called. - assert.ok(saved_fade_out_called); - assert.ok(cancel_fade_to_called); - assert.ok(instructions_fade_to_called); - assert.equal(text_cleared, true); - })(); - input_typeahead_called = true; - }; - - let get_by_email_called = false; - override_rewire(people, "get_by_email", (user_email) => { - get_by_email_called = true; - switch (user_email) { - case iago.email: - return iago; - case bob.email: - return bob; - /* istanbul ignore next */ - default: - throw new Error("Expected user email to be of Iago or Bob here."); - } - }); - - function test_create_item(handler) { - (function test_rejection_path() { - const item = handler(iago.email, pills.items()); - assert.ok(get_by_email_called); - assert.equal(item, undefined); - })(); - - (function test_success_path() { - get_by_email_called = false; - const res = handler(bob.email, pills.items()); - assert.ok(get_by_email_called); - assert.equal(typeof res, "object"); - assert.equal(res.user_id, bob.user_id); - assert.equal(res.display_value, bob.full_name); - })(); - - (function test_deactivated_pill() { - people.deactivate(bob); - get_by_email_called = false; - const res = handler(bob.email, pills.items()); - assert.ok(get_by_email_called); - assert.equal(typeof res, "object"); - assert.equal(res.user_id, bob.user_id); - assert.equal(res.display_value, bob.full_name); - assert.ok(res.deactivated); - people.add_active_user(bob); - })(); - } - - pills.onPillRemove = (handler) => { - set_global("setTimeout", (func) => { - func(); - }); - realm_user_group.members = new Set([2, 31]); - handler(); - }; - - reset_test_setup($pill_container_stub); - settings_user_groups_legacy.set_up(); - assert.ok(templates_render_called); - assert.ok(user_groups_list_append_called); - assert.ok(get_by_user_id_called); - assert.ok(input_typeahead_called); - test_create_item(create_item_handler); - - // Tests for settings_user_groups_legacy.set_up workflow. - assert.equal(typeof $("#user-groups").get_on_handler("click", ".delete"), "function"); - assert.equal( - typeof $("#user-groups").get_on_handler("keypress", ".user-group h4 > span"), - "function", - ); -}); -test_ui("with_external_user", ({disallow_rewire, override_rewire, mock_template}) => { - const realm_user_group = { - id: 1, - name: "Mobile", - description: "All mobile people", - members: new Set([2, 4]), - }; - - user_groups.get_realm_user_groups = () => [realm_user_group]; - - // These are already tested, so we skip them - disallow_rewire(people, "get_realm_users"); - - mock_template( - "settings/admin_user_group_list.hbs", - false, - () => "settings/admin_user_group_list.hbs", - ); - - override_rewire(people, "get_by_user_id", () => "user stub"); - - override_rewire(user_pill, "append_person", noop); - - let can_edit_called = 0; - override_rewire(settings_user_groups_legacy, "can_edit", () => { - can_edit_called += 1; - return false; - }); - - // Reset zjquery to test stuff with user who cannot edit - $.clear_all_elements(); - - let user_group_find_called = 0; - const $user_group_stub = $(`div.user-group[id="${CSS.escape(1)}"]`); - const $name_field_stub = $.create("fake-name-field"); - const $description_field_stub = $.create("fake-description-field"); - const $input_stub = $.create("fake-input"); - $user_group_stub.find = (elem) => { - user_group_find_called += 1; - switch (elem) { - case ".name": - return $name_field_stub; - case ".description": - return $description_field_stub; - /* istanbul ignore next */ - default: - throw new Error(`Unknown element ${elem}`); - } - }; - - const $pill_container_stub = $(`.pill-container[data-group-pills="${CSS.escape(1)}"]`); - const $pill_stub = $.create("fake-pill"); - let pill_container_find_called = 0; - $pill_container_stub.find = (elem) => { - pill_container_find_called += 1; - switch (elem) { - case ".input": - return $input_stub; - case ".pill": - return $pill_stub; - /* istanbul ignore next */ - default: - throw new Error(`Unknown element ${elem}`); - } - }; - - $input_stub.css = (property, val) => { - assert.equal(property, "display"); - assert.equal(val, "none"); - }; - - // Test the 'off' handlers on the pill-container - const turned_off = {}; - $pill_container_stub.off = (event_name, sel = "whole") => { - turned_off[event_name + "/" + sel] = true; - }; - - const $exit_button = $.create("fake-pill-exit"); - $pill_stub.set_find_results(".exit", $exit_button); - let exit_button_called = false; - $exit_button.css = (property, value) => { - exit_button_called = true; - assert.equal(property, "opacity"); - assert.equal(value, "0.5"); - }; - - // We return [] because these are already tested, so we skip them - $pill_container_stub.children = () => []; - - $("#user-groups").append = noop; - - reset_test_setup($pill_container_stub); - - settings_user_groups_legacy.set_up(); - - let set_parents_result_called = 0; - let set_attributes_called = 0; - - // Test different handlers with an external user - const delete_handler = $("#user-groups").get_on_handler("click", ".delete"); - const $fake_delete = $.create("fk-#user-groups.delete_btn"); - $fake_delete.set_parents_result(".user-group", $(".user-group")); - set_parents_result_called += 1; - $(".user-group").attr("id", "1"); - set_attributes_called += 1; - - const name_update_handler = $(user_group_selector).get_on_handler("input", ".name"); - - const des_update_handler = $(user_group_selector).get_on_handler("input", ".description"); - - const member_change_handler = $(user_group_selector).get_on_handler("blur", ".input"); - - const name_change_handler = $(user_group_selector).get_on_handler("blur", ".name"); - - const des_change_handler = $(user_group_selector).get_on_handler("blur", ".description"); - - const event = { - stopPropagation: noop, - }; - const pill_mouseenter_handler = $pill_stub.get_on_handler("mouseenter"); - const pill_click_handler = $pill_container_stub.get_on_handler("click"); - pill_mouseenter_handler(event); - pill_click_handler(event); - assert.equal(delete_handler.call($fake_delete), undefined); - assert.equal(name_update_handler(), undefined); - assert.equal(des_update_handler(), undefined); - assert.equal(member_change_handler(), undefined); - assert.equal(name_change_handler(), undefined); - assert.equal(des_change_handler(), undefined); - assert.equal(set_parents_result_called, 1); - assert.equal(set_attributes_called, 1); - assert.equal(can_edit_called, 9); - assert.ok(exit_button_called); - assert.equal(user_group_find_called, 2); - assert.equal(pill_container_find_called, 4); - assert.equal(turned_off["keydown/.pill"], true); - assert.equal(turned_off["keydown/.input"], true); - assert.equal(turned_off["click/whole"], true); -}); - -test_ui("reload", ({override_rewire}) => { - $("#user-groups").html("Some text"); - let populate_user_groups_called = false; - override_rewire(settings_user_groups_legacy, "populate_user_groups", () => { - populate_user_groups_called = true; - }); - settings_user_groups_legacy.reload(); - assert.ok(populate_user_groups_called); - assert.equal($("#user-groups").html(), ""); -}); - -test_ui("reset", () => { - settings_user_groups_legacy.reset(); - const result = settings_user_groups_legacy.reload(); - assert.equal(result, undefined); -}); - -test_ui("on_events", ({mock_template, override, override_rewire}) => { - override(settings_data, "user_can_edit_user_groups", () => true); - mock_template("confirm_dialog/confirm_delete_user.hbs", false, (data) => { - assert.deepEqual(data, { - group_name: "Mobile", - }); - return "stub"; - }); - - page_params.is_admin = true; - - (function test_admin_user_group_form_submit_triggered() { - const handler = settings_user_groups_legacy.add_user_group; - const event = { - stopPropagation: noop, - preventDefault: noop, - }; - const $fake_this = $.create("#add-user-group-form"); - const fake_object_array = [ - { - name: "fake-name", - value: "", - }, - { - name: "fake-name", - value: "fake-value", - }, - ]; - $fake_this.serializeArray = () => fake_object_array; - channel.post = (opts) => { - const data = { - members: "[null]", - }; - data[fake_object_array[1].name] = fake_object_array[1].value; - assert.equal(opts.url, "/json/user_groups/create"); - assert.deepEqual(opts.data, data); - - (function test_post_success() { - $("#dialog_error").show(); - $("#add-user-group-form input[type='text']").val("fake-content"); - ui_report.success = (text, ele) => { - assert.equal(text, "translated HTML: User group added!"); - assert.equal(ele, $("#dialog_error")); - }; - dialog_widget.close = () => {}; - - opts.success(); - - assert.ok(!$("#dialog_error").visible()); - })(); - (function test_post_error() { - $("#dialog_error").show(); - ui_report.error = (error_msg, error_obj, ele) => { - assert.equal(error_msg, "translated HTML: Failed"); - assert.deepEqual(error_obj, {responseJson: {msg: "fake-msg"}}); - assert.equal(ele, $("#dialog_error")); - }; - opts.error({responseJson: {msg: "fake-msg"}}); - - assert.ok(!$("#dialog_error").visible()); - })(); - }; - - handler(event); - })(); - - (function test_user_groups_delete_click_triggered() { - const handler = $("#user-groups").get_on_handler("click", ".delete"); - const $fake_this = $.create("fake-#user-groups.delete_btn"); - $fake_this.set_parents_result(".user-group", $(".user-group")); - $(".user-group").attr("id", "1"); - - channel.del = (opts) => { - const data = { - id: 1, - }; - assert.equal(opts.url, "/json/user_groups/1"); - assert.deepEqual(opts.data, data); - - $fake_this.text($t({defaultMessage: "fake-text"})); - opts.error(); - assert.equal($fake_this.text(), "translated: Failed!"); - }; - - confirm_dialog.launch = (conf) => { - conf.on_click(); - }; - - handler.call($fake_this); - })(); - - (function test_user_groups_keypress_enter_triggered() { - const handler = $("#user-groups").get_on_handler("keypress", ".user-group h4 > span"); - let default_action_for_enter_stopped = false; - const event = { - key: "Enter", - preventDefault() { - default_action_for_enter_stopped = true; - }, - }; - handler(event); - assert.ok(default_action_for_enter_stopped); - })(); - - (function test_do_not_blur() { - const blur_event_classes = [".name", ".description", ".input"]; - let api_endpoint_called = false; - /* istanbul ignore next */ - channel.post = () => { - api_endpoint_called = true; - }; - channel.patch = noop; - const $fake_this = $.create("fake-#user-groups_do_not_blur"); - const event = { - // FIXME: event.relatedTarget should not be a jQuery object - relatedTarget: $fake_this, - }; - - // Any of the blur_exceptions trigger blur event. - for (const class_name of blur_event_classes) { - const handler = $(user_group_selector).get_on_handler("blur", class_name); - - for (const blur_exception of [ - ".pill-container", - ".name", - ".description", - ".input", - ".delete", - ]) { - if (blur_exception === class_name) { - continue; - } - api_endpoint_called = false; - $fake_this.closest = (class_name) => { - if (class_name === blur_exception || class_name === user_group_selector) { - return [1]; - } - return []; - }; - handler.call($fake_this, event); - assert.ok(!api_endpoint_called); - } - - api_endpoint_called = false; - $fake_this.closest = (class_name) => { - assert.equal(class_name, ".typeahead"); - return [1]; - }; - handler.call($fake_this, event); - assert.ok(!api_endpoint_called); - - // Cancel button triggers blur event. - let settings_user_groups_legacy_reload_called = false; - override_rewire(settings_user_groups_legacy, "reload", () => { - settings_user_groups_legacy_reload_called = true; - }); - api_endpoint_called = false; - $fake_this.closest = (class_name) => { - if ( - class_name === ".save-status.btn-danger" || - class_name === user_group_selector - ) { - return [1]; - } - return []; - }; - handler.call($fake_this, event); - assert.ok(!api_endpoint_called); - assert.ok(settings_user_groups_legacy_reload_called); - } - })(); - - (function test_update_cancel_button() { - const handler_name = $(user_group_selector).get_on_handler("input", ".name"); - const handler_desc = $(user_group_selector).get_on_handler("input", ".description"); - const $sib_des = $(description_selector); - const $sib_name = $(name_selector); - $sib_name.text($t({defaultMessage: "mobile"})); - $sib_des.text($t({defaultMessage: "All mobile members"})); - - const group_data = { - name: "translated: mobile", - description: "translated: All mobile members", - members: new Set([2, 31]), - }; - user_groups.get_user_group_from_id = () => group_data; - - let cancel_fade_out_called = false; - let instructions_fade_out_called = false; - $(cancel_selector).show(); - $(cancel_selector).fadeOut = () => { - cancel_fade_out_called = true; - }; - $(instructions_selector).fadeOut = () => { - instructions_fade_out_called = true; - }; - - // Cancel button removed if user group if user group has no changes. - const $fake_this = $.create("fake-#update_cancel_button"); - handler_name.call($fake_this); - assert.ok(cancel_fade_out_called); - assert.ok(instructions_fade_out_called); - - // Check if cancel button removed if user group error is showing. - $(user_group_selector + " .user-group-status").show(); - cancel_fade_out_called = false; - instructions_fade_out_called = false; - handler_name.call($fake_this); - assert.ok(cancel_fade_out_called); - assert.ok(instructions_fade_out_called); - - // Check for handler_desc to achieve 100% coverage. - cancel_fade_out_called = false; - instructions_fade_out_called = false; - handler_desc.call($fake_this); - assert.ok(cancel_fade_out_called); - assert.ok(instructions_fade_out_called); - })(); - - (function test_user_groups_save_group_changes_triggered() { - const handler_name = $(user_group_selector).get_on_handler("blur", ".name"); - const handler_desc = $(user_group_selector).get_on_handler("blur", ".description"); - const $sib_des = $(description_selector); - const $sib_name = $(name_selector); - $sib_name.text($t({defaultMessage: "mobile"})); - $sib_des.text($t({defaultMessage: "All mobile members"})); - - const group_data = {members: new Set([2, 31])}; - user_groups.get_user_group_from_id = () => group_data; - let api_endpoint_called = false; - let cancel_fade_out_called = false; - let saved_fade_to_called = false; - let instructions_fade_out_called = false; - $(instructions_selector).fadeOut = () => { - instructions_fade_out_called = true; - }; - $(cancel_selector).fadeOut = () => { - cancel_fade_out_called = true; - }; - $(saved_selector).css = (data) => { - assert.equal(typeof data, "object"); - assert.equal(data.display, "inline-block"); - assert.equal(data.opacity, "0"); - return $(saved_selector); - }; - $(saved_selector).fadeTo = () => { - saved_fade_to_called = true; - return $(saved_selector); - }; - - channel.patch = (opts) => { - assert.equal(opts.url, "/json/user_groups/1"); - assert.equal(opts.data.name, "translated: mobile"); - assert.equal(opts.data.description, "translated: All mobile members"); - api_endpoint_called = true; - (function test_post_success() { - set_global("setTimeout", (func) => { - func(); - }); - opts.success(); - assert.ok(cancel_fade_out_called); - assert.ok(instructions_fade_out_called); - assert.ok(saved_fade_to_called); - })(); - (function test_post_error() { - const $user_group_error = $(user_group_selector + " .user-group-status"); - $user_group_error.show(); - ui_report.error = (error_msg, error_obj, ele) => { - assert.equal(error_msg, "translated HTML: Failed"); - assert.deepEqual(error_obj, {responseJson: {msg: "fake-msg"}}); - assert.equal(ele, $user_group_error); - }; - opts.error({responseJson: {msg: "fake-msg"}}); - - assert.ok($user_group_error.visible()); - })(); - }; - - const $fake_this = $.create("fake-#user-groups_blur_name"); - $fake_this.closest = () => []; - $fake_this.set_parents_result(user_group_selector, $(user_group_selector)); - const event = { - // FIXME: event.relatedTarget should not be a jQuery object - relatedTarget: $fake_this, - }; - - api_endpoint_called = false; - handler_name.call($fake_this, event); - assert.ok(api_endpoint_called); - - // Check API endpoint isn't called if name and desc haven't changed. - group_data.name = "translated: mobile"; - group_data.description = "translated: All mobile members"; - api_endpoint_called = false; - handler_name.call($fake_this, event); - assert.ok(!api_endpoint_called); - - // Check for handler_desc to achieve 100% coverage. - api_endpoint_called = false; - handler_desc.call($fake_this, event); - assert.ok(!api_endpoint_called); - })(); - - (function test_user_groups_save_member_changes_triggered() { - const handler = $(user_group_selector).get_on_handler("blur", ".input"); - const realm_user_group = { - id: 1, - name: "Mobile", - description: "All mobile people", - members: new Set([2, 4]), - }; - - user_groups.get_user_group_from_id = (id) => { - assert.equal(id, 1); - return realm_user_group; - }; - - let cancel_fade_out_called = false; - let saved_fade_to_called = false; - let instructions_fade_out_called = false; - $(instructions_selector).fadeOut = () => { - instructions_fade_out_called = true; - }; - $(cancel_selector).fadeOut = () => { - cancel_fade_out_called = true; - }; - $(saved_selector).css = () => $(saved_selector); - $(saved_selector).fadeTo = () => { - saved_fade_to_called = true; - return $(saved_selector); - }; - - let api_endpoint_called = false; - channel.post = (opts) => { - assert.equal(opts.url, "/json/user_groups/1/members"); - assert.equal(opts.data.add, "[31]"); - assert.equal(opts.data.delete, "[4]"); - api_endpoint_called = true; - - (function test_post_success() { - opts.success(); - assert.ok(cancel_fade_out_called); - assert.ok(instructions_fade_out_called); - assert.ok(saved_fade_to_called); - })(); - }; - - const $fake_this = $.create("fake-#user-groups_blur_input"); - $fake_this.set_parents_result(user_group_selector, $(user_group_selector)); - $fake_this.closest = () => []; - const event = { - // FIXME: event.relatedTarget should not be a jQuery object - relatedTarget: $fake_this, - }; - - api_endpoint_called = false; - handler.call($fake_this, event); - assert.ok(api_endpoint_called); - })(); -}); diff --git a/web/tests/user_pill.test.js b/web/tests/user_pill.test.js index 8d6565172e..ab4249d721 100644 --- a/web/tests/user_pill.test.js +++ b/web/tests/user_pill.test.js @@ -4,6 +4,7 @@ const {strict: assert} = require("assert"); const {zrequire} = require("./lib/namespace"); const {run_test} = require("./lib/test"); +const blueslip = require("./lib/zblueslip"); const {page_params} = require("./lib/zpage_params"); const people = zrequire("people"); @@ -102,6 +103,9 @@ test("append", () => { assert.ok(appended); assert.ok(cleared); + + blueslip.expect("warn", "Undefined user in function append_user"); + user_pill.append_user(undefined, pill_widget); }); test("get_items", () => {