Files
upstream-zulip/web/tests/compose_pm_pill.test.cjs
upstream-mirror 64898b2c79
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
2026-09-15 15:05:30 +05:00

301 lines
9.3 KiB
JavaScript

"use strict";
const assert = require("node:assert/strict");
const {make_realm} = require("./lib/example_realm.cjs");
const {make_user} = require("./lib/example_user.cjs");
const {mock_esm, zrequire} = require("./lib/namespace.cjs");
const {run_test} = require("./lib/test.cjs");
const {$} = require("./lib/zjquery.cjs");
const input_pill = mock_esm("../src/input_pill");
const people = zrequire("people");
const compose_pm_pill = zrequire("compose_pm_pill");
const {set_realm} = zrequire("state_data");
set_realm(make_realm());
let pills = {
pill: {},
};
run_test("pills", ({override}) => {
const me = make_user({
email: "me@example.com",
user_id: 30,
full_name: "Me Myself",
});
const othello = make_user({
email: "othello@example.com",
user_id: 1,
full_name: "Othello",
});
const iago = make_user({
email: "iago@zulip.com",
user_id: 2,
full_name: "Iago",
});
const hamlet = make_user({
email: "hamlet@example.com",
user_id: 3,
full_name: "Hamlet",
});
people.initialize_current_user(me.user_id);
people.add_active_user(me);
people.add_active_user(othello);
people.add_active_user(iago);
people.add_active_user(hamlet);
const $recipient_stub = $("#private_message_recipient");
const $pill_container_stub = $.create("pill-container-stub");
$recipient_stub.set_parent($pill_container_stub);
let create_item_handler;
const all_pills = new Map();
pills.appendValidatedData = (item) => {
const id = item.user_id;
assert.ok(!all_pills.has(id));
all_pills.set(id, item);
};
pills.items = () => all_pills.values().toArray();
pills.clear_text = () => {};
pills.clear = () => {
pills = {
pill: {},
};
all_pills.clear();
};
function test_create_item(handler) {
(function test_rejection_path() {
const item = handler(othello.user_id, pills.items());
assert.equal(item, undefined);
})();
(function test_success_path() {
const res = handler(iago.user_id, pills.items());
assert.equal(typeof res, "object");
assert.equal(res.user_id, iago.user_id);
assert.equal(res.full_name, iago.full_name);
})();
(function test_deactivated_pill() {
people.deactivate(iago);
const res = handler(iago.user_id, pills.items());
assert.equal(typeof res, "object");
assert.equal(res.user_id, iago.user_id);
assert.equal(res.full_name, iago.full_name);
assert.ok(res.deactivated);
people.add_active_user(iago);
})();
}
function input_pill_stub(opts) {
assert.equal(opts.$container[0], $pill_container_stub[0]);
create_item_handler = opts.create_item_from_text;
assert.ok(create_item_handler);
return pills;
}
override(input_pill, "create", input_pill_stub);
// We stub the return value of input_pill.create(), manually add widget functions to it.
pills.onPillCreate = (callback) => {
callback();
};
pills.onPillRemove = (callback) => {
callback();
};
let on_pill_create_or_remove_call_count = 0;
compose_pm_pill.initialize({
on_pill_create_or_remove() {
on_pill_create_or_remove_call_count += 1;
},
});
assert.ok(compose_pm_pill.widget);
// Called two times via our overridden onPillCreate and onPillRemove methods.
// Normally these would be called via `set_from_typeahead` method.
assert.equal(on_pill_create_or_remove_call_count, 2);
compose_pm_pill.set_from_typeahead(othello);
compose_pm_pill.set_from_typeahead(hamlet);
let user_ids = compose_pm_pill.get_user_ids();
assert.deepEqual(user_ids, [othello.user_id, hamlet.user_id]);
const user_ids_string = compose_pm_pill.get_user_ids_string();
assert.equal(user_ids_string, "1,3");
const emails = compose_pm_pill.get_emails();
assert.equal(emails, "othello@example.com,hamlet@example.com");
const persons = [othello, iago, hamlet];
const items = compose_pm_pill.filter_taken_users(persons);
assert.deepEqual(items, [iago]);
test_create_item(create_item_handler);
compose_pm_pill.clear();
compose_pm_pill.set_from_typeahead(me);
compose_pm_pill.set_from_typeahead(othello);
user_ids = compose_pm_pill.get_user_ids();
assert.deepEqual(user_ids, [othello.user_id]);
compose_pm_pill.set_from_user_ids([hamlet.user_id], true);
user_ids = compose_pm_pill.get_user_ids();
assert.deepEqual(user_ids, [hamlet.user_id]);
});
run_test("has_unconverted_data", ({override}) => {
override(compose_pm_pill.widget, "is_pending", () => true);
// If the pill itself has pending data, we have unconverted
// data.
assert.equal(compose_pm_pill.has_unconverted_data(), true);
override(compose_pm_pill.widget, "is_pending", () => false);
override(compose_pm_pill.widget, "items", () => [{user_id: 99}]);
// Our pill is complete and all items contain user_id, so
// we do NOT have unconverted data.
assert.equal(compose_pm_pill.has_unconverted_data(), false);
override(compose_pm_pill.widget, "items", () => [{user_id: 99}, {email: "random@mit.edu"}]);
// One of our items only knows email (as in a bridge
// scenario where we might not have registered the user yet), so
// we have some unconverted data.
assert.equal(compose_pm_pill.has_unconverted_data(), true);
});
run_test("update_user_pill_active_status", ({override_rewire}) => {
const othello = make_user({
email: "othello@example.com",
user_id: 1,
full_name: "Othello",
is_active: true,
});
const inaccessible_user = make_user({
email: "iago@zulip.com",
user_id: 2,
full_name: "Iago",
is_active: false,
is_inaccessible_user: true,
});
// Test with uninitialized widget - should return early without error
override_rewire(compose_pm_pill, "widget", undefined);
// No assertions needed - we're just checking it doesn't throw
compose_pm_pill.update_user_pill_active_status(othello, false);
// Set up test data for normal widget tests
const pills_data = [
{
item: {user_id: othello.user_id, full_name: othello.full_name},
$element: {0: {id: "pill_1"}},
},
{
item: {user_id: inaccessible_user.user_id, full_name: inaccessible_user.full_name},
$element: {0: {id: "pill_2"}},
},
];
let pill_updated = false;
const widget = {
getPillByPredicate(predicate) {
return pills_data.find((p) => predicate(p.item));
},
updatePill(element, item) {
const pill = pills_data.find((p) => p.$element[0] === element);
pill.item = item;
pill_updated = true;
},
};
override_rewire(compose_pm_pill, "widget", widget);
// Test deactivating a user - should set deactivated to true
compose_pm_pill.update_user_pill_active_status(othello, false);
assert.deepEqual(pills_data[0].item, {
user_id: othello.user_id,
full_name: othello.full_name,
deactivated: true,
});
assert.ok(pill_updated);
// Reset for next test
pill_updated = false;
// Test reactivating a user - should set deactivated to false
compose_pm_pill.update_user_pill_active_status(othello, true);
assert.deepEqual(pills_data[0].item, {
user_id: othello.user_id,
full_name: othello.full_name,
deactivated: false,
});
assert.ok(pill_updated);
// Reset for next test
pill_updated = false;
// Test deactivating an inaccessible user - should keep deactivated as false
// We consider inaccessible users as active to avoid falsely showing them as deactivated,
// since we don't have information about their activity status.
compose_pm_pill.update_user_pill_active_status(inaccessible_user, false);
assert.deepEqual(pills_data[1].item, {
user_id: inaccessible_user.user_id,
full_name: inaccessible_user.full_name,
deactivated: false,
});
assert.ok(pill_updated);
// Reset for next test
pill_updated = false;
// Test updating a user that doesn't have a pill - should be a no-op
const hamlet = make_user({
email: "hamlet@example.com",
user_id: 3,
full_name: "Hamlet",
});
compose_pm_pill.update_user_pill_active_status(hamlet, true);
assert.ok(!pill_updated);
});
run_test("update_user_pill_full_name", ({override_rewire}) => {
// The pill-update logic lives in user_pill.update_pill_full_name and
// is tested there; here we just verify the wrapper delegates when
// the widget is set, and is a no-op otherwise.
let user_pill_function_called = false;
const widget = {
getPillByPredicate() {
user_pill_function_called = true;
return undefined;
},
updatePill() {},
};
override_rewire(compose_pm_pill, "widget", undefined);
compose_pm_pill.update_user_pill_full_name(1, "Othello the Moor");
assert.ok(!user_pill_function_called);
override_rewire(compose_pm_pill, "widget", widget);
compose_pm_pill.update_user_pill_full_name(1, "Othello the Moor");
assert.ok(user_pill_function_called);
});