From 633f64a79efc78bff473b23633d944c365e5c135 Mon Sep 17 00:00:00 2001 From: Aman Agrawal Date: Wed, 17 Jan 2024 06:53:40 +0000 Subject: [PATCH] narrow: Use message list id to track message lists in DOM. This removes use of zfilt and zhome from codebase. --- templates/zerver/app/index.html | 7 +-- tools/message-screenshot.js | 8 ++- web/e2e-tests/compose.test.ts | 10 +-- web/e2e-tests/copy-and-paste.test.ts | 9 ++- web/e2e-tests/delete-message.test.ts | 14 +++-- web/e2e-tests/drafts.test.ts | 4 +- web/e2e-tests/edit.test.ts | 21 ++++--- web/e2e-tests/lib/common.ts | 36 +++++++++-- web/e2e-tests/mention.test.ts | 7 ++- web/e2e-tests/message-basics.test.ts | 93 ++++++++++++++++++++-------- web/e2e-tests/navigation.test.ts | 5 +- web/e2e-tests/stars.test.ts | 22 +++++-- web/src/compose_fade.js | 11 ++-- web/src/message_list.js | 15 ++--- web/src/message_list_view.js | 53 ++++++++-------- web/src/message_lists.ts | 6 +- web/src/narrow.js | 20 +++--- web/src/navigate.js | 5 +- web/src/rows.ts | 10 --- web/src/stream_color_events.js | 8 ++- web/src/timerender.ts | 4 +- web/src/upload.js | 2 +- web/src/widgetize.js | 5 +- web/templates/message_group.hbs | 2 +- web/templates/message_list.hbs | 1 + web/templates/single_message.hbs | 2 +- web/tests/message_fetch.test.js | 3 - web/tests/message_list_view.test.js | 56 ++++++++++------- web/tests/narrow_activate.test.js | 25 +++++++- web/tests/upload.test.js | 6 +- web/tests/widgetize.test.js | 6 +- 31 files changed, 297 insertions(+), 179 deletions(-) create mode 100644 web/templates/message_list.hbs diff --git a/templates/zerver/app/index.html b/templates/zerver/app/index.html index 38b6e2b499..4024167b6c 100644 --- a/templates/zerver/app/index.html +++ b/templates/zerver/app/index.html @@ -255,12 +255,7 @@
-
-
-
-
-
-
+
diff --git a/tools/message-screenshot.js b/tools/message-screenshot.js index 4880694afa..28ef29ee46 100644 --- a/tools/message-screenshot.js +++ b/tools/message-screenshot.js @@ -57,10 +57,14 @@ async function run() { await page.goto(`${options.realmUri}/#narrow/id/${options.messageId}`, { waitUntil: "networkidle2", }); - const messageSelector = `#zfilt${CSS.escape(options.messageId)}`; + // eslint-disable-next-line no-undef + const message_list_id = await page.evaluate(() => zulip_test.current_msg_list.id); + const messageSelector = `#message-row-${message_list_id}-${CSS.escape(options.messageId)}`; await page.waitForSelector(messageSelector); // remove unread marker and don't select message - const marker = `#zfilt${CSS.escape(options.messageId)} .unread_marker`; + const marker = `#message-row-${message_list_id}-${CSS.escape( + options.messageId, + )} .unread_marker`; await page.evaluate((sel) => $(sel).remove(), marker); const messageBox = await page.$(messageSelector); await page.evaluate((msg) => $(msg).removeClass("selected_message"), messageSelector); diff --git a/web/e2e-tests/compose.test.ts b/web/e2e-tests/compose.test.ts index 60d33ecf5d..6ba34d429b 100644 --- a/web/e2e-tests/compose.test.ts +++ b/web/e2e-tests/compose.test.ts @@ -28,14 +28,14 @@ function get_message_selector(text: string): string { } async function test_send_messages(page: Page): Promise { - const initial_msgs_count = (await page.$$("#zhome .message_row")).length; + const initial_msgs_count = (await page.$$(".message-list .message_row")).length; await common.send_multiple_messages(page, [ {stream_name: "Verona", topic: "Reply test", content: "Compose stream reply test"}, {recipient: "cordelia@zulip.com", content: "Compose direct message reply test"}, ]); - assert.equal((await page.$$("#zhome .message_row")).length, initial_msgs_count + 2); + assert.equal((await page.$$(".message-list .message_row")).length, initial_msgs_count + 2); } async function test_stream_compose_keyboard_shortcut(page: Page): Promise { @@ -138,7 +138,9 @@ async function test_send_multirecipient_pm_from_cordelia_pm_narrow(page: Page): // Go back to all messages view and make sure all messages are loaded. await page.click("#left-sidebar-navigation-list .top_left_all_messages"); - await page.waitForSelector("#zhome .message_row", {visible: true}); + await page.waitForSelector(".message-list .message_row", {visible: true}); + // Assert that there is only one message list. + assert.equal((await page.$$(".message-list")).length, 1); const pm = await page.waitForSelector( `xpath/(//*[${common.has_class_x( "messagebox", @@ -217,7 +219,7 @@ async function test_markdown_preview(page: Page): Promise { async function compose_tests(page: Page): Promise { await common.log_in(page); await page.click("#left-sidebar-navigation-list .top_left_all_messages"); - await page.waitForSelector("#zhome .message_row", {visible: true}); + await page.waitForSelector(".message-list .message_row", {visible: true}); await test_send_messages(page); await test_keyboard_shortcuts(page); await test_reply_by_click_prepopulates_stream_topic_names(page); diff --git a/web/e2e-tests/copy-and-paste.test.ts b/web/e2e-tests/copy-and-paste.test.ts index 4a892ec2bb..321465514d 100644 --- a/web/e2e-tests/copy-and-paste.test.ts +++ b/web/e2e-tests/copy-and-paste.test.ts @@ -12,7 +12,7 @@ async function copy_messages( return await page.evaluate( (start_message: string, end_message: string) => { function get_message_node(message: string): Element { - return [...document.querySelectorAll("#zhome .message_content")].find( + return [...document.querySelectorAll(".message-list .message_content")].find( (node) => node.textContent?.trim() === message, )!; } @@ -130,7 +130,9 @@ async function test_copying_messages_from_several_topics(page: Page): Promise { await common.log_in(page); await page.click("#left-sidebar-navigation-list .top_left_all_messages"); - await page.waitForSelector("#zhome .message_row", {visible: true}); + await page.waitForSelector(".message-list .message_row", {visible: true}); + // Assert that there is only one message list. + assert.equal((await page.$$(".message-list")).length, 1); await common.send_multiple_messages(page, [ {stream_name: "Verona", topic: "copy-paste-topic #1", content: "copy paste test A"}, @@ -148,7 +150,8 @@ async function copy_paste_test(page: Page): Promise { {stream_name: "Verona", topic: "copy-paste-topic #3", content: "copy paste test G"}, ]); - await common.check_messages_sent(page, "zhome", [ + const message_list_id = await common.get_current_msg_list_id(page, true); + await common.check_messages_sent(page, message_list_id, [ ["Verona > copy-paste-topic #1", ["copy paste test A", "copy paste test B"]], [ "Verona > copy-paste-topic #2", diff --git a/web/e2e-tests/delete-message.test.ts b/web/e2e-tests/delete-message.test.ts index 676f151c2d..3332e7564c 100644 --- a/web/e2e-tests/delete-message.test.ts +++ b/web/e2e-tests/delete-message.test.ts @@ -5,7 +5,7 @@ import type {Page} from "puppeteer"; import * as common from "./lib/common"; async function click_delete_and_return_last_msg_id(page: Page): Promise { - const msg = (await page.$$("#zhome .message_row")).at(-1); + const msg = (await page.$$(".message-list .message_row")).at(-1); assert.ok(msg !== undefined); const id = await (await msg.getProperty("id")).jsonValue(); await msg.hover(); @@ -23,8 +23,14 @@ async function click_delete_and_return_last_msg_id(page: Page): Promise async function delete_message_test(page: Page): Promise { await common.log_in(page); await page.click("#left-sidebar-navigation-list .top_left_all_messages"); - await page.waitForSelector("#zhome .message_row", {visible: true}); - const messages_quantity = (await page.$$("#zhome .message_row")).length; + const message_list_id = await common.get_current_msg_list_id(page, true); + await page.waitForSelector( + `.message-list[data-message-list-id='${message_list_id}'] .message_row`, + {visible: true}, + ); + // Assert that there is only one message list. + assert.equal((await page.$$(".message-list")).length, 1); + const messages_quantity = (await page.$$(".message-list .message_row")).length; const last_message_id = await click_delete_and_return_last_msg_id(page); await common.wait_for_micromodal_to_open(page); @@ -34,7 +40,7 @@ async function delete_message_test(page: Page): Promise { await common.wait_for_micromodal_to_close(page); await page.waitForSelector(`#${CSS.escape(last_message_id)}`, {hidden: true}); - assert.equal((await page.$$("#zhome .message_row")).length, messages_quantity - 1); + assert.equal((await page.$$(".message-list .message_row")).length, messages_quantity - 1); } common.run_test(delete_message_test); diff --git a/web/e2e-tests/drafts.test.ts b/web/e2e-tests/drafts.test.ts index 7d836d2724..0c1d2078a6 100644 --- a/web/e2e-tests/drafts.test.ts +++ b/web/e2e-tests/drafts.test.ts @@ -246,7 +246,9 @@ async function test_save_draft_by_reloading(page: Page): Promise { async function drafts_test(page: Page): Promise { await common.log_in(page); await page.click("#left-sidebar-navigation-list .top_left_all_messages"); - await page.waitForSelector("#zhome .message_row", {visible: true}); + await page.waitForSelector(".message-list .message_row", {visible: true}); + // Assert that there is only one message list. + assert.equal((await page.$$(".message-list")).length, 1); await test_empty_drafts(page); diff --git a/web/e2e-tests/edit.test.ts b/web/e2e-tests/edit.test.ts index ebad46e02d..9134487e96 100644 --- a/web/e2e-tests/edit.test.ts +++ b/web/e2e-tests/edit.test.ts @@ -5,7 +5,7 @@ import type {Page} from "puppeteer"; import * as common from "./lib/common"; async function trigger_edit_last_message(page: Page): Promise { - const msg = (await page.$$("#zhome .message_row")).at(-1); + const msg = (await page.$$(".message-list .message_row")).at(-1); assert.ok(msg !== undefined); const id = await (await msg.getProperty("id")).jsonValue(); await msg.hover(); @@ -29,7 +29,7 @@ async function edit_stream_message(page: Page, content: string): Promise { await common.wait_for_fully_processed_message(page, content); } -async function test_stream_message_edit(page: Page): Promise { +async function test_stream_message_edit(page: Page, message_list_id: number): Promise { await common.send_message(page, "stream", { stream_name: "Verona", topic: "edits", @@ -38,11 +38,13 @@ async function test_stream_message_edit(page: Page): Promise { await edit_stream_message(page, "test edited"); - await common.check_messages_sent(page, "zhome", [["Verona > edits", ["test edited"]]]); + await common.check_messages_sent(page, message_list_id, [["Verona > edits", ["test edited"]]]); } async function test_edit_message_with_slash_me(page: Page): Promise { - const last_message_xpath = `(//*[@id="zhome"]//*[${common.has_class_x("messagebox")}])[last()]`; + const last_message_xpath = `(//*[${common.has_class_x("message-list")}]//*[${common.has_class_x( + "messagebox", + )}])[last()]`; await common.send_message(page, "stream", { stream_name: "Verona", @@ -74,7 +76,7 @@ async function test_edit_message_with_slash_me(page: Page): Promise { ); } -async function test_edit_private_message(page: Page): Promise { +async function test_edit_private_message(page: Page, message_list_id: number): Promise { await common.send_message(page, "private", { recipient: "cordelia@zulip.com", content: "test editing pm", @@ -85,7 +87,7 @@ async function test_edit_private_message(page: Page): Promise { await page.click(".message_edit_save"); await common.wait_for_fully_processed_message(page, "test edited pm"); - await common.check_messages_sent(page, "zhome", [ + await common.check_messages_sent(page, message_list_id, [ ["You and Cordelia, Lear's daughter", ["test edited pm"]], ]); } @@ -93,11 +95,12 @@ async function test_edit_private_message(page: Page): Promise { async function edit_tests(page: Page): Promise { await common.log_in(page); await page.click("#left-sidebar-navigation-list .top_left_all_messages"); - await page.waitForSelector("#zhome .message_row", {visible: true}); + await page.waitForSelector(".message-list .message_row", {visible: true}); + const message_list_id = await common.get_current_msg_list_id(page, true); - await test_stream_message_edit(page); + await test_stream_message_edit(page, message_list_id); await test_edit_message_with_slash_me(page); - await test_edit_private_message(page); + await test_edit_private_message(page, message_list_id); } common.run_test(edit_tests); diff --git a/web/e2e-tests/lib/common.ts b/web/e2e-tests/lib/common.ts index 946f680116..14243f265e 100644 --- a/web/e2e-tests/lib/common.ts +++ b/web/e2e-tests/lib/common.ts @@ -26,6 +26,8 @@ export const is_firefox = process.env.PUPPETEER_PRODUCT === "firefox"; let realm_url = "http://zulip.zulipdev.com:9981/"; const gps = new StackTraceGPS({ajax: async (url) => (await fetch(url)).text()}); +let last_current_msg_list_id: number | null = null; + export const pm_recipient = { async set(page: Page, recipient: string): Promise { // Without using the delay option here there seems to be @@ -483,9 +485,11 @@ export async function send_multiple_messages(page: Page, msgs: Message[]): Promi */ export async function get_rendered_messages( page: Page, - table = "zhome", + message_list_id: number, ): Promise<[string, string[]][]> { - const recipient_rows = await page.$$(`#${CSS.escape(table)} .recipient_row`); + const recipient_rows = await page.$$( + `.message-list[data-message-list-id='${message_list_id}'] .recipient_row`, + ); return Promise.all( recipient_rows.map(async (element): Promise<[string, string[]]> => { const stream_label = await element.$(".stream_label"); @@ -519,11 +523,13 @@ export async function get_rendered_messages( // messages array passed exist in the order they are passed. export async function check_messages_sent( page: Page, - table: string, + message_list_id: number, messages: [string, string[]][], ): Promise { - await page.waitForSelector(`#${CSS.escape(table)}`, {visible: true}); - const rendered_messages = await get_rendered_messages(page, table); + await page.waitForSelector(`.message-list[data-message-list-id='${message_list_id}']`, { + visible: true, + }); + const rendered_messages = await get_rendered_messages(page, message_list_id); // We only check the last n messages because if we run // the test with --interactive there will be duplicates. @@ -714,3 +720,23 @@ export function run_test(test_function: (page: Page) => Promise): void { process.exit(1); }); } + +export async function get_current_msg_list_id( + page: Page, + wait_for_change = false, +): Promise { + if (wait_for_change) { + // Wait for the current_msg_list to change if the in the middle of switching narrows. + // Also works as a way to verify that the current message list did change. + // NOTE: This only checks if the current message list id changed from the last call to this function, + // so, make sure to have a call to this function before changing to the narrow that you want to check. + await page.waitForFunction( + (last_current_msg_list_id) => + zulip_test.current_msg_list.id !== last_current_msg_list_id, + {}, + last_current_msg_list_id, + ); + } + last_current_msg_list_id = await page.evaluate(() => zulip_test.current_msg_list.id); + return last_current_msg_list_id!; +} diff --git a/web/e2e-tests/mention.test.ts b/web/e2e-tests/mention.test.ts index 61492108d9..51d4b25c74 100644 --- a/web/e2e-tests/mention.test.ts +++ b/web/e2e-tests/mention.test.ts @@ -7,7 +7,7 @@ import * as common from "./lib/common"; async function test_mention(page: Page): Promise { await common.log_in(page); await page.click("#left-sidebar-navigation-list .top_left_all_messages"); - await page.waitForSelector("#zhome .message_row", {visible: true}); + await page.waitForSelector(".message-list .message_row", {visible: true}); await page.keyboard.press("KeyC"); await page.waitForSelector("#compose", {visible: true}); @@ -36,7 +36,10 @@ async function test_mention(page: Page): Promise { await page.click("#compose_banners .wildcard_warning .main-view-banner-action-button"); await page.waitForSelector(".wildcard_warning", {hidden: true}); - await common.check_messages_sent(page, "zhome", [["Verona > Test mention all", ["@all"]]]); + const message_list_id = await common.get_current_msg_list_id(page, true); + await common.check_messages_sent(page, message_list_id, [ + ["Verona > Test mention all", ["@all"]], + ]); } common.run_test(test_mention); diff --git a/web/e2e-tests/message-basics.test.ts b/web/e2e-tests/message-basics.test.ts index 527b8b311f..b910790812 100644 --- a/web/e2e-tests/message-basics.test.ts +++ b/web/e2e-tests/message-basics.test.ts @@ -10,7 +10,8 @@ async function get_stream_li(page: Page, stream_name: string): Promise { } async function expect_home(page: Page): Promise { - await common.check_messages_sent(page, "zhome", [ + const message_list_id = await common.get_current_msg_list_id(page, true); + await common.check_messages_sent(page, message_list_id, [ ["Verona > test", ["verona test a", "verona test b"]], ["Verona > other topic", ["verona other topic c"]], ["Denmark > test", ["denmark message"]], @@ -26,8 +27,11 @@ async function expect_home(page: Page): Promise { } async function expect_verona_stream(page: Page): Promise { - await page.waitForSelector("#zfilt", {visible: true}); - await common.check_messages_sent(page, "zfilt", [ + const message_list_id = await common.get_current_msg_list_id(page, true); + await page.waitForSelector(`.message-list[data-message-list-id='${message_list_id}']`, { + visible: true, + }); + await common.check_messages_sent(page, message_list_id, [ ["Verona > test", ["verona test a", "verona test b"]], ["Verona > other topic", ["verona other topic c"]], ["Verona > test", ["verona test d"]], @@ -36,8 +40,11 @@ async function expect_verona_stream(page: Page): Promise { } async function expect_verona_stream_test_topic(page: Page): Promise { - await page.waitForSelector("#zfilt", {visible: true}); - await common.check_messages_sent(page, "zfilt", [ + const message_list_id = await common.get_current_msg_list_id(page, true); + await page.waitForSelector(`.message-list[data-message-list-id='${message_list_id}']`, { + visible: true, + }); + await common.check_messages_sent(page, message_list_id, [ ["Verona > test", ["verona test a", "verona test b", "verona test d"]], ]); assert.strictEqual( @@ -47,15 +54,21 @@ async function expect_verona_stream_test_topic(page: Page): Promise { } async function expect_verona_other_topic(page: Page): Promise { - await page.waitForSelector("#zfilt", {visible: true}); - await common.check_messages_sent(page, "zfilt", [ + const message_list_id = await common.get_current_msg_list_id(page, true); + await page.waitForSelector(`.message-list[data-message-list-id='${message_list_id}']`, { + visible: true, + }); + await common.check_messages_sent(page, message_list_id, [ ["Verona > other topic", ["verona other topic c"]], ]); } async function expect_test_topic(page: Page): Promise { - await page.waitForSelector("#zfilt", {visible: true}); - await common.check_messages_sent(page, "zfilt", [ + const message_list_id = await common.get_current_msg_list_id(page, true); + await page.waitForSelector(`.message-list[data-message-list-id='${message_list_id}']`, { + visible: true, + }); + await common.check_messages_sent(page, message_list_id, [ ["Verona > test", ["verona test a", "verona test b"]], ["Denmark > test", ["denmark message"]], ["Verona > test", ["verona test d"]], @@ -63,8 +76,11 @@ async function expect_test_topic(page: Page): Promise { } async function expect_group_direct_messages(page: Page): Promise { - await page.waitForSelector("#zfilt", {visible: true}); - await common.check_messages_sent(page, "zfilt", [ + const message_list_id = await common.get_current_msg_list_id(page, true); + await page.waitForSelector(`.message-list[data-message-list-id='${message_list_id}']`, { + visible: true, + }); + await common.check_messages_sent(page, message_list_id, [ [ "You and Cordelia, Lear's daughter, King Hamlet", ["group direct message a", "group direct message b", "group direct message d"], @@ -77,8 +93,11 @@ async function expect_group_direct_messages(page: Page): Promise { } async function expect_cordelia_direct_messages(page: Page): Promise { - await page.waitForSelector("#zfilt", {visible: true}); - await common.check_messages_sent(page, "zfilt", [ + const message_list_id = await common.get_current_msg_list_id(page, true); + await page.waitForSelector(`.message-list[data-message-list-id='${message_list_id}']`, { + visible: true, + }); + await common.check_messages_sent(page, message_list_id, [ ["You and Cordelia, Lear's daughter", ["direct message c", "direct message e"]], ]); } @@ -88,7 +107,9 @@ async function un_narrow(page: Page): Promise { await page.keyboard.press("Escape"); } await page.click("#left-sidebar-navigation-list .top_left_all_messages"); - await page.waitForSelector("#zhome .message_row", {visible: true}); + await page.waitForSelector(".message-list .message_row", {visible: true}); + // Assert that there is only one message list. + assert.equal((await page.$$(".message-list")).length, 1); assert.strictEqual(await page.title(), "All messages - Zulip Dev - Zulip"); } @@ -104,7 +125,7 @@ async function expect_recent_view(page: Page): Promise { async function test_navigations_from_home(page: Page): Promise { return; // No idea why this is broken. console.log("Narrowing by clicking stream"); - await page.click(`#zhome [title='Narrow to stream "Verona"']`); + await page.click(`.focused-message-list [title='Narrow to stream "Verona"']`); await expect_verona_stream(page); assert.strictEqual(await page.title(), "#Verona - Zulip Dev - Zulip"); @@ -112,7 +133,7 @@ async function test_navigations_from_home(page: Page): Promise { await expect_home(page); console.log("Narrowing by clicking topic"); - await page.click(`#zhome [title='Narrow to stream "Verona", topic "test"']`); + await page.click(`.focused-message-list [title='Narrow to stream "Verona", topic "test"']`); await expect_verona_stream_test_topic(page); await un_narrow(page); @@ -121,7 +142,7 @@ async function test_navigations_from_home(page: Page): Promise { return; // TODO: rest of this test seems nondeterministically broken console.log("Narrowing by clicking group personal header"); await page.click( - `#zhome [title="Narrow to your direct messages with Cordelia, Lear's daughter, King Hamlet"]`, + `.focused-message-list [title="Narrow to your direct messages with Cordelia, Lear's daughter, King Hamlet"]`, ); await expect_group_direct_messages(page); @@ -129,7 +150,7 @@ async function test_navigations_from_home(page: Page): Promise { await expect_home(page); await page.click( - `#zhome [title="Narrow to your direct messages with Cordelia, Lear's daughter, King Hamlet"]`, + `.focused-message-list [title="Narrow to your direct messages with Cordelia, Lear's daughter, King Hamlet"]`, ); await un_narrow_by_clicking_org_icon(page); await expect_recent_view(page); @@ -161,11 +182,13 @@ async function search_silent_user(page: Page, str: string, item: string): Promis await common.get_text_from_selector(page, ".empty_feed_notice"), expect_message, ); + await common.get_current_msg_list_id(page, true); await un_narrow(page); await expect_home(page); } async function expect_non_existing_user(page: Page): Promise { + await common.get_current_msg_list_id(page, true); await page.waitForSelector(".empty_feed_notice", {visible: true}); const expected_message = "This user does not exist!"; assert.strictEqual( @@ -175,6 +198,7 @@ async function expect_non_existing_user(page: Page): Promise { } async function expect_non_existing_users(page: Page): Promise { + await common.get_current_msg_list_id(page, true); await page.waitForSelector(".empty_feed_notice", {visible: true}); const expected_message = "One or more of these users do not exist!"; assert.strictEqual( @@ -263,8 +287,11 @@ async function search_tests(page: Page): Promise { } async function expect_all_direct_messages(page: Page): Promise { - await page.waitForSelector("#zfilt", {visible: true}); - await common.check_messages_sent(page, "zfilt", [ + const message_list_id = await common.get_current_msg_list_id(page, true); + await page.waitForSelector(`.message-list[data-message-list-id='${message_list_id}']`, { + visible: true, + }); + await common.check_messages_sent(page, message_list_id, [ [ "You and Cordelia, Lear's daughter, King Hamlet", ["group direct message a", "group direct message b"], @@ -477,18 +504,34 @@ async function test_narrow_public_streams(page: Page): Promise { await page.click(".subscriptions-header .exit-sign"); await page.waitForSelector("#subscription_overlay", {hidden: true}); await page.goto(`http://zulip.zulipdev.com:9981/#narrow/stream/${stream_id}-Denmark`); - await page.waitForSelector("#zfilt .recipient_row ~ .recipient_row ~ .recipient_row"); - assert.ok((await page.$("#zfilt .stream-status")) !== null); + let message_list_id = await common.get_current_msg_list_id(page, true); + await page.waitForSelector( + `.message-list[data-message-list-id='${message_list_id}'] .recipient_row ~ .recipient_row ~ .recipient_row`, + ); + assert.ok( + (await page.$( + `.message-list[data-message-list-id='${message_list_id}'] .stream-status`, + )) !== null, + ); await page.goto("http://zulip.zulipdev.com:9981/#narrow/streams/public"); - await page.waitForSelector("#zfilt .recipient_row ~ .recipient_row ~ .recipient_row"); - assert.ok((await page.$("#zfilt .stream-status")) === null); + message_list_id = await common.get_current_msg_list_id(page, true); + await page.waitForSelector( + `.message-list[data-message-list-id='${message_list_id}'] .recipient_row ~ .recipient_row ~ .recipient_row`, + ); + assert.ok( + (await page.$( + `.message-list[data-message-list-id='${message_list_id}'] .stream-status`, + )) === null, + ); } async function message_basic_tests(page: Page): Promise { await common.log_in(page); await page.click("#left-sidebar-navigation-list .top_left_all_messages"); - await page.waitForSelector("#zhome .message_row", {visible: true}); + await page.waitForSelector(".message-list .message_row", {visible: true}); + // Assert that there is only one message list. + assert.equal((await page.$$(".message-list")).length, 1); console.log("Sending messages"); await common.send_multiple_messages(page, [ diff --git a/web/e2e-tests/navigation.test.ts b/web/e2e-tests/navigation.test.ts index e939f26a9a..3625d8b5df 100644 --- a/web/e2e-tests/navigation.test.ts +++ b/web/e2e-tests/navigation.test.ts @@ -71,7 +71,10 @@ async function test_reload_hash(page: Page): Promise { await page.evaluate(() => zulip_test.initiate_reload({immediate: true})); await page.waitForNavigation(); - await page.waitForSelector("#zfilt", {visible: true}); + const message_list_id = await common.get_current_msg_list_id(page, true); + await page.waitForSelector(`.message-list[data-message-list-id='${message_list_id}']`, { + visible: true, + }); const page_load_time = await page.evaluate(() => zulip_test.page_load_time); assert.ok(page_load_time > initial_page_load_time, "Page not reloaded."); diff --git a/web/e2e-tests/stars.test.ts b/web/e2e-tests/stars.test.ts index 8f924d2611..862a85f782 100644 --- a/web/e2e-tests/stars.test.ts +++ b/web/e2e-tests/stars.test.ts @@ -7,12 +7,12 @@ import * as common from "./lib/common"; const message = "test star"; async function stars_count(page: Page): Promise { - return (await page.$$("#zhome .zulip-icon-star-filled:not(.empty-star)")).length; + return (await page.$$(".message-list .zulip-icon-star-filled:not(.empty-star)")).length; } async function toggle_test_star_message(page: Page): Promise { const messagebox = await page.waitForSelector( - `xpath/(//*[@id="zhome"]//*[${common.has_class_x( + `xpath/(//*[${common.has_class_x("message-list")}]//*[${common.has_class_x( "message_content", )} and normalize-space()="${message}"])[last()]/ancestor::*[${common.has_class_x( "messagebox", @@ -29,17 +29,24 @@ async function toggle_test_star_message(page: Page): Promise { async function test_narrow_to_starred_messages(page: Page): Promise { await page.click('#left-sidebar-navigation-list a[href^="#narrow/is/starred"]'); - await common.check_messages_sent(page, "zfilt", [["Verona > stars", [message]]]); + const message_list_id = await common.get_current_msg_list_id(page, true); + await common.check_messages_sent(page, message_list_id, [["Verona > stars", [message]]]); // Go back to all messages narrow. await page.click("#left-sidebar-navigation-list .top_left_all_messages"); - await page.waitForSelector("#zhome .message_row", {visible: true}); + await page.waitForSelector(".message-list .message_row", {visible: true}); } async function stars_test(page: Page): Promise { await common.log_in(page); await page.click("#left-sidebar-navigation-list .top_left_all_messages"); - await page.waitForSelector("#zhome .message_row", {visible: true}); + const message_list_id = await common.get_current_msg_list_id(page, true); + await page.waitForSelector( + `.message-list[data-message-list-id='${message_list_id}'] .message_row`, + {visible: true}, + ); + // Assert that there is only one message list. + assert.equal((await page.$$(".message-list")).length, 1); await common.send_message(page, "stream", { stream_name: "Verona", topic: "stars", @@ -49,7 +56,10 @@ async function stars_test(page: Page): Promise { assert.strictEqual(await stars_count(page), 0, "Unexpected already starred message(s)."); await toggle_test_star_message(page); - await page.waitForSelector("#zhome .zulip-icon-star-filled", {visible: true}); + await page.waitForSelector( + `.message-list[data-message-list-id='${message_list_id}'] .zulip-icon-star-filled`, + {visible: true}, + ); assert.strictEqual( await stars_count(page), 1, diff --git a/web/src/compose_fade.js b/web/src/compose_fade.js index f1be5c50dc..ad25432e3d 100644 --- a/web/src/compose_fade.js +++ b/web/src/compose_fade.js @@ -42,8 +42,7 @@ export function set_focused_recipient(msg_type) { } function display_messages_normally() { - const $table = rows.get_table(message_lists.current.table_name); - $table.find(".recipient_row").removeClass("message-fade"); + message_lists.current.view.$list.find(".recipient_row").removeClass("message-fade"); normal_display = true; } @@ -77,9 +76,7 @@ function fade_messages() { // Defer updating all message groups so that the compose box can open sooner setTimeout( (expected_msg_list, expected_recipient) => { - const all_groups = rows - .get_table(message_lists.current.table_name) - .find(".recipient_row"); + const $all_groups = message_lists.current.view.$list.find(".recipient_row"); if ( message_lists.current !== expected_msg_list || @@ -93,8 +90,8 @@ function fade_messages() { // Note: The below algorithm relies on the fact that all_elts is // sorted as it would be displayed in the message view - for (i = 0; i < all_groups.length; i += 1) { - const $group_elt = $(all_groups[i]); + for (i = 0; i < $all_groups.length; i += 1) { + const $group_elt = $($all_groups[i]); should_fade_group = compose_fade_helper.should_fade_message( rows.recipient_from_group($group_elt), ); diff --git a/web/src/message_list.js b/web/src/message_list.js index 663878207f..1360b24bd8 100644 --- a/web/src/message_list.js +++ b/web/src/message_list.js @@ -17,6 +17,7 @@ import * as stream_data from "./stream_data"; import {user_settings} from "./user_settings"; export class MessageList { + static id_counter = 0; // A MessageList is the main interface for a message feed that is // rendered in the DOM. Code outside the message feed rendering // internals will directly call this module in order to manipulate @@ -30,6 +31,8 @@ export class MessageList { // is not particularly well-defined; it could be nice to figure // out a good rule. constructor(opts) { + MessageList.id_counter += 1; + this.id = MessageList.id_counter; // The MessageListData keeps track of the actual sequence of // messages displayed by this MessageList. Most // configuration/logic questions in this module will be @@ -46,11 +49,6 @@ export class MessageList { }); } - // The table_name is the outer HTML element for this message - // list in the DOM. - const table_name = opts.table_name; - this.table_name = table_name; - // TODO: This property should likely just be inlined into // having the MessageListView code that needs to access it // query .data.filter directly. @@ -59,7 +57,7 @@ export class MessageList { // The MessageListView object that is responsible for // maintaining this message feed's HTML representation in the // DOM. - this.view = new MessageListView(this, table_name, collapse_messages); + this.view = new MessageListView(this, collapse_messages, opts.is_node_test); // Whether this is a narrowed message list. The only message // list that is not is the home_msg_list global. @@ -266,7 +264,7 @@ export class MessageList { // false. if (!opts.use_closest && closest_id !== id) { error_data = { - table_name: this.table_name, + filter_terms: this.filter.terms(), id, closest_id, }; @@ -275,7 +273,7 @@ export class MessageList { if (closest_id === -1 && !opts.empty_ok) { error_data = { - table_name: this.table_name, + filter_terms: this.filter.terms(), id, items_length: this.data.num_items(), }; @@ -526,7 +524,6 @@ export class MessageList { export function initialize() { /* Create home_msg_list and register it. */ const home_msg_list = new MessageList({ - table_name: "zhome", filter: new Filter([{operator: "in", operand: "home"}]), excludes_muted_topics: true, }); diff --git a/web/src/message_list_view.js b/web/src/message_list_view.js index 8603fb2e0c..bd54debbe6 100644 --- a/web/src/message_list_view.js +++ b/web/src/message_list_view.js @@ -5,6 +5,7 @@ import * as resolved_topic from "../shared/src/resolved_topic"; import render_bookend from "../templates/bookend.hbs"; import render_login_to_view_image_button from "../templates/login_to_view_image_button.hbs"; import render_message_group from "../templates/message_group.hbs"; +import render_message_list from "../templates/message_list.hbs"; import render_recipient_row from "../templates/recipient_row.hbs"; import render_single_message from "../templates/single_message.hbs"; @@ -260,9 +261,12 @@ export class MessageListView { // Logic to compute context, render templates, insert them into // the DOM, and generally - constructor(list, table_name, collapse_messages) { + constructor(list, collapse_messages, is_node_test = false) { // The MessageList that this MessageListView is responsible for rendering. this.list = list; + this._add_message_list_to_DOM(); + // The jQuery element for the rendered list element. + this.$list = $(`.message-list[data-message-list-id="${this.list.id}"]`); // TODO: Access this via .list.data. this.collapse_messages = collapse_messages; @@ -285,12 +289,10 @@ export class MessageListView { this.message_containers = new Map(); this._message_groups = []; - // TODO: Should this be just accessing .list.table_name? - this.table_name = table_name; - if (this.table_name) { + if (!is_node_test) { + // Skip running this in node tests. this.clear_table(); } - // For performance reasons, this module renders at most // _RENDER_WINDOW_SIZE messages into the DOM at a time, and // will transparently adjust which messages are rendered @@ -312,6 +314,10 @@ export class MessageListView { // trigger a re-render _RENDER_THRESHOLD = 50; + _add_message_list_to_DOM() { + $("#message-lists-container").append(render_message_list({message_list_id: this.list.id})); + } + _get_msg_timestring(message_container) { let last_edit_timestamp; if (message_container.msg.local_edit_timestamp !== undefined) { @@ -782,7 +788,7 @@ export class MessageListView { message_container.msg.message_reactions = msg_reactions; const msg_to_render = { ...message_container, - table_name: this.table_name, + message_list_id: this.list.id, }; return render_single_message(msg_to_render); } @@ -790,13 +796,12 @@ export class MessageListView { _render_group(opts) { const message_groups = opts.message_groups; const use_match_properties = opts.use_match_properties; - const table_name = opts.table_name; return $( render_message_group({ message_groups, use_match_properties, - table_name, + message_list_id: this.list.id, }), ); } @@ -810,8 +815,6 @@ export class MessageListView { } const list = this.list; // for convenience - const table_name = this.table_name; - const $table = rows.get_table(table_name); let orig_scrolltop_offset; // If we start with the message feed scrolled up (i.e. @@ -857,7 +860,7 @@ export class MessageListView { return undefined; } - const new_message_groups = this.build_message_groups(message_containers, this.table_name); + const new_message_groups = this.build_message_groups(message_containers); const message_actions = this.merge_message_groups(new_message_groups, where); const new_dom_elements = []; let $rendered_groups; @@ -876,7 +879,6 @@ export class MessageListView { $rendered_groups = this._render_group({ message_groups: message_actions.prepend_groups, use_match_properties: this.list.is_keyword_search(), - table_name: this.table_name, }); $dom_messages = $rendered_groups.find(".message_row"); @@ -886,8 +888,8 @@ export class MessageListView { // The date row will be included in the message groups or will be // added in a rerendered in the group below - $table.find(".recipient_row").first().prev(".date_row").remove(); - $table.prepend($rendered_groups); + this.$list.find(".recipient_row").first().prev(".date_row").remove(); + this.$list.prepend($rendered_groups); condense.condense_and_collapse($dom_messages); } @@ -903,7 +905,6 @@ export class MessageListView { $rendered_groups = this._render_group({ message_groups: [message_group], use_match_properties: this.list.is_keyword_search(), - table_name: this.table_name, }); $dom_messages = $rendered_groups.find(".message_row"); @@ -917,7 +918,7 @@ export class MessageListView { // Insert new messages in to the last message group if (message_actions.append_messages.length > 0) { - $last_message_row = $table.find(".message_row").last().expectOne(); + $last_message_row = this.$list.find(".message_row").last().expectOne(); $last_group_row = rows.get_message_recipient_row($last_message_row); $dom_messages = $( message_actions.append_messages @@ -940,7 +941,6 @@ export class MessageListView { $rendered_groups = this._render_group({ message_groups: message_actions.append_groups, use_match_properties: this.list.is_keyword_search(), - table_name: this.table_name, }); $dom_messages = $rendered_groups.find(".message_row"); @@ -962,7 +962,7 @@ export class MessageListView { // this next line seems to prevent the Chrome bug from firing. message_viewport.scrollTop(); - $table.append($rendered_groups); + this.$list.append($rendered_groups); condense.condense_and_collapse($dom_messages); } @@ -1436,7 +1436,7 @@ export class MessageListView { // We do not want to call .empty() because that also clears // jQuery data. This does mean, however, that we need to be // mindful of memory leaks. - rows.get_table(this.table_name).children().detach(); + this.$list.children().detach(); this._rows.clear(); this._message_groups = []; this.message_containers.clear(); @@ -1455,7 +1455,7 @@ export class MessageListView { } clear_trailing_bookend() { - const $trailing_bookend = rows.get_table(this.table_name).find(".trailing_bookend"); + const $trailing_bookend = this.$list.find(".trailing_bookend"); $trailing_bookend.remove(); } @@ -1484,7 +1484,7 @@ export class MessageListView { is_web_public, }), ); - rows.get_table(this.table_name).append($rendered_trailing_bookend); + this.$list.append($rendered_trailing_bookend); } selected_row() { @@ -1501,7 +1501,7 @@ export class MessageListView { this._rows.delete(old_id); $row.attr("zid", new_id); - $row.attr("id", this.table_name + new_id); + $row.attr("id", `message-row-${this.list.id}-` + new_id); $row.removeClass("local"); this._rows.set(new_id, $row); } @@ -1570,8 +1570,7 @@ export class MessageListView { return 0; } - const $table = rows.get_table(this.table_name); - const $headers = $table.find(".message_header"); + const $headers = this.$list.find(".message_header"); const iterable_headers = $headers.toArray(); let start = 0; let end = iterable_headers.length - 1; @@ -1670,8 +1669,7 @@ export class MessageListView { } update_recipient_bar_background_color() { - const $table = rows.get_table(this.table_name); - const $stream_headers = $table.find(".message_header_stream"); + const $stream_headers = this.$list.find(".message_header_stream"); for (const stream_header of $stream_headers) { const $stream_header = $(stream_header); stream_color.update_stream_recipient_color($stream_header); @@ -1689,8 +1687,7 @@ export class MessageListView { } show_messages_as_unread(message_ids) { - const $table = rows.get_table(this.table_name); - const $rows_to_show_as_unread = $table.find(".message_row").filter((_index, $row) => { + const $rows_to_show_as_unread = this.$list.find(".message_row").filter((_index, $row) => { const message_id = Number.parseFloat($row.getAttribute("zid")); return message_ids.includes(message_id); }); diff --git a/web/src/message_lists.ts b/web/src/message_lists.ts index 6ec3550090..cf6092a841 100644 --- a/web/src/message_lists.ts +++ b/web/src/message_lists.ts @@ -1,4 +1,3 @@ -import $ from "jquery"; import assert from "minimalistic-assert"; import * as blueslip from "./blueslip"; @@ -15,11 +14,12 @@ type MessageListView = { _render_win_start: number; _render_win_end: number; sticky_recipient_message_id: number | undefined; + $list: JQuery; }; export type RenderInfo = {need_user_to_scroll: boolean}; export type MessageList = { - table_name: string; + id: number; view: MessageListView; selected_id: () => number; selected_row: () => JQuery; @@ -61,7 +61,7 @@ export function all_rendered_message_lists(): MessageList[] { export function all_current_message_rows(): JQuery { assert(current !== undefined); - return $(`#${CSS.escape(current.table_name)}.message-list .message_row`); + return current.view.$list.find(".message_row"); } export function update_recipient_bar_background_color(): void { diff --git a/web/src/narrow.js b/web/src/narrow.js index 74a945ece8..cd035376e0 100644 --- a/web/src/narrow.js +++ b/web/src/narrow.js @@ -420,16 +420,19 @@ export function activate(raw_terms, opts) { const msg_list = new message_list.MessageList({ data: msg_data, - table_name: "zfilt", }); // Show the new set of messages. It is important to set message_lists.current to // the view right as it's being shown, because we rely on message_lists.current // being shown for deciding when to condense messages. $("body").addClass("narrowed_view"); - $("#zfilt").addClass("focused-message-list"); - $("#zhome").removeClass("focused-message-list"); + msg_list.view.$list.addClass("focused-message-list"); + message_lists.home.view.$list.removeClass("focused-message-list"); + // Remove old message list from DOM. + if (message_lists.current !== message_lists.home) { + message_lists.current?.view.$list.remove(); + } message_lists.set_current(msg_list); let then_select_offset; @@ -1003,7 +1006,7 @@ function handle_post_narrow_deactivate_processes(msg_list) { message_feed_top_notices.update_top_of_narrow_notices(msg_list); // We may need to scroll to the selected message after swapping - // the currently displayed center panel to zhome. + // the currently displayed center panel to All messages. message_viewport.maybe_scroll_to_selected(); } @@ -1076,11 +1079,14 @@ export function deactivate() { narrow_state.set_has_shown_message_list_view(); $("body").removeClass("narrowed_view"); - $("#zfilt").removeClass("focused-message-list"); - $("#zhome").addClass("focused-message-list"); + message_lists.home.view.$list.addClass("focused-message-list"); + // Remove old message list from DOM. + if (message_lists.current !== message_lists.home) { + message_lists.current?.view.$list.remove(); + } message_lists.set_current(message_lists.home); message_lists.current.resume_reading(); - condense.condense_and_collapse($("#zhome div.message_row")); + condense.condense_and_collapse(message_lists.home.view.$list.find(".message_row")); reset_ui_state(); compose_recipient.handle_middle_pane_transition(); diff --git a/web/src/navigate.js b/web/src/navigate.js index 1b4cbd8044..c1fb520f0d 100644 --- a/web/src/navigate.js +++ b/web/src/navigate.js @@ -1,6 +1,5 @@ import * as message_lists from "./message_lists"; import * as message_viewport from "./message_viewport"; -import * as rows from "./rows"; import * as unread_ops from "./unread_ops"; function go_to_row(msg_id) { @@ -23,9 +22,9 @@ export function down(with_centering) { if (with_centering) { // At the last message, scroll to the bottom so we have // lots of nice whitespace for new messages coming in. - const $current_msg_table = rows.get_table(message_lists.current.table_name); + const $current_msg_list = message_lists.current.view.$list; message_viewport.scrollTop( - ($current_msg_table.outerHeight(true) ?? 0) - message_viewport.height() * 0.1, + ($current_msg_list.outerHeight(true) ?? 0) - message_viewport.height() * 0.1, ); unread_ops.process_scrolled_to_bottom(); } diff --git a/web/src/rows.ts b/web/src/rows.ts index 72b706d9d8..0131e1f4af 100644 --- a/web/src/rows.ts +++ b/web/src/rows.ts @@ -112,16 +112,6 @@ export function local_echo_id($message_row: JQuery): string | undefined { return zid; } -const valid_table_names = new Set(["zhome", "zfilt"]); - -export function get_table(table_name: string): JQuery { - if (!valid_table_names.has(table_name)) { - return $(); - } - - return $(`#${CSS.escape(table_name)}`); -} - export function get_message_id(elem: string): number | undefined { // Gets the message_id for elem, where elem is a DOM // element inside a message. This is typically used diff --git a/web/src/stream_color_events.js b/web/src/stream_color_events.js index 2bfd805946..4c689af33d 100644 --- a/web/src/stream_color_events.js +++ b/web/src/stream_color_events.js @@ -4,7 +4,6 @@ import * as inbox_util from "./inbox_util"; import * as message_lists from "./message_lists"; import * as message_view_header from "./message_view_header"; import * as overlays from "./overlays"; -import * as rows from "./rows"; import * as stream_color from "./stream_color"; import * as stream_data from "./stream_data"; @@ -30,8 +29,11 @@ function update_stream_privacy_color(id, color) { function update_message_recipient_color(stream_name, color) { const recipient_color = stream_color.get_recipient_bar_color(color); for (const msg_list of message_lists.all_rendered_message_lists()) { - const $table = rows.get_table(msg_list.table_name); - update_table_message_recipient_stream_color($table, stream_name, recipient_color); + update_table_message_recipient_stream_color( + msg_list.view.$list, + stream_name, + recipient_color, + ); } // Update color for drafts if open. diff --git a/web/src/timerender.ts b/web/src/timerender.ts index fb05b6956a..2e5c76df9f 100644 --- a/web/src/timerender.ts +++ b/web/src/timerender.ts @@ -404,8 +404,8 @@ export function update_timestamps(): void { const className = entry.className; const $elements = $(`.${CSS.escape(className)}`); // The element might not exist any more (because it - // was in the zfilt table, or because we added - // messages above it and re-collapsed). + // was in the narrowed message list which was removed, + // or because we added messages above it and re-collapsed). if ($elements.length > 0) { const time = entry.time; const rendered_time = render_now(time, today); diff --git a/web/src/upload.js b/web/src/upload.js index 9e1440034e..c05eedcfb7 100644 --- a/web/src/upload.js +++ b/web/src/upload.js @@ -118,7 +118,7 @@ export function get_item(key, config, file_id) { return "message-edit-file-input"; case "drag_drop_container": return $( - `#${message_lists.current.table_name}${CSS.escape( + `#message-row-${message_lists.current.id}-${CSS.escape( config.row, )} .message_edit_form`, ); diff --git a/web/src/widgetize.js b/web/src/widgetize.js index 530c31aa4f..eac464c0bc 100644 --- a/web/src/widgetize.js +++ b/web/src/widgetize.js @@ -49,7 +49,10 @@ export function activate(in_opts) { }); }; - if ($row.attr("id").startsWith("zhome") && narrow_state.active()) { + if ( + $row.attr("id").startsWith(`message-row-${message_lists.home.id}-`) && + narrow_state.active() + ) { // Don't place widget in a home message row if we are narrowed // to active state return; diff --git a/web/templates/message_group.hbs b/web/templates/message_group.hbs index a56b177325..99cc243af2 100644 --- a/web/templates/message_group.hbs +++ b/web/templates/message_group.hbs @@ -10,7 +10,7 @@ {{> recipient_row use_match_properties=../use_match_properties}} {{#each message_containers}} {{#with this}} - {{> single_message use_match_properties=../../use_match_properties table_name=../../table_name}} + {{> single_message use_match_properties=../../use_match_properties message_list_id=../../message_list_id}} {{/with}} {{/each}}
diff --git a/web/templates/message_list.hbs b/web/templates/message_list.hbs new file mode 100644 index 0000000000..498c6d4418 --- /dev/null +++ b/web/templates/message_list.hbs @@ -0,0 +1 @@ +
diff --git a/web/templates/single_message.hbs b/web/templates/single_message.hbs index 8679d9d666..6adad889fb 100644 --- a/web/templates/single_message.hbs +++ b/web/templates/single_message.hbs @@ -1,4 +1,4 @@ -
{{#if want_date_divider}} diff --git a/web/tests/message_fetch.test.js b/web/tests/message_fetch.test.js index af6775bb54..80468b36b3 100644 --- a/web/tests/message_fetch.test.js +++ b/web/tests/message_fetch.test.js @@ -65,11 +65,9 @@ const alice = { people.add_active_user(alice); function make_home_msg_list() { - const table_name = "whatever"; const filter = new Filter([]); const list = new message_list.MessageList({ - table_name, filter, }); return list; @@ -297,7 +295,6 @@ function simulate_narrow() { const filter = new Filter([{operator: "dm", operand: alice.email}]); const msg_list = new message_list.MessageList({ - table_name: "zfilt", filter, }); message_lists.current = msg_list; diff --git a/web/tests/message_list_view.test.js b/web/tests/message_list_view.test.js index cada5d86b2..2870a5e056 100644 --- a/web/tests/message_list_view.test.js +++ b/web/tests/message_list_view.test.js @@ -20,18 +20,6 @@ mock_esm("../src/timerender", { }, }); -mock_esm("../src/rows", { - get_table() { - return { - children() { - return { - detach: noop, - }; - }, - }; - }, -}); - mock_esm("../src/people", { sender_is_bot: () => false, sender_is_guest: () => false, @@ -47,9 +35,10 @@ const muted_users = zrequire("muted_users"); let next_timestamp = 1500000000; function test(label, f) { - run_test(label, ({override}) => { + run_test(label, ({override, mock_template}) => { muted_users.set_muted_users([]); - f({override}); + mock_template("message_list.hbs", false, noop); + f({override, mock_template}); }); } @@ -80,7 +69,13 @@ test("msg_moved_var", () => { } function build_list(message_groups) { - const list = new MessageListView(undefined, undefined, true); + const list = new MessageListView( + { + id: 1, + }, + true, + true, + ); list._message_groups = message_groups; return list; } @@ -229,7 +224,13 @@ test("msg_edited_vars", () => { } function build_list(message_groups) { - const list = new MessageListView(undefined, undefined, true); + const list = new MessageListView( + { + id: 1, + }, + true, + true, + ); list._message_groups = message_groups; return list; } @@ -293,7 +294,13 @@ test("muted_message_vars", () => { } function build_list(message_groups) { - const list = new MessageListView(undefined, undefined, true); + const list = new MessageListView( + { + id: 1, + }, + true, + true, + ); list._message_groups = message_groups; return list; } @@ -403,7 +410,8 @@ test("muted_message_vars", () => { })(); }); -test("merge_message_groups", () => { +test("merge_message_groups", ({mock_template}) => { + mock_template("message_list.hbs", false, noop); // MessageListView has lots of DOM code, so we are going to test the message // group merging logic on its own. @@ -433,15 +441,14 @@ test("merge_message_groups", () => { } 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, + is_node_test: true, }); - const view = new MessageListView(list, table_name, true); + const view = new MessageListView(list, true, true); view._message_groups = message_groups; view.list.unsubscribed_bookend_content = noop; view.list.subscribed_bookend_content = noop; @@ -687,19 +694,19 @@ test("merge_message_groups", () => { })(); }); -test("render_windows", () => { +test("render_windows", ({mock_template}) => { + mock_template("message_list.hbs", false, noop); // 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, + is_node_test: true, }); const view = list.view; @@ -731,6 +738,7 @@ test("render_windows", () => { id: i, })); list.selected_idx = () => 0; + list.view.clear_table = noop; list.clear(); list.add_messages(messages, {}); diff --git a/web/tests/narrow_activate.test.js b/web/tests/narrow_activate.test.js index fcb0be8ee9..c1a25dc484 100644 --- a/web/tests/narrow_activate.test.js +++ b/web/tests/narrow_activate.test.js @@ -21,8 +21,23 @@ const compose_recipient = mock_esm("../src/compose_recipient"); const message_fetch = mock_esm("../src/message_fetch"); const message_list = mock_esm("../src/message_list"); const message_lists = mock_esm("../src/message_lists", { - home: {}, - current: {}, + home: { + view: { + $list: { + removeClass: noop, + addClass: noop, + }, + }, + }, + current: { + view: { + $list: { + remove: noop, + removeClass: noop, + addClass: noop, + }, + }, + }, set_current(msg_list) { message_lists.current = msg_list; }, @@ -117,6 +132,12 @@ function stub_message_list() { set_message_offset(offset) { this.offset = offset; }, + + $list: { + remove: noop, + removeClass: noop, + addClass: noop, + }, }; get(msg_id) { diff --git a/web/tests/upload.test.js b/web/tests/upload.test.js index b9b26982e3..66ede82e03 100644 --- a/web/tests/upload.test.js +++ b/web/tests/upload.test.js @@ -30,7 +30,7 @@ const compose_ui = zrequire("compose_ui"); const upload = zrequire("upload"); const message_lists = zrequire("message_lists"); message_lists.current = { - table_name: "zfilt", + id: "1", }; function test(label, f) { run_test(label, (helpers) => { @@ -129,7 +129,7 @@ test("get_item", () => { assert.equal(upload.get_item("source", {mode: "edit", row: 123}), "message-edit-file-input"); assert.equal( upload.get_item("drag_drop_container", {mode: "edit", row: 1}), - $(`#zfilt${CSS.escape(1)} .message_edit_form`), + $(`#message-row-1-${CSS.escape(1)} .message_edit_form`), ); assert.equal( upload.get_item("markdown_preview_hide_button", {mode: "edit", row: 65}), @@ -769,7 +769,7 @@ test("main_file_drop_edit_mode", ({override, override_rewire}) => { prevent_default_counter += 1; }, }; - const $drag_drop_container = $(`#zfilt${CSS.escape(40)} .message_edit_form`); + const $drag_drop_container = $(`#message-row-1-${CSS.escape(40)} .message_edit_form`); // Dragover event test const dragover_handler = $(".app, #navbar-fixed-container").get_on_handler("dragover"); diff --git a/web/tests/widgetize.test.js b/web/tests/widgetize.test.js index 008b817624..b8902e3729 100644 --- a/web/tests/widgetize.test.js +++ b/web/tests/widgetize.test.js @@ -54,7 +54,7 @@ const fake_poll_widget = { }, }; -const message_lists = mock_esm("../src/message_lists", {current: {}}); +const message_lists = mock_esm("../src/message_lists", {current: {}, home: {id: 1}}); const narrow_state = mock_esm("../src/narrow_state"); mock_esm("../src/poll_widget", fake_poll_widget); @@ -80,8 +80,8 @@ test("activate", ({override}) => { // Both widgetize.activate and widgetize.handle_event are tested // here to use the "caching" of widgets const $row = $.create(""); - $row.attr("id", "zhome2909"); - const $message_content = $.create("#zhome2909"); + $row.attr("id", "message-row-1-2909"); + const $message_content = $.create("#message-row-1-2909"); $row.set_find_results(".message_content", $message_content); let narrow_active;