mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	This lets us simplify the long-ish ‘../../static/js’ paths, and will remove the need for the ‘zrequire’ wrapper. Signed-off-by: Anders Kaseorg <anders@zulip.com>
		
			
				
	
	
		
			805 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			805 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
"use strict";
 | 
						|
 | 
						|
const {strict: assert} = require("assert");
 | 
						|
 | 
						|
const _ = require("lodash");
 | 
						|
 | 
						|
const {mock_esm, set_global, zrequire} = require("./lib/namespace");
 | 
						|
const {run_test} = require("./lib/test");
 | 
						|
const $ = require("./lib/zjquery");
 | 
						|
 | 
						|
set_global("document", "document-stub");
 | 
						|
 | 
						|
const noop = () => {};
 | 
						|
 | 
						|
// timerender calls setInterval when imported
 | 
						|
mock_esm("../src/timerender", {
 | 
						|
    render_date(time) {
 | 
						|
        return [{outerHTML: String(time.getTime())}];
 | 
						|
    },
 | 
						|
    stringify_time(time) {
 | 
						|
        return time.toString("h:mm TT");
 | 
						|
    },
 | 
						|
});
 | 
						|
 | 
						|
mock_esm("../src/rows", {
 | 
						|
    get_table() {
 | 
						|
        return {
 | 
						|
            children() {
 | 
						|
                return {
 | 
						|
                    detach: noop,
 | 
						|
                };
 | 
						|
            },
 | 
						|
        };
 | 
						|
    },
 | 
						|
});
 | 
						|
 | 
						|
mock_esm("../src/people", {
 | 
						|
    sender_is_bot: () => false,
 | 
						|
    sender_is_guest: () => false,
 | 
						|
    small_avatar_url: () => "fake/small/avatar/url",
 | 
						|
});
 | 
						|
 | 
						|
const {Filter} = zrequire("../src/filter");
 | 
						|
const {MessageListView} = zrequire("../src/message_list_view");
 | 
						|
const message_list = zrequire("message_list");
 | 
						|
const muted_users = zrequire("muted_users");
 | 
						|
 | 
						|
let next_timestamp = 1500000000;
 | 
						|
 | 
						|
function test(label, f) {
 | 
						|
    run_test(label, ({override}) => {
 | 
						|
        muted_users.set_muted_users([]);
 | 
						|
        f({override});
 | 
						|
    });
 | 
						|
}
 | 
						|
 | 
						|
test("msg_moved_var", () => {
 | 
						|
    // This is a test to verify that when the stream or topic is changed
 | 
						|
    // (and the content is not), the message says "MOVED" rather than "EDITED."
 | 
						|
    // See the end of the test for the list of cases verified.
 | 
						|
 | 
						|
    function build_message_context(message = {}, message_context = {}) {
 | 
						|
        message_context = {
 | 
						|
            ...message_context,
 | 
						|
        };
 | 
						|
        if ("edit_history" in message) {
 | 
						|
            message_context.msg = {
 | 
						|
                last_edit_timestamp: (next_timestamp += 1),
 | 
						|
                ...message,
 | 
						|
            };
 | 
						|
        } else {
 | 
						|
            message_context.msg = {
 | 
						|
                ...message,
 | 
						|
            };
 | 
						|
        }
 | 
						|
        return message_context;
 | 
						|
    }
 | 
						|
 | 
						|
    function build_message_group(messages) {
 | 
						|
        return {message_containers: messages};
 | 
						|
    }
 | 
						|
 | 
						|
    function build_list(message_groups) {
 | 
						|
        const list = new MessageListView(undefined, undefined, true);
 | 
						|
        list._message_groups = message_groups;
 | 
						|
        return list;
 | 
						|
    }
 | 
						|
 | 
						|
    function assert_moved_true(message_container) {
 | 
						|
        assert.equal(message_container.moved, true);
 | 
						|
    }
 | 
						|
    function assert_moved_false(message_container) {
 | 
						|
        assert.equal(message_container.moved, false);
 | 
						|
    }
 | 
						|
    function assert_moved_undefined(message_container) {
 | 
						|
        assert.equal(message_container.moved, undefined);
 | 
						|
    }
 | 
						|
 | 
						|
    (function test_msg_moved_var() {
 | 
						|
        const messages = [
 | 
						|
            // no edit history: NO LABEL
 | 
						|
            build_message_context({}),
 | 
						|
            // stream changed: MOVED
 | 
						|
            build_message_context({
 | 
						|
                edit_history: [{prev_stream: 1, timestamp: 1000, user_id: 1}],
 | 
						|
            }),
 | 
						|
            // topic changed (not resolved/unresolved): MOVED
 | 
						|
            build_message_context({
 | 
						|
                edit_history: [
 | 
						|
                    {prev_topic: "test_topic", topic: "new_topic", timestamp: 1000, user_id: 1},
 | 
						|
                ],
 | 
						|
            }),
 | 
						|
            // content edited: EDITED
 | 
						|
            build_message_context({
 | 
						|
                edit_history: [{prev_content: "test_content", timestamp: 1000, user_id: 1}],
 | 
						|
            }),
 | 
						|
            // stream and topic edited: MOVED
 | 
						|
            build_message_context({
 | 
						|
                edit_history: [
 | 
						|
                    {
 | 
						|
                        prev_stream: 1,
 | 
						|
                        prev_topic: "test_topic",
 | 
						|
                        topic: "new_topic",
 | 
						|
                        timestamp: 1000,
 | 
						|
                        user_id: 1,
 | 
						|
                    },
 | 
						|
                ],
 | 
						|
            }),
 | 
						|
            // topic and content changed: EDITED
 | 
						|
            build_message_context({
 | 
						|
                edit_history: [
 | 
						|
                    {
 | 
						|
                        prev_topic: "test_topic",
 | 
						|
                        topic: "new_topic",
 | 
						|
                        prev_content: "test_content",
 | 
						|
                        timestamp: 1000,
 | 
						|
                        user_id: 1,
 | 
						|
                    },
 | 
						|
                ],
 | 
						|
            }),
 | 
						|
            // only topic resolved: NO LABEL
 | 
						|
            build_message_context({
 | 
						|
                edit_history: [
 | 
						|
                    {prev_topic: "test_topic", topic: "✔ test_topic", timestamp: 1000, user_id: 1},
 | 
						|
                ],
 | 
						|
            }),
 | 
						|
            // only topic unresolved: NO LABEL
 | 
						|
            build_message_context({
 | 
						|
                edit_history: [
 | 
						|
                    {prev_topic: "✔ test_topic", topic: "test_topic", timestamp: 1000, user_id: 1},
 | 
						|
                ],
 | 
						|
            }),
 | 
						|
            // multiple edit history logs, with at least one content edit: EDITED
 | 
						|
            build_message_context({
 | 
						|
                edit_history: [
 | 
						|
                    {prev_stream: 1, timestamp: 1000, user_id: 1},
 | 
						|
                    {prev_topic: "old_topic", topic: "test_topic", timestamp: 1001, user_id: 1},
 | 
						|
                    {prev_content: "test_content", timestamp: 1002, user_id: 1},
 | 
						|
                    {prev_topic: "test_topic", topic: "✔ test_topic", timestamp: 1003, user_id: 1},
 | 
						|
                ],
 | 
						|
            }),
 | 
						|
            // multiple edit history logs with no content edit: MOVED
 | 
						|
            build_message_context({
 | 
						|
                edit_history: [
 | 
						|
                    {prev_stream: 1, timestamp: 1000, user_id: 1},
 | 
						|
                    {prev_topic: "old_topic", topic: "test_topic", timestamp: 1001, user_id: 1},
 | 
						|
                    {prev_topic: "test_topic", topic: "✔ test_topic", timestamp: 1002, user_id: 1},
 | 
						|
                    {prev_topic: "✔ test_topic", topic: "test_topic", timestamp: 1003, user_id: 1},
 | 
						|
                ],
 | 
						|
            }),
 | 
						|
        ];
 | 
						|
 | 
						|
        const message_group = build_message_group(messages);
 | 
						|
        const list = build_list([message_group]);
 | 
						|
 | 
						|
        for (const message_container of messages) {
 | 
						|
            list._maybe_format_me_message(message_container);
 | 
						|
            list._add_msg_edited_vars(message_container);
 | 
						|
        }
 | 
						|
 | 
						|
        const result = list._message_groups[0].message_containers;
 | 
						|
 | 
						|
        // no edit history: undefined
 | 
						|
        assert_moved_undefined(result[0]);
 | 
						|
        // stream changed: true
 | 
						|
        assert_moved_true(result[1]);
 | 
						|
        // topic changed: true
 | 
						|
        assert_moved_true(result[2]);
 | 
						|
        // content edited: false
 | 
						|
        assert_moved_false(result[3]);
 | 
						|
        // stream and topic edited: true
 | 
						|
        assert_moved_true(result[4]);
 | 
						|
        // topic and content changed: false
 | 
						|
        assert_moved_false(result[5]);
 | 
						|
        // only topic resolved: undefined
 | 
						|
        assert_moved_undefined(result[6]);
 | 
						|
        // only topic unresolved: undefined
 | 
						|
        assert_moved_undefined(result[7]);
 | 
						|
        // multiple edits with content edit: false
 | 
						|
        assert_moved_false(result[8]);
 | 
						|
        // multiple edits without content edit: true
 | 
						|
        assert_moved_true(result[9]);
 | 
						|
    })();
 | 
						|
});
 | 
						|
 | 
						|
test("msg_edited_vars", () => {
 | 
						|
    // This is a test to verify that only one of the three bools,
 | 
						|
    // `edited_in_left_col`, `edited_alongside_sender`, `edited_status_msg`
 | 
						|
    // is not false; Tests for three different kinds of messages:
 | 
						|
    //   * "/me" message
 | 
						|
    //   * message that includes sender
 | 
						|
    //   * message without sender
 | 
						|
 | 
						|
    function build_message_context(message = {}, message_context = {}) {
 | 
						|
        message_context = {
 | 
						|
            include_sender: true,
 | 
						|
            ...message_context,
 | 
						|
        };
 | 
						|
        message_context.msg = {
 | 
						|
            is_me_message: false,
 | 
						|
            last_edit_timestamp: (next_timestamp += 1),
 | 
						|
            edit_history: [{prev_content: "test_content", timestamp: 1000, user_id: 1}],
 | 
						|
            ...message,
 | 
						|
        };
 | 
						|
        return message_context;
 | 
						|
    }
 | 
						|
 | 
						|
    function build_message_group(messages) {
 | 
						|
        return {message_containers: messages};
 | 
						|
    }
 | 
						|
 | 
						|
    function build_list(message_groups) {
 | 
						|
        const list = new MessageListView(undefined, undefined, true);
 | 
						|
        list._message_groups = message_groups;
 | 
						|
        return list;
 | 
						|
    }
 | 
						|
 | 
						|
    function assert_left_col(message_container) {
 | 
						|
        assert.equal(message_container.edited_in_left_col, true);
 | 
						|
        assert.equal(message_container.edited_alongside_sender, false);
 | 
						|
        assert.equal(message_container.edited_status_msg, false);
 | 
						|
    }
 | 
						|
 | 
						|
    function assert_alongside_sender(message_container) {
 | 
						|
        assert.equal(message_container.edited_in_left_col, false);
 | 
						|
        assert.equal(message_container.edited_alongside_sender, true);
 | 
						|
        assert.equal(message_container.edited_status_msg, false);
 | 
						|
    }
 | 
						|
 | 
						|
    function assert_status_msg(message_container) {
 | 
						|
        assert.equal(message_container.edited_in_left_col, false);
 | 
						|
        assert.equal(message_container.edited_alongside_sender, false);
 | 
						|
        assert.equal(message_container.edited_status_msg, true);
 | 
						|
    }
 | 
						|
 | 
						|
    (function test_msg_edited_vars() {
 | 
						|
        const messages = [
 | 
						|
            build_message_context(),
 | 
						|
            build_message_context({}, {include_sender: false}),
 | 
						|
            build_message_context({is_me_message: true, content: "<p>/me test</p>"}),
 | 
						|
        ];
 | 
						|
        const message_group = build_message_group(messages);
 | 
						|
        const list = build_list([message_group]);
 | 
						|
 | 
						|
        for (const message_container of messages) {
 | 
						|
            list._maybe_format_me_message(message_container);
 | 
						|
            list._add_msg_edited_vars(message_container);
 | 
						|
        }
 | 
						|
 | 
						|
        const result = list._message_groups[0].message_containers;
 | 
						|
 | 
						|
        assert_alongside_sender(result[0]);
 | 
						|
        assert_left_col(result[1]);
 | 
						|
        assert_status_msg(result[2]);
 | 
						|
    })();
 | 
						|
});
 | 
						|
 | 
						|
test("muted_message_vars", () => {
 | 
						|
    // This verifies that the variables for muted/hidden messages are set
 | 
						|
    // correctly.
 | 
						|
 | 
						|
    function build_message_context(message = {}, message_context = {}) {
 | 
						|
        message_context = {
 | 
						|
            ...message_context,
 | 
						|
        };
 | 
						|
        message_context.msg = {
 | 
						|
            ...message,
 | 
						|
        };
 | 
						|
        return message_context;
 | 
						|
    }
 | 
						|
 | 
						|
    function build_message_group(messages) {
 | 
						|
        return {message_containers: messages};
 | 
						|
    }
 | 
						|
 | 
						|
    function build_list(message_groups) {
 | 
						|
        const list = new MessageListView(undefined, undefined, true);
 | 
						|
        list._message_groups = message_groups;
 | 
						|
        return list;
 | 
						|
    }
 | 
						|
 | 
						|
    function calculate_variables(list, messages, is_revealed) {
 | 
						|
        list.set_calculated_message_container_variables(messages[0], is_revealed);
 | 
						|
        list.set_calculated_message_container_variables(messages[1], is_revealed);
 | 
						|
        list.set_calculated_message_container_variables(messages[2], is_revealed);
 | 
						|
        return list._message_groups[0].message_containers;
 | 
						|
    }
 | 
						|
 | 
						|
    (function test_hidden_message_variables() {
 | 
						|
        // We want to have no search results, which apparently works like this.
 | 
						|
        // See https://chat.zulip.org/#narrow/stream/6-frontend/topic/set_find_results.20with.20no.20results/near/1414799
 | 
						|
        const empty_list_stub = $.create("empty-stub", {children: []});
 | 
						|
        $("<message-stub-1>").set_find_results(".user-mention:not(.silent)", empty_list_stub);
 | 
						|
        $("<message-stub2>").set_find_results(".user-mention:not(.silent)", empty_list_stub);
 | 
						|
        $("<message-stub-3>").set_find_results(".user-mention:not(.silent)", empty_list_stub);
 | 
						|
        // Make a representative message group of three messages.
 | 
						|
        const messages = [
 | 
						|
            build_message_context(
 | 
						|
                {sender_id: 10, content: "<message-stub-1>"},
 | 
						|
                {include_sender: true},
 | 
						|
            ),
 | 
						|
            build_message_context(
 | 
						|
                {mentioned: true, sender_id: 10, content: "<message-stub2>"},
 | 
						|
                {include_sender: false},
 | 
						|
            ),
 | 
						|
            build_message_context(
 | 
						|
                {sender_id: 10, content: "<message-stub-3>"},
 | 
						|
                {include_sender: false},
 | 
						|
            ),
 | 
						|
        ];
 | 
						|
        const message_group = build_message_group(messages);
 | 
						|
        const list = build_list([message_group]);
 | 
						|
        list._add_msg_edited_vars = noop;
 | 
						|
 | 
						|
        // Sender is not muted.
 | 
						|
        let result = calculate_variables(list, messages);
 | 
						|
 | 
						|
        // sanity check on mocked values
 | 
						|
        assert.equal(result[1].sender_is_bot, false);
 | 
						|
        assert.equal(result[1].sender_is_guest, false);
 | 
						|
        assert.equal(result[1].small_avatar_url, "fake/small/avatar/url");
 | 
						|
 | 
						|
        // Check that `is_hidden` is false on all messages, and `include_sender` has not changed.
 | 
						|
        assert.equal(result[0].is_hidden, false);
 | 
						|
        assert.equal(result[1].is_hidden, false);
 | 
						|
        assert.equal(result[2].is_hidden, false);
 | 
						|
 | 
						|
        assert.equal(result[0].include_sender, true);
 | 
						|
        assert.equal(result[1].include_sender, false);
 | 
						|
        assert.equal(result[2].include_sender, false);
 | 
						|
 | 
						|
        // Additionally test that the message with a mention is marked as such.
 | 
						|
        assert.equal(result[1].mention_classname, "group_mention");
 | 
						|
 | 
						|
        // Now, mute the sender.
 | 
						|
        muted_users.add_muted_user(10);
 | 
						|
        result = calculate_variables(list, messages);
 | 
						|
 | 
						|
        // Check that `is_hidden` is true and `include_sender` is false on all messages.
 | 
						|
        assert.equal(result[0].is_hidden, true);
 | 
						|
        assert.equal(result[1].is_hidden, true);
 | 
						|
        assert.equal(result[2].is_hidden, true);
 | 
						|
 | 
						|
        assert.equal(result[0].include_sender, false);
 | 
						|
        assert.equal(result[1].include_sender, false);
 | 
						|
        assert.equal(result[2].include_sender, false);
 | 
						|
 | 
						|
        // Additionally test that, both there is no mention classname even on that message
 | 
						|
        // which has a mention, since we don't want to display muted mentions so visibly.
 | 
						|
        assert.equal(result[1].mention_classname, null);
 | 
						|
 | 
						|
        // Now, reveal the hidden messages.
 | 
						|
        let is_revealed = true;
 | 
						|
        result = calculate_variables(list, messages, is_revealed);
 | 
						|
 | 
						|
        // Check that `is_hidden` is false and `include_sender` is true on all messages.
 | 
						|
        assert.equal(result[0].is_hidden, false);
 | 
						|
        assert.equal(result[1].is_hidden, false);
 | 
						|
        assert.equal(result[2].is_hidden, false);
 | 
						|
 | 
						|
        assert.equal(result[0].include_sender, true);
 | 
						|
        assert.equal(result[1].include_sender, true);
 | 
						|
        assert.equal(result[2].include_sender, true);
 | 
						|
 | 
						|
        // Additionally test that the message with a mention is marked as such.
 | 
						|
        assert.equal(result[1].mention_classname, "group_mention");
 | 
						|
 | 
						|
        // Now test rehiding muted user's message
 | 
						|
        is_revealed = false;
 | 
						|
        result = calculate_variables(list, messages, is_revealed);
 | 
						|
 | 
						|
        // Check that `is_hidden` is false and `include_sender` is false on all messages.
 | 
						|
        assert.equal(result[0].is_hidden, true);
 | 
						|
        assert.equal(result[1].is_hidden, true);
 | 
						|
        assert.equal(result[2].is_hidden, true);
 | 
						|
 | 
						|
        assert.equal(result[0].include_sender, false);
 | 
						|
        assert.equal(result[1].include_sender, false);
 | 
						|
        assert.equal(result[2].include_sender, false);
 | 
						|
 | 
						|
        // Additionally test that, both there is no mention classname even on that message
 | 
						|
        // which has a mention, since we don't want to display hidden mentions so visibly.
 | 
						|
        assert.equal(result[1].mention_classname, null);
 | 
						|
    })();
 | 
						|
});
 | 
						|
 | 
						|
test("merge_message_groups", () => {
 | 
						|
    // MessageListView has lots of DOM code, so we are going to test the message
 | 
						|
    // group merging logic on its own.
 | 
						|
 | 
						|
    function build_message_context(message = {}, message_context = {}) {
 | 
						|
        message_context = {
 | 
						|
            include_sender: true,
 | 
						|
            ...message_context,
 | 
						|
        };
 | 
						|
        message_context.msg = {
 | 
						|
            id: _.uniqueId("test_message_"),
 | 
						|
            status_message: false,
 | 
						|
            type: "stream",
 | 
						|
            stream: "Test stream 1",
 | 
						|
            stream_id: 2,
 | 
						|
            topic: "Test topic 1",
 | 
						|
            sender_email: "test@example.com",
 | 
						|
            timestamp: (next_timestamp += 1),
 | 
						|
            ...message,
 | 
						|
        };
 | 
						|
        return message_context;
 | 
						|
    }
 | 
						|
 | 
						|
    function build_message_group(messages) {
 | 
						|
        return {
 | 
						|
            message_containers: messages,
 | 
						|
            message_group_id: _.uniqueId("test_message_group_"),
 | 
						|
        };
 | 
						|
    }
 | 
						|
 | 
						|
    function build_list(message_groups) {
 | 
						|
        const table_name = "zfilt";
 | 
						|
        const filter = new Filter([{operator: "stream", operand: "foo"}]);
 | 
						|
 | 
						|
        const list = new message_list.MessageList({
 | 
						|
            table_name,
 | 
						|
            filter,
 | 
						|
        });
 | 
						|
 | 
						|
        const view = new MessageListView(list, table_name, true);
 | 
						|
        view._message_groups = message_groups;
 | 
						|
        view.list.unsubscribed_bookend_content = () => {};
 | 
						|
        view.list.subscribed_bookend_content = () => {};
 | 
						|
        return view;
 | 
						|
    }
 | 
						|
 | 
						|
    function extract_message_ids(lst) {
 | 
						|
        return lst.map((item) => item.msg.id);
 | 
						|
    }
 | 
						|
 | 
						|
    function assert_message_list_equal(list1, list2) {
 | 
						|
        const ids1 = extract_message_ids(list1);
 | 
						|
        const ids2 = extract_message_ids(list2);
 | 
						|
        assert.ok(ids1.length);
 | 
						|
        assert.deepEqual(ids1, ids2);
 | 
						|
    }
 | 
						|
 | 
						|
    function extract_group(group) {
 | 
						|
        return extract_message_ids(group.message_containers);
 | 
						|
    }
 | 
						|
 | 
						|
    function assert_message_groups_list_equal(list1, list2) {
 | 
						|
        const ids1 = list1.map((group) => extract_group(group));
 | 
						|
        const ids2 = list2.map((group) => extract_group(group));
 | 
						|
        assert.ok(ids1.length);
 | 
						|
        assert.deepEqual(ids1, ids2);
 | 
						|
    }
 | 
						|
 | 
						|
    (function test_empty_list_bottom() {
 | 
						|
        const list = build_list([]);
 | 
						|
        const message_group = build_message_group([build_message_context()]);
 | 
						|
 | 
						|
        const result = list.merge_message_groups([message_group], "bottom");
 | 
						|
 | 
						|
        assert_message_groups_list_equal(list._message_groups, [message_group]);
 | 
						|
        assert_message_groups_list_equal(result.append_groups, [message_group]);
 | 
						|
        assert.deepEqual(result.prepend_groups, []);
 | 
						|
        assert.deepEqual(result.rerender_groups, []);
 | 
						|
        assert.deepEqual(result.append_messages, []);
 | 
						|
    })();
 | 
						|
 | 
						|
    (function test_append_message_same_topic() {
 | 
						|
        const message1 = build_message_context();
 | 
						|
        const message_group1 = build_message_group([message1]);
 | 
						|
 | 
						|
        const message2 = build_message_context();
 | 
						|
        const message_group2 = build_message_group([message2]);
 | 
						|
 | 
						|
        const list = build_list([message_group1]);
 | 
						|
        const result = list.merge_message_groups([message_group2], "bottom");
 | 
						|
 | 
						|
        assert_message_groups_list_equal(list._message_groups, [
 | 
						|
            build_message_group([message1, message2]),
 | 
						|
        ]);
 | 
						|
        assert.deepEqual(result.append_groups, []);
 | 
						|
        assert.deepEqual(result.prepend_groups, []);
 | 
						|
        assert.deepEqual(result.rerender_groups, []);
 | 
						|
        assert_message_list_equal(result.append_messages, [message2]);
 | 
						|
    })();
 | 
						|
 | 
						|
    (function test_append_message_different_topic() {
 | 
						|
        const message1 = build_message_context();
 | 
						|
        const message_group1 = build_message_group([message1]);
 | 
						|
 | 
						|
        const message2 = build_message_context({topic: "Test topic 2"});
 | 
						|
        const message_group2 = build_message_group([message2]);
 | 
						|
 | 
						|
        const list = build_list([message_group1]);
 | 
						|
        const result = list.merge_message_groups([message_group2], "bottom");
 | 
						|
 | 
						|
        assert.ok(!message_group2.group_date_html);
 | 
						|
        assert_message_groups_list_equal(list._message_groups, [message_group1, message_group2]);
 | 
						|
        assert_message_groups_list_equal(result.append_groups, [message_group2]);
 | 
						|
        assert.deepEqual(result.prepend_groups, []);
 | 
						|
        assert.deepEqual(result.rerender_groups, []);
 | 
						|
        assert.deepEqual(result.append_messages, []);
 | 
						|
    })();
 | 
						|
 | 
						|
    (function test_append_message_different_topic_and_days() {
 | 
						|
        const message1 = build_message_context({timestamp: 1000});
 | 
						|
        const message_group1 = build_message_group([message1]);
 | 
						|
 | 
						|
        const message2 = build_message_context({topic: "Test topic 2", timestamp: 900000});
 | 
						|
        const message_group2 = build_message_group([message2]);
 | 
						|
 | 
						|
        const list = build_list([message_group1]);
 | 
						|
        const result = list.merge_message_groups([message_group2], "bottom");
 | 
						|
 | 
						|
        assert_message_groups_list_equal(list._message_groups, [message_group1, message_group2]);
 | 
						|
        assert_message_groups_list_equal(result.append_groups, [message_group2]);
 | 
						|
        assert.deepEqual(result.prepend_groups, []);
 | 
						|
        assert.deepEqual(result.rerender_groups, []);
 | 
						|
        assert.deepEqual(result.append_messages, []);
 | 
						|
        assert.equal(message_group2.group_date_html, "900000000");
 | 
						|
    })();
 | 
						|
 | 
						|
    (function test_append_message_different_day() {
 | 
						|
        const message1 = build_message_context({timestamp: 1000});
 | 
						|
        const message_group1 = build_message_group([message1]);
 | 
						|
 | 
						|
        const message2 = build_message_context({timestamp: 900000});
 | 
						|
        const message_group2 = build_message_group([message2]);
 | 
						|
 | 
						|
        const list = build_list([message_group1]);
 | 
						|
        const result = list.merge_message_groups([message_group2], "bottom");
 | 
						|
 | 
						|
        assert_message_groups_list_equal(list._message_groups, [message_group1]);
 | 
						|
        assert.deepEqual(result.append_groups, []);
 | 
						|
        assert.deepEqual(result.prepend_groups, []);
 | 
						|
        assert.deepEqual(result.rerender_groups, []);
 | 
						|
        assert.deepEqual(result.append_messages, [message2]);
 | 
						|
        assert.ok(list._message_groups[0].message_containers[1].want_date_divider);
 | 
						|
    })();
 | 
						|
 | 
						|
    (function test_append_message_historical() {
 | 
						|
        const message1 = build_message_context({historical: false});
 | 
						|
        const message_group1 = build_message_group([message1]);
 | 
						|
 | 
						|
        const message2 = build_message_context({historical: true});
 | 
						|
        const message_group2 = build_message_group([message2]);
 | 
						|
 | 
						|
        const list = build_list([message_group1]);
 | 
						|
        const result = list.merge_message_groups([message_group2], "bottom");
 | 
						|
 | 
						|
        assert.ok(message_group2.bookend_top);
 | 
						|
        assert_message_groups_list_equal(list._message_groups, [message_group1, message_group2]);
 | 
						|
        assert_message_groups_list_equal(result.append_groups, [message_group2]);
 | 
						|
        assert.deepEqual(result.prepend_groups, []);
 | 
						|
        assert.deepEqual(result.rerender_groups, []);
 | 
						|
        assert.deepEqual(result.append_messages, []);
 | 
						|
    })();
 | 
						|
 | 
						|
    (function test_append_message_same_topic_me_message() {
 | 
						|
        const message1 = build_message_context();
 | 
						|
        const message_group1 = build_message_group([message1]);
 | 
						|
 | 
						|
        const message2 = build_message_context({is_me_message: true});
 | 
						|
        const message_group2 = build_message_group([message2]);
 | 
						|
 | 
						|
        const list = build_list([message_group1]);
 | 
						|
        const result = list.merge_message_groups([message_group2], "bottom");
 | 
						|
 | 
						|
        assert.ok(message2.include_sender);
 | 
						|
        assert_message_groups_list_equal(list._message_groups, [
 | 
						|
            build_message_group([message1, message2]),
 | 
						|
        ]);
 | 
						|
        assert.deepEqual(result.append_groups, []);
 | 
						|
        assert.deepEqual(result.prepend_groups, []);
 | 
						|
        assert.deepEqual(result.rerender_groups, []);
 | 
						|
        assert_message_list_equal(result.append_messages, [message2]);
 | 
						|
    })();
 | 
						|
 | 
						|
    (function test_prepend_message_same_topic() {
 | 
						|
        const message1 = build_message_context();
 | 
						|
        const message_group1 = build_message_group([message1]);
 | 
						|
 | 
						|
        const message2 = build_message_context();
 | 
						|
        const message_group2 = build_message_group([message2]);
 | 
						|
 | 
						|
        const list = build_list([message_group1]);
 | 
						|
        const result = list.merge_message_groups([message_group2], "top");
 | 
						|
 | 
						|
        assert_message_groups_list_equal(list._message_groups, [
 | 
						|
            build_message_group([message2, message1]),
 | 
						|
        ]);
 | 
						|
        assert.deepEqual(result.append_groups, []);
 | 
						|
        assert.deepEqual(result.prepend_groups, []);
 | 
						|
        assert_message_groups_list_equal(result.rerender_groups, [
 | 
						|
            build_message_group([message2, message1]),
 | 
						|
        ]);
 | 
						|
        assert.deepEqual(result.append_messages, []);
 | 
						|
    })();
 | 
						|
 | 
						|
    (function test_prepend_message_different_topic() {
 | 
						|
        const message1 = build_message_context();
 | 
						|
        const message_group1 = build_message_group([message1]);
 | 
						|
 | 
						|
        const message2 = build_message_context({topic: "Test topic 2"});
 | 
						|
        const message_group2 = build_message_group([message2]);
 | 
						|
 | 
						|
        const list = build_list([message_group1]);
 | 
						|
        const result = list.merge_message_groups([message_group2], "top");
 | 
						|
 | 
						|
        assert_message_groups_list_equal(list._message_groups, [message_group2, message_group1]);
 | 
						|
        assert.deepEqual(result.append_groups, []);
 | 
						|
        assert_message_groups_list_equal(result.prepend_groups, [message_group2]);
 | 
						|
        assert.deepEqual(result.rerender_groups, []);
 | 
						|
        assert.deepEqual(result.append_messages, []);
 | 
						|
    })();
 | 
						|
 | 
						|
    (function test_prepend_message_different_topic_and_day() {
 | 
						|
        const message1 = build_message_context({timestamp: 900000});
 | 
						|
        const message_group1 = build_message_group([message1]);
 | 
						|
 | 
						|
        const message2 = build_message_context({topic: "Test topic 2", timestamp: 1000});
 | 
						|
        const message_group2 = build_message_group([message2]);
 | 
						|
 | 
						|
        const list = build_list([message_group1]);
 | 
						|
        const result = list.merge_message_groups([message_group2], "top");
 | 
						|
 | 
						|
        assert.equal(message_group1.group_date_html, "900000000");
 | 
						|
        assert_message_groups_list_equal(list._message_groups, [message_group2, message_group1]);
 | 
						|
        assert.deepEqual(result.append_groups, []);
 | 
						|
        assert_message_groups_list_equal(result.prepend_groups, [message_group2]);
 | 
						|
        assert.deepEqual(result.rerender_groups, [message_group1]);
 | 
						|
        assert.deepEqual(result.append_messages, []);
 | 
						|
    })();
 | 
						|
 | 
						|
    (function test_prepend_message_different_day() {
 | 
						|
        const message1 = build_message_context({timestamp: 900000});
 | 
						|
        const message_group1 = build_message_group([message1]);
 | 
						|
 | 
						|
        const message2 = build_message_context({timestamp: 1000});
 | 
						|
        const message_group2 = build_message_group([message2]);
 | 
						|
 | 
						|
        const list = build_list([message_group1]);
 | 
						|
        const result = list.merge_message_groups([message_group2], "top");
 | 
						|
 | 
						|
        assert.equal(message_group2.message_containers[1].date_divider_html, "900000000");
 | 
						|
        assert_message_groups_list_equal(list._message_groups, [message_group2]);
 | 
						|
        assert.deepEqual(result.append_groups, []);
 | 
						|
        assert.deepEqual(result.prepend_groups, []);
 | 
						|
        assert_message_groups_list_equal(result.rerender_groups, [message_group2]);
 | 
						|
        assert.deepEqual(result.append_messages, []);
 | 
						|
    })();
 | 
						|
 | 
						|
    (function test_prepend_message_historical() {
 | 
						|
        const message1 = build_message_context({historical: false});
 | 
						|
        const message_group1 = build_message_group([message1]);
 | 
						|
 | 
						|
        const message2 = build_message_context({historical: true});
 | 
						|
        const message_group2 = build_message_group([message2]);
 | 
						|
 | 
						|
        const list = build_list([message_group1]);
 | 
						|
        const result = list.merge_message_groups([message_group2], "top");
 | 
						|
 | 
						|
        assert.ok(message_group1.bookend_top);
 | 
						|
        assert_message_groups_list_equal(list._message_groups, [message_group2, message_group1]);
 | 
						|
        assert.deepEqual(result.append_groups, []);
 | 
						|
        assert_message_groups_list_equal(result.prepend_groups, [message_group2]);
 | 
						|
        assert.deepEqual(result.rerender_groups, []);
 | 
						|
        assert.deepEqual(result.append_messages, []);
 | 
						|
    })();
 | 
						|
});
 | 
						|
 | 
						|
test("render_windows", () => {
 | 
						|
    // We only render up to 400 messages at a time in our message list,
 | 
						|
    // and we only change the window (which is a range, really, with
 | 
						|
    // start/end) when the pointer moves outside of the window or close
 | 
						|
    // to the edges.
 | 
						|
 | 
						|
    const view = (function make_view() {
 | 
						|
        const table_name = "zfilt";
 | 
						|
        const filter = new Filter();
 | 
						|
 | 
						|
        const list = new message_list.MessageList({
 | 
						|
            table_name,
 | 
						|
            filter,
 | 
						|
        });
 | 
						|
 | 
						|
        const view = list.view;
 | 
						|
 | 
						|
        // Stub out functionality that is not core to the rendering window
 | 
						|
        // logic.
 | 
						|
        list.data.unmuted_messages = (messages) => messages;
 | 
						|
 | 
						|
        // We don't need to actually render the DOM.  The windowing logic
 | 
						|
        // sits above that layer.
 | 
						|
        view.render = noop;
 | 
						|
        view.rerender_preserving_scrolltop = noop;
 | 
						|
 | 
						|
        return view;
 | 
						|
    })();
 | 
						|
 | 
						|
    const list = view.list;
 | 
						|
 | 
						|
    (function test_with_empty_list() {
 | 
						|
        // The function should early exit here.
 | 
						|
        const rendered = view.maybe_rerender();
 | 
						|
        assert.equal(rendered, false);
 | 
						|
    })();
 | 
						|
 | 
						|
    let messages;
 | 
						|
 | 
						|
    function reset_list(opts) {
 | 
						|
        messages = _.range(opts.count).map((i) => ({
 | 
						|
            id: i,
 | 
						|
        }));
 | 
						|
        list.selected_idx = () => 0;
 | 
						|
        list.clear();
 | 
						|
 | 
						|
        list.add_messages(messages, {});
 | 
						|
    }
 | 
						|
 | 
						|
    function verify_no_move_range(start, end) {
 | 
						|
        // In our render window, there are up to 300 positions in
 | 
						|
        // the list where we can move the pointer without forcing
 | 
						|
        // a re-render.  The code avoids hasty re-renders for
 | 
						|
        // performance reasons.
 | 
						|
        for (const idx of _.range(start, end)) {
 | 
						|
            list.selected_idx = () => idx;
 | 
						|
            const rendered = view.maybe_rerender();
 | 
						|
            assert.equal(rendered, false);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    function verify_move(idx, range) {
 | 
						|
        const start = range[0];
 | 
						|
        const end = range[1];
 | 
						|
 | 
						|
        list.selected_idx = () => idx;
 | 
						|
        const rendered = view.maybe_rerender();
 | 
						|
        assert.equal(rendered, true);
 | 
						|
        assert.equal(view._render_win_start, start);
 | 
						|
        assert.equal(view._render_win_end, end);
 | 
						|
    }
 | 
						|
 | 
						|
    reset_list({count: 51});
 | 
						|
    verify_no_move_range(0, 51);
 | 
						|
 | 
						|
    reset_list({count: 450});
 | 
						|
    verify_no_move_range(0, 350);
 | 
						|
 | 
						|
    verify_move(350, [150, 450]);
 | 
						|
    verify_no_move_range(200, 400);
 | 
						|
 | 
						|
    verify_move(199, [0, 400]);
 | 
						|
    verify_no_move_range(50, 350);
 | 
						|
 | 
						|
    verify_move(350, [150, 450]);
 | 
						|
    verify_no_move_range(200, 400);
 | 
						|
 | 
						|
    verify_move(199, [0, 400]);
 | 
						|
    verify_no_move_range(0, 350);
 | 
						|
 | 
						|
    verify_move(400, [200, 450]);
 | 
						|
 | 
						|
    reset_list({count: 800});
 | 
						|
    verify_no_move_range(0, 350);
 | 
						|
 | 
						|
    verify_move(350, [150, 550]);
 | 
						|
    verify_no_move_range(200, 500);
 | 
						|
 | 
						|
    verify_move(500, [300, 700]);
 | 
						|
    verify_no_move_range(350, 650);
 | 
						|
 | 
						|
    verify_move(650, [450, 800]);
 | 
						|
    verify_no_move_range(500, 750);
 | 
						|
 | 
						|
    verify_move(499, [299, 699]);
 | 
						|
    verify_no_move_range(349, 649);
 | 
						|
 | 
						|
    verify_move(348, [148, 548]);
 | 
						|
    verify_no_move_range(198, 398);
 | 
						|
 | 
						|
    verify_move(197, [0, 400]);
 | 
						|
    verify_no_move_range(0, 350);
 | 
						|
});
 |