snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
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
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
This commit is contained in:
896
web/tests/drafts.test.cjs
Normal file
896
web/tests/drafts.test.cjs
Normal file
@@ -0,0 +1,896 @@
|
||||
"use strict";
|
||||
|
||||
const assert = require("node:assert/strict");
|
||||
|
||||
const {mock_banners} = require("./lib/compose_banner.cjs");
|
||||
const {make_realm} = require("./lib/example_realm.cjs");
|
||||
const {make_stream} = require("./lib/example_stream.cjs");
|
||||
const {make_user} = require("./lib/example_user.cjs");
|
||||
const {clock, mock_esm, mock_cjs, set_global, zrequire} = require("./lib/namespace.cjs");
|
||||
const {run_test, noop} = require("./lib/test.cjs");
|
||||
const {$} = require("./lib/zjquery.cjs");
|
||||
|
||||
const user_pill = mock_esm("../src/user_pill", {get_user_ids: () => []});
|
||||
const settings_data = mock_esm("../src/settings_data");
|
||||
const messages_overlay_ui = mock_esm("../src/messages_overlay_ui");
|
||||
const channel = mock_esm("../src/channel");
|
||||
|
||||
const people = zrequire("people");
|
||||
const compose_state = zrequire("compose_state");
|
||||
const compose_recipient = zrequire("compose_recipient");
|
||||
const stream_data = zrequire("stream_data");
|
||||
const stream_color = zrequire("stream_color");
|
||||
const {initialize_user_settings} = zrequire("user_settings");
|
||||
const {set_current_user, set_realm} = zrequire("state_data");
|
||||
class Clipboard {
|
||||
on() {}
|
||||
}
|
||||
|
||||
mock_cjs("clipboard", Clipboard);
|
||||
|
||||
initialize_user_settings({user_settings: {}});
|
||||
|
||||
const REALM_EMPTY_TOPIC_DISPLAY_NAME = "test general chat";
|
||||
const realm = make_realm({realm_empty_topic_display_name: REALM_EMPTY_TOPIC_DISPLAY_NAME});
|
||||
set_realm(realm);
|
||||
|
||||
const aaron = make_user({
|
||||
email: "aaron@zulip.com",
|
||||
user_id: 6,
|
||||
full_name: "Aaron",
|
||||
});
|
||||
const iago = make_user({
|
||||
email: "iago@zulip.com",
|
||||
user_id: 2,
|
||||
full_name: "Iago",
|
||||
});
|
||||
const zoe = make_user({
|
||||
email: "zoe@zulip.com",
|
||||
user_id: 3,
|
||||
full_name: "Zoe",
|
||||
});
|
||||
set_current_user(aaron);
|
||||
people.add_active_user(aaron);
|
||||
people.add_valid_user_id(aaron.user_id);
|
||||
people.initialize_current_user(aaron.user_id);
|
||||
people.add_active_user(iago);
|
||||
people.add_valid_user_id(iago.user_id);
|
||||
people.add_active_user(zoe);
|
||||
people.add_valid_user_id(zoe.user_id);
|
||||
|
||||
const stream_A = make_stream({
|
||||
subscribed: false,
|
||||
name: "A",
|
||||
stream_id: 1,
|
||||
});
|
||||
const stream_B = make_stream({
|
||||
subscribed: false,
|
||||
name: "B",
|
||||
stream_id: 2,
|
||||
});
|
||||
const stream_1 = make_stream({
|
||||
subscribed: false,
|
||||
name: "stream 1",
|
||||
stream_id: 30,
|
||||
color: "c2726a",
|
||||
});
|
||||
const stream_2 = make_stream({
|
||||
subscribed: false,
|
||||
name: "stream 2",
|
||||
stream_id: 40,
|
||||
color: "e2226a",
|
||||
invite_only: false,
|
||||
is_web_public: false,
|
||||
});
|
||||
stream_data.add_sub_for_tests(stream_A);
|
||||
stream_data.add_sub_for_tests(stream_B);
|
||||
stream_data.add_sub_for_tests(stream_1);
|
||||
stream_data.add_sub_for_tests(stream_2);
|
||||
|
||||
const setTimeout_delay = new Set([0, 3000]);
|
||||
set_global("setTimeout", (f, delay) => {
|
||||
assert.ok(setTimeout_delay.has(delay));
|
||||
f();
|
||||
});
|
||||
const markdown = mock_esm("../src/markdown", {
|
||||
render: noop,
|
||||
contains_backend_only_syntax: () => false,
|
||||
});
|
||||
const overlays = mock_esm("../src/overlays", {
|
||||
open_overlay: noop,
|
||||
});
|
||||
mock_esm("../src/rendered_markdown", {
|
||||
update_elements: noop,
|
||||
});
|
||||
|
||||
const tippy_sel = ".top_left_drafts .unread_count";
|
||||
let tippy_args;
|
||||
let tippy_show_called;
|
||||
let tippy_destroy_called;
|
||||
mock_esm("tippy.js", {
|
||||
default(sel, opts) {
|
||||
assert.equal(sel, tippy_sel);
|
||||
assert.deepEqual(opts, tippy_args);
|
||||
return [
|
||||
{
|
||||
show() {
|
||||
tippy_show_called = true;
|
||||
},
|
||||
destroy() {
|
||||
tippy_destroy_called = true;
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
delegate: noop,
|
||||
});
|
||||
|
||||
const {localstorage} = zrequire("localstorage");
|
||||
const drafts = zrequire("drafts");
|
||||
const drafts_overlay_ui = zrequire("drafts_overlay_ui");
|
||||
zrequire("timerender");
|
||||
|
||||
const mock_current_timestamp = 1234;
|
||||
const stream_id = 30;
|
||||
|
||||
const draft_1 = {
|
||||
stream_id,
|
||||
topic: "topic",
|
||||
type: "stream",
|
||||
content: "Test stream message",
|
||||
updatedAt: mock_current_timestamp,
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const draft_2 = {
|
||||
private_message_recipient_ids: [aaron.user_id],
|
||||
type: "private",
|
||||
content: "Test direct message",
|
||||
updatedAt: mock_current_timestamp,
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const short_msg = {
|
||||
stream_id,
|
||||
topic: "topic",
|
||||
type: "stream",
|
||||
content: "a",
|
||||
updatedAt: mock_current_timestamp,
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
|
||||
function test(label, f) {
|
||||
run_test(label, (helpers) => {
|
||||
$(".top_left_drafts").set_find_results(".unread_count", $("<unread-count-stub>"));
|
||||
$(".compose-drafts-count-container").set_find_results(
|
||||
".compose-drafts-count",
|
||||
$("<compose-drafts-count-stub>"),
|
||||
);
|
||||
window.localStorage.clear();
|
||||
f(helpers);
|
||||
});
|
||||
}
|
||||
|
||||
// There were some buggy drafts that had their topics
|
||||
// renamed to `undefined` in #23238.
|
||||
// TODO/compatibility: The next two tests can be deleted
|
||||
// when we get to delete drafts.fix_drafts_with_undefined_topics.
|
||||
//
|
||||
// This test must run before others, so that
|
||||
// fixed_buggy_drafts and fixed_private_draft_recipient_ids are false.
|
||||
test("fix buggy drafts", () => {
|
||||
const buggy_draft = {
|
||||
stream_id: stream_B.stream_id,
|
||||
topic: undefined,
|
||||
type: "stream",
|
||||
content: "Test stream message",
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
const draft_with_pm_emails = {
|
||||
private_message_recipient: "iago@zulip.com,zoe@zulip.com",
|
||||
reply_to: "iago@zulip.com,zoe@zulip.com",
|
||||
type: "private",
|
||||
content: "Test direct message",
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
// 999 is an invalid user ID not present in the people store.
|
||||
const draft_with_invalid_recipient = {
|
||||
private_message_recipient_ids: [iago.user_id, 999],
|
||||
type: "private",
|
||||
content: "Test direct message 2",
|
||||
updatedAt: Date.now(),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const draft_with_only_invalid_recipients = {
|
||||
private_message_recipient_ids: [999],
|
||||
type: "private",
|
||||
content: "Test direct message 3",
|
||||
updatedAt: Date.now(),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const ls = localstorage();
|
||||
ls.set("drafts", {
|
||||
id1: buggy_draft,
|
||||
id2: draft_with_pm_emails,
|
||||
id3: draft_with_invalid_recipient,
|
||||
id4: draft_with_only_invalid_recipients,
|
||||
});
|
||||
const draft_model = drafts.draft_model;
|
||||
|
||||
// The draft is fixed in this codepath.
|
||||
drafts.rename_stream_recipient(
|
||||
stream_B.stream_id,
|
||||
"old_topic",
|
||||
stream_A.stream_id,
|
||||
"new_topic",
|
||||
);
|
||||
|
||||
const draft = draft_model.getDraft("id1");
|
||||
assert.equal(draft.stream_id, stream_B.stream_id);
|
||||
assert.equal(draft.topic, "");
|
||||
|
||||
const fixed_draft = draft_model.getDraft("id2");
|
||||
assert.equal(fixed_draft.private_message_recipient, undefined);
|
||||
assert.deepEqual(fixed_draft.private_message_recipient_ids, [iago.user_id, zoe.user_id]);
|
||||
// reply_to field is also removed since it is not present in the
|
||||
// zod schema.
|
||||
assert.equal(fixed_draft.reply_to, undefined);
|
||||
|
||||
// fix_private_draft_recipient_ids removes invalid user IDs.
|
||||
const fixed_invalid_recipient_draft = draft_model.getDraft("id3");
|
||||
assert.deepEqual(fixed_invalid_recipient_draft.private_message_recipient_ids, [iago.user_id]);
|
||||
|
||||
const fixed_only_invalid_recipients_draft = draft_model.getDraft("id4");
|
||||
assert.deepEqual(fixed_only_invalid_recipients_draft.private_message_recipient_ids, []);
|
||||
});
|
||||
|
||||
test("draft_model add", () => {
|
||||
const draft_model = drafts.draft_model;
|
||||
const ls = localstorage();
|
||||
assert.equal(ls.get("draft"), undefined);
|
||||
|
||||
const id = draft_model.addDraft(draft_1);
|
||||
assert.deepEqual(draft_model.getDraft(id), draft_1);
|
||||
});
|
||||
|
||||
test("draft_model edit", () => {
|
||||
const draft_model = drafts.draft_model;
|
||||
const ls = localstorage();
|
||||
assert.equal(ls.get("draft"), undefined);
|
||||
|
||||
const id = draft_model.addDraft(draft_1);
|
||||
assert.deepEqual(draft_model.getDraft(id), draft_1);
|
||||
|
||||
draft_model.editDraft(id, draft_2);
|
||||
assert.deepEqual(draft_model.getDraft(id), draft_2);
|
||||
});
|
||||
|
||||
test("draft_model delete", () => {
|
||||
const draft_model = drafts.draft_model;
|
||||
const ls = localstorage();
|
||||
assert.equal(ls.get("draft"), undefined);
|
||||
|
||||
const id = draft_model.addDraft(draft_1);
|
||||
assert.deepEqual(draft_model.getDraft(id), draft_1);
|
||||
|
||||
draft_model.deleteDrafts([id]);
|
||||
assert.deepEqual(draft_model.getDraft(id), false);
|
||||
});
|
||||
|
||||
test("snapshot_message", ({override}) => {
|
||||
override(user_pill, "get_user_ids", () => [aaron.user_id]);
|
||||
mock_banners();
|
||||
|
||||
let curr_draft;
|
||||
|
||||
function set_compose_state() {
|
||||
compose_state.set_message_type(curr_draft.type);
|
||||
compose_state.message_content(curr_draft.content);
|
||||
if (curr_draft.type === "private") {
|
||||
compose_state.set_compose_recipient_id(compose_recipient.DIRECT_MESSAGE_ID);
|
||||
} else {
|
||||
compose_state.set_stream_id(curr_draft.stream_id);
|
||||
}
|
||||
compose_state.topic(curr_draft.topic);
|
||||
}
|
||||
|
||||
compose_state.set_stream_id(stream_1.stream_id);
|
||||
|
||||
override(Date, "now", () => mock_current_timestamp);
|
||||
|
||||
curr_draft = draft_1;
|
||||
set_compose_state();
|
||||
assert.deepEqual(drafts.snapshot_message(), draft_1);
|
||||
|
||||
curr_draft = draft_2;
|
||||
set_compose_state();
|
||||
assert.deepEqual(drafts.snapshot_message(), draft_2);
|
||||
|
||||
curr_draft = short_msg;
|
||||
set_compose_state();
|
||||
assert.deepEqual(drafts.snapshot_message(), undefined);
|
||||
|
||||
curr_draft = {type: false};
|
||||
set_compose_state();
|
||||
assert.equal(drafts.snapshot_message(), undefined);
|
||||
});
|
||||
|
||||
test("initialize", ({override_rewire}) => {
|
||||
window.addEventListener = (event_name, f) => {
|
||||
assert.equal(event_name, "beforeunload");
|
||||
let called = false;
|
||||
override_rewire(drafts, "update_draft", () => {
|
||||
called = true;
|
||||
return 100;
|
||||
});
|
||||
f();
|
||||
assert.ok(called);
|
||||
};
|
||||
|
||||
drafts.initialize();
|
||||
drafts.initialize_ui();
|
||||
drafts_overlay_ui.initialize();
|
||||
});
|
||||
|
||||
test("update_draft", ({override}) => {
|
||||
compose_state.set_message_type(undefined);
|
||||
let draft_id = drafts.update_draft();
|
||||
assert.equal(draft_id, undefined);
|
||||
|
||||
override(user_pill, "get_user_ids", () => [aaron.user_id]);
|
||||
compose_state.set_message_type("private");
|
||||
compose_state.message_content("dummy content");
|
||||
|
||||
tippy_args = {
|
||||
content: "translated: Saved as draft",
|
||||
arrow: true,
|
||||
placement: "right",
|
||||
};
|
||||
tippy_show_called = false;
|
||||
tippy_destroy_called = false;
|
||||
|
||||
override(Date, "now", () => 5);
|
||||
override(Math, "random", () => 2);
|
||||
draft_id = drafts.update_draft();
|
||||
assert.equal(draft_id, "5-2");
|
||||
assert.ok(tippy_show_called);
|
||||
assert.ok(tippy_destroy_called);
|
||||
|
||||
override(Date, "now", () => 6);
|
||||
|
||||
compose_state.message_content("dummy content edited once");
|
||||
tippy_show_called = false;
|
||||
tippy_destroy_called = false;
|
||||
draft_id = drafts.update_draft();
|
||||
assert.equal(draft_id, "5-2");
|
||||
assert.ok(tippy_show_called);
|
||||
assert.ok(tippy_destroy_called);
|
||||
|
||||
override(Date, "now", () => 7);
|
||||
|
||||
// message contents not edited
|
||||
tippy_show_called = false;
|
||||
tippy_destroy_called = false;
|
||||
draft_id = drafts.update_draft();
|
||||
assert.equal(draft_id, "5-2");
|
||||
assert.ok(!tippy_show_called);
|
||||
assert.ok(!tippy_destroy_called);
|
||||
|
||||
override(Date, "now", () => 8);
|
||||
|
||||
compose_state.message_content("dummy content edited a second time");
|
||||
tippy_show_called = false;
|
||||
tippy_destroy_called = false;
|
||||
draft_id = drafts.update_draft({no_notify: true});
|
||||
assert.equal(draft_id, "5-2");
|
||||
assert.ok(!tippy_show_called);
|
||||
assert.ok(!tippy_destroy_called);
|
||||
});
|
||||
|
||||
test("rename_stream_recipient", () => {
|
||||
const draft_1 = {
|
||||
stream_id: stream_A.stream_id,
|
||||
topic: "a",
|
||||
type: "stream",
|
||||
content: "Test stream message",
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
const draft_2 = {
|
||||
stream_id: stream_A.stream_id,
|
||||
topic: "b",
|
||||
type: "stream",
|
||||
content: "Test stream message",
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
const draft_3 = {
|
||||
stream_id: stream_B.stream_id,
|
||||
topic: "a",
|
||||
type: "stream",
|
||||
content: "Test stream message",
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
const draft_4 = {
|
||||
stream_id: stream_B.stream_id,
|
||||
topic: "c",
|
||||
type: "stream",
|
||||
content: "Test stream message",
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
const data = {id1: draft_1, id2: draft_2, id3: draft_3, id4: draft_4};
|
||||
const ls = localstorage();
|
||||
ls.set("drafts", data);
|
||||
|
||||
const draft_model = drafts.draft_model;
|
||||
function assert_draft(draft_id, stream_id, topic_name) {
|
||||
const draft = draft_model.getDraft(draft_id);
|
||||
assert.equal(draft.topic, topic_name);
|
||||
assert.equal(draft.stream_id, stream_id);
|
||||
}
|
||||
|
||||
// There are no drafts in B>b, so moving messages from there doesn't change drafts
|
||||
drafts.rename_stream_recipient(stream_B.stream_id, "b", undefined, "c");
|
||||
assert_draft("id1", stream_A.stream_id, "a");
|
||||
assert_draft("id2", stream_A.stream_id, "b");
|
||||
assert_draft("id3", stream_B.stream_id, "a");
|
||||
assert_draft("id4", stream_B.stream_id, "c");
|
||||
|
||||
// Update with both stream and topic changes Bc -> Aa
|
||||
drafts.rename_stream_recipient(stream_B.stream_id, "c", stream_A.stream_id, "a");
|
||||
assert_draft("id1", stream_A.stream_id, "a");
|
||||
assert_draft("id2", stream_A.stream_id, "b");
|
||||
assert_draft("id3", stream_B.stream_id, "a");
|
||||
assert_draft("id4", stream_A.stream_id, "a");
|
||||
|
||||
// Update with only stream change Aa -> Ba
|
||||
drafts.rename_stream_recipient(stream_A.stream_id, "a", stream_B.stream_id, undefined);
|
||||
assert_draft("id1", stream_B.stream_id, "a");
|
||||
assert_draft("id2", stream_A.stream_id, "b");
|
||||
assert_draft("id3", stream_B.stream_id, "a");
|
||||
assert_draft("id4", stream_B.stream_id, "a");
|
||||
|
||||
// Update with only topic change, affecting three messages
|
||||
drafts.rename_stream_recipient(stream_B.stream_id, "a", undefined, "e");
|
||||
assert_draft("id1", stream_B.stream_id, "e");
|
||||
assert_draft("id2", stream_A.stream_id, "b");
|
||||
assert_draft("id3", stream_B.stream_id, "e");
|
||||
assert_draft("id4", stream_B.stream_id, "e");
|
||||
});
|
||||
|
||||
test("delete_all_drafts", () => {
|
||||
const draft_model = drafts.draft_model;
|
||||
const ls = localstorage();
|
||||
const data = {draft_1, draft_2, short_msg};
|
||||
ls.set("drafts", data);
|
||||
assert.deepEqual(draft_model.get(), data);
|
||||
|
||||
drafts.delete_all_drafts();
|
||||
assert.deepEqual(draft_model.get(), {});
|
||||
});
|
||||
|
||||
test("format_drafts", ({override, mock_template}) => {
|
||||
override(settings_data, "using_dark_theme", () => false);
|
||||
|
||||
function feb12() {
|
||||
return new Date(1549958107000); // 2/12/2019 07:55:07 AM (UTC+0)
|
||||
}
|
||||
|
||||
function date(offset) {
|
||||
return feb12().setDate(offset);
|
||||
}
|
||||
|
||||
const draft_1 = {
|
||||
topic: "topic",
|
||||
type: "stream",
|
||||
content: "Test stream message",
|
||||
stream_id: 30,
|
||||
updatedAt: feb12().getTime(),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const draft_2 = {
|
||||
private_message_recipient_ids: [aaron.user_id],
|
||||
type: "private",
|
||||
content: "Test direct message",
|
||||
updatedAt: date(-1),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const draft_3 = {
|
||||
topic: "topic",
|
||||
type: "stream",
|
||||
stream_id: 40,
|
||||
content: "Test stream message 2",
|
||||
updatedAt: date(-10),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const draft_4 = {
|
||||
private_message_recipient_ids: [iago.user_id],
|
||||
type: "private",
|
||||
content: "Test direct message 2",
|
||||
updatedAt: date(-5),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const draft_5 = {
|
||||
private_message_recipient_ids: [zoe.user_id, iago.user_id],
|
||||
type: "private",
|
||||
content: "Test direct message 3",
|
||||
updatedAt: date(-2),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const draft_6 = {
|
||||
topic: "",
|
||||
type: "stream",
|
||||
stream_id: 40,
|
||||
content: "Test stream message 3",
|
||||
updatedAt: date(-11),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const draft_7 = {
|
||||
private_message_recipient_ids: [],
|
||||
type: "private",
|
||||
content: "Test direct message 4",
|
||||
updatedAt: date(-12),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
|
||||
const expected = [
|
||||
{
|
||||
draft_id: "id1",
|
||||
is_stream: true,
|
||||
stream_name: stream_1.name,
|
||||
stream_id: 30,
|
||||
recipient_bar_color: stream_color.get_recipient_bar_color(stream_1.color),
|
||||
stream_privacy_icon_color: stream_color.get_stream_privacy_icon_color(stream_1.color),
|
||||
topic_display_name: "topic",
|
||||
is_empty_string_topic: false,
|
||||
raw_content: "Test stream message",
|
||||
time_stamp: "7:55 AM",
|
||||
invite_only: stream_1.invite_only,
|
||||
is_web_public: stream_1.is_web_public,
|
||||
is_sending_saving: false,
|
||||
},
|
||||
{
|
||||
draft_id: "id2",
|
||||
is_dm_with_self: true,
|
||||
is_stream: false,
|
||||
has_recipient_data: true,
|
||||
recipients: "Aaron",
|
||||
raw_content: "Test direct message",
|
||||
time_stamp: "Jan 30",
|
||||
is_sending_saving: false,
|
||||
},
|
||||
{
|
||||
draft_id: "id5",
|
||||
is_dm_with_self: false,
|
||||
is_stream: false,
|
||||
recipients: "Iago, Zoe",
|
||||
has_recipient_data: true,
|
||||
raw_content: "Test direct message 3",
|
||||
time_stamp: "Jan 29",
|
||||
is_sending_saving: false,
|
||||
},
|
||||
{
|
||||
draft_id: "id4",
|
||||
is_dm_with_self: false,
|
||||
is_stream: false,
|
||||
recipients: "Iago",
|
||||
has_recipient_data: true,
|
||||
raw_content: "Test direct message 2",
|
||||
time_stamp: "Jan 26",
|
||||
is_sending_saving: false,
|
||||
},
|
||||
{
|
||||
draft_id: "id3",
|
||||
is_stream: true,
|
||||
stream_name: stream_2.name,
|
||||
stream_id: 40,
|
||||
recipient_bar_color: stream_color.get_recipient_bar_color(stream_2.color),
|
||||
stream_privacy_icon_color: stream_color.get_stream_privacy_icon_color(stream_2.color),
|
||||
topic_display_name: "topic",
|
||||
is_empty_string_topic: false,
|
||||
raw_content: "Test stream message 2",
|
||||
time_stamp: "Jan 21",
|
||||
invite_only: stream_2.invite_only,
|
||||
is_web_public: stream_2.is_web_public,
|
||||
is_sending_saving: false,
|
||||
},
|
||||
{
|
||||
draft_id: "id6",
|
||||
is_stream: true,
|
||||
stream_name: stream_2.name,
|
||||
stream_id: 40,
|
||||
recipient_bar_color: stream_color.get_recipient_bar_color(stream_2.color),
|
||||
stream_privacy_icon_color: stream_color.get_stream_privacy_icon_color(stream_2.color),
|
||||
topic_display_name: REALM_EMPTY_TOPIC_DISPLAY_NAME,
|
||||
is_empty_string_topic: true,
|
||||
raw_content: "Test stream message 3",
|
||||
time_stamp: "Jan 20",
|
||||
invite_only: stream_2.invite_only,
|
||||
is_web_public: stream_2.is_web_public,
|
||||
is_sending_saving: false,
|
||||
},
|
||||
{
|
||||
draft_id: "id7",
|
||||
is_stream: false,
|
||||
has_recipient_data: false,
|
||||
recipients: "",
|
||||
raw_content: "Test direct message 4",
|
||||
time_stamp: "Jan 19",
|
||||
is_sending_saving: false,
|
||||
},
|
||||
];
|
||||
|
||||
const draft_model = drafts.draft_model;
|
||||
const ls = localstorage();
|
||||
const data = {
|
||||
id1: draft_1,
|
||||
id2: draft_2,
|
||||
id3: draft_3,
|
||||
id4: draft_4,
|
||||
id5: draft_5,
|
||||
id6: draft_6,
|
||||
id7: draft_7,
|
||||
};
|
||||
ls.set("drafts", data);
|
||||
assert.deepEqual(draft_model.get(), data);
|
||||
|
||||
override(realm, "realm_topics_policy", "disable_empty_topic");
|
||||
expected[5].topic_display_name = "translated: No topic entered";
|
||||
expected[5].is_empty_string_topic = true;
|
||||
assert.deepEqual(draft_model.get(), data);
|
||||
|
||||
clock.setSystemTime(1549958107000);
|
||||
|
||||
override(user_pill, "get_user_ids", () => []);
|
||||
compose_state.set_message_type("private");
|
||||
|
||||
mock_template("draft_table_body.hbs", false, (data) => {
|
||||
// Tests formatting and time-sorting of drafts
|
||||
assert.deepEqual(data.context.narrow_drafts, []);
|
||||
assert.deepEqual(data.context.other_drafts, expected);
|
||||
assert.ok(data);
|
||||
return "<draft table stub>";
|
||||
});
|
||||
|
||||
override(messages_overlay_ui, "set_initial_element", noop);
|
||||
override(messages_overlay_ui, "get_and_clear_pending_restore_element_id", () => undefined);
|
||||
|
||||
$.set_results(".drafts-list", []);
|
||||
$.set_results(".drafts-tab-pane .overlay-message-row", []);
|
||||
$.set_results(".draft-selection-checkbox", []);
|
||||
drafts_overlay_ui.launch();
|
||||
});
|
||||
|
||||
test("filter_drafts", ({override, mock_template}) => {
|
||||
override(settings_data, "using_dark_theme", () => true);
|
||||
function feb12() {
|
||||
return new Date(1549958107000); // 2/12/2019 07:55:07 AM (UTC+0)
|
||||
}
|
||||
|
||||
function date(offset) {
|
||||
return feb12().setDate(offset);
|
||||
}
|
||||
|
||||
const stream_draft_1 = {
|
||||
topic: "topic",
|
||||
type: "stream",
|
||||
content: "Test stream message",
|
||||
stream_id: 30,
|
||||
updatedAt: feb12().getTime(),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const pm_draft_1 = {
|
||||
private_message_recipient_ids: [aaron.user_id],
|
||||
type: "private",
|
||||
content: "Test direct message",
|
||||
updatedAt: date(-1),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const stream_draft_2 = {
|
||||
topic: "topic",
|
||||
type: "stream",
|
||||
stream_id: 40,
|
||||
content: "Test stream message 2",
|
||||
updatedAt: date(-10),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const pm_draft_2 = {
|
||||
private_message_recipient_ids: [aaron.user_id],
|
||||
type: "private",
|
||||
content: "Test direct message 2",
|
||||
updatedAt: date(-5),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const pm_draft_3 = {
|
||||
private_message_recipient_ids: [aaron.user_id],
|
||||
type: "private",
|
||||
content: "Test direct message 3",
|
||||
updatedAt: date(-2),
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
|
||||
const expected_pm_drafts = [
|
||||
{
|
||||
draft_id: "id2",
|
||||
is_dm_with_self: true,
|
||||
is_stream: false,
|
||||
has_recipient_data: true,
|
||||
recipients: "Aaron",
|
||||
raw_content: "Test direct message",
|
||||
time_stamp: "Jan 30",
|
||||
is_sending_saving: false,
|
||||
},
|
||||
{
|
||||
draft_id: "id5",
|
||||
is_dm_with_self: true,
|
||||
is_stream: false,
|
||||
has_recipient_data: true,
|
||||
recipients: "Aaron",
|
||||
raw_content: "Test direct message 3",
|
||||
time_stamp: "Jan 29",
|
||||
is_sending_saving: false,
|
||||
},
|
||||
{
|
||||
draft_id: "id4",
|
||||
is_dm_with_self: true,
|
||||
is_stream: false,
|
||||
has_recipient_data: true,
|
||||
recipients: "Aaron",
|
||||
raw_content: "Test direct message 2",
|
||||
time_stamp: "Jan 26",
|
||||
is_sending_saving: false,
|
||||
},
|
||||
];
|
||||
|
||||
const expected_other_drafts = [
|
||||
{
|
||||
draft_id: "id1",
|
||||
is_stream: true,
|
||||
stream_name: stream_1.name,
|
||||
stream_id: 30,
|
||||
recipient_bar_color: stream_color.get_recipient_bar_color(stream_1.color),
|
||||
stream_privacy_icon_color: stream_color.get_stream_privacy_icon_color(stream_1.color),
|
||||
topic_display_name: "topic",
|
||||
is_empty_string_topic: false,
|
||||
raw_content: "Test stream message",
|
||||
time_stamp: "7:55 AM",
|
||||
invite_only: stream_1.invite_only,
|
||||
is_web_public: stream_1.is_web_public,
|
||||
is_sending_saving: false,
|
||||
},
|
||||
{
|
||||
draft_id: "id3",
|
||||
is_stream: true,
|
||||
stream_name: stream_2.name,
|
||||
stream_id: 40,
|
||||
recipient_bar_color: stream_color.get_recipient_bar_color(stream_2.color),
|
||||
stream_privacy_icon_color: stream_color.get_stream_privacy_icon_color(stream_2.color),
|
||||
topic_display_name: "topic",
|
||||
is_empty_string_topic: false,
|
||||
raw_content: "Test stream message 2",
|
||||
time_stamp: "Jan 21",
|
||||
invite_only: stream_2.invite_only,
|
||||
is_web_public: stream_2.is_web_public,
|
||||
is_sending_saving: false,
|
||||
},
|
||||
];
|
||||
|
||||
const draft_model = drafts.draft_model;
|
||||
const ls = localstorage();
|
||||
const data = {
|
||||
id1: stream_draft_1,
|
||||
id2: pm_draft_1,
|
||||
id3: stream_draft_2,
|
||||
id4: pm_draft_2,
|
||||
id5: pm_draft_3,
|
||||
};
|
||||
ls.set("drafts", data);
|
||||
assert.deepEqual(draft_model.get(), data);
|
||||
|
||||
clock.setSystemTime(1549958107000);
|
||||
|
||||
mock_template("draft_table_body.hbs", false, (data) => {
|
||||
// Tests splitting up drafts by current narrow.
|
||||
assert.deepEqual(data.context.narrow_drafts, expected_pm_drafts);
|
||||
assert.deepEqual(data.context.other_drafts, expected_other_drafts);
|
||||
return "<draft table stub>";
|
||||
});
|
||||
|
||||
override(messages_overlay_ui, "set_initial_element", noop);
|
||||
override(messages_overlay_ui, "get_and_clear_pending_restore_element_id", () => undefined);
|
||||
|
||||
override(user_pill, "get_user_ids", () => [aaron.user_id]);
|
||||
compose_state.set_message_type("private");
|
||||
|
||||
$.set_results(".drafts-list", []);
|
||||
$.set_results(".drafts-tab-pane .overlay-message-row", []);
|
||||
$.set_results(".draft-selection-checkbox", []);
|
||||
drafts_overlay_ui.launch();
|
||||
});
|
||||
|
||||
test("server_rendering_for_backend_only_syntax", ({override, mock_template}) => {
|
||||
override(settings_data, "using_dark_theme", () => false);
|
||||
|
||||
const now = Date.now();
|
||||
const draft_with_image = {
|
||||
topic: "topic",
|
||||
type: "stream",
|
||||
content: "Look at this screenshot: https://user-uploads.zulipdev.org/upload/image.png",
|
||||
stream_id: 30,
|
||||
updatedAt: now,
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
const draft_without_image = {
|
||||
topic: "topic",
|
||||
type: "stream",
|
||||
content: "This is a plain text draft",
|
||||
stream_id: 30,
|
||||
updatedAt: now - 1000,
|
||||
is_sending_saving: false,
|
||||
drafts_version: 1,
|
||||
};
|
||||
|
||||
const draft_model = drafts.draft_model;
|
||||
const ls = localstorage();
|
||||
ls.set("drafts", {id1: draft_with_image, id2: draft_without_image});
|
||||
assert.deepEqual(draft_model.get(), {id1: draft_with_image, id2: draft_without_image});
|
||||
|
||||
override(
|
||||
markdown,
|
||||
"contains_backend_only_syntax",
|
||||
(content) => content === draft_with_image.content,
|
||||
);
|
||||
|
||||
const locally_rendered_content =
|
||||
'<p>Look at this screenshot: <a href="https://user-uploads.zulipdev.org/upload/image.png">https://user-uploads.zulipdev.org/upload/image.png</a></p>';
|
||||
const server_rendered_content =
|
||||
'<p>Look at this screenshot: <a href="https://user-uploads.zulipdev.org/upload/image.png" target="_blank" rel="noopener noreferrer" title="https://user-uploads.zulipdev.org/upload/image.png"><img src="/thumbnail?url=user_uploads%2Fimage.png&size=thumbnail"></a></p>';
|
||||
|
||||
let post_calls = 0;
|
||||
const $content_element = $.create('[data-draft-id="id1"] .message_content');
|
||||
$content_element.html(locally_rendered_content);
|
||||
override(overlays, "drafts_open", () => true);
|
||||
|
||||
mock_template("draft_table_body.hbs", false, () => "<draft table stub>");
|
||||
override(messages_overlay_ui, "set_initial_element", noop);
|
||||
override(messages_overlay_ui, "get_and_clear_pending_restore_element_id", () => undefined);
|
||||
|
||||
// These selectors are accessed during render_widgets() and
|
||||
// update_bulk_delete_ui() inside launch().
|
||||
$.set_results(".drafts-list", []);
|
||||
$.set_results(".drafts-tab-pane .overlay-message-row", []);
|
||||
$.set_results(".draft-selection-checkbox", []);
|
||||
|
||||
override(channel, "post", (payload) => {
|
||||
post_calls += 1;
|
||||
assert.equal(payload.url, "/json/messages/render");
|
||||
assert.equal(payload.data.content, draft_with_image.content);
|
||||
|
||||
const resp = {
|
||||
msg: "",
|
||||
result: "success",
|
||||
rendered: server_rendered_content,
|
||||
};
|
||||
payload.success(resp);
|
||||
assert.equal($content_element.html(), server_rendered_content);
|
||||
});
|
||||
drafts_overlay_ui.launch();
|
||||
|
||||
// Only the draft with the image triggered a server render request;
|
||||
// the plain text draft did not.
|
||||
assert.equal(post_calls, 1);
|
||||
});
|
||||
Reference in New Issue
Block a user