summaryrefslogtreecommitdiffstats
path: root/comm/mail/test/browser/folder-display/browser_summarization.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/test/browser/folder-display/browser_summarization.js')
-rw-r--r--comm/mail/test/browser/folder-display/browser_summarization.js462
1 files changed, 462 insertions, 0 deletions
diff --git a/comm/mail/test/browser/folder-display/browser_summarization.js b/comm/mail/test/browser/folder-display/browser_summarization.js
new file mode 100644
index 0000000000..6861a7e605
--- /dev/null
+++ b/comm/mail/test/browser/folder-display/browser_summarization.js
@@ -0,0 +1,462 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Test that summarization happens at the right time, that it clears itself at
+ * the right time, that it waits for selection stability when recently
+ * summarized, and that summarization does not break under tabbing.
+ *
+ * Because most of the legwork is done automatically by
+ * test-folder-display-helpers, the more basic tests may look like general
+ * selection / tabbing tests, but are intended to specifically exercise the
+ * summarization logic and edge cases. (Although general selection tests and
+ * tab tests may do the same thing too...)
+ *
+ * Things we don't test but should:
+ * - The difference between thread summary and multi-message summary.
+ */
+
+"use strict";
+
+var { ensure_card_exists, ensure_no_card_exists } = ChromeUtils.import(
+ "resource://testing-common/mozmill/AddressBookHelpers.jsm"
+);
+var {
+ add_message_sets_to_folders,
+ assert_collapsed,
+ assert_expanded,
+ assert_messages_summarized,
+ assert_message_not_in_view,
+ assert_nothing_selected,
+ assert_selected,
+ assert_selected_and_displayed,
+ assert_summary_contains_N_elts,
+ be_in_folder,
+ close_tab,
+ collapse_all_threads,
+ create_folder,
+ create_thread,
+ create_virtual_folder,
+ make_display_threaded,
+ make_display_unthreaded,
+ make_message_sets_in_folders,
+ mc,
+ open_folder_in_new_tab,
+ open_selected_message_in_new_tab,
+ plan_to_wait_for_folder_events,
+ select_click_row,
+ select_control_click_row,
+ select_none,
+ select_shift_click_row,
+ switch_tab,
+ toggle_thread_row,
+ wait_for_blank_content_pane,
+ wait_for_folder_events,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+var folder;
+var thread1, thread2, msg1, msg2;
+
+add_setup(async function () {
+ // Make sure the whole test starts with an unthreaded view in all folders.
+ Services.prefs.setIntPref("mailnews.default_view_flags", 0);
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("mailnews.default_view_flags");
+ });
+
+ folder = await create_folder("SummarizationA");
+ thread1 = create_thread(10);
+ msg1 = create_thread(1);
+ thread2 = create_thread(10);
+ msg2 = create_thread(1);
+ await add_message_sets_to_folders([folder], [thread1, msg1, thread2, msg2]);
+});
+
+add_task(async function test_basic_summarization() {
+ await be_in_folder(folder);
+
+ // - make sure we get a summary
+ select_click_row(0);
+ select_shift_click_row(5);
+ // this will verify a multi-message display is happening
+ assert_selected_and_displayed([0, 5]);
+});
+
+add_task(function test_summarization_goes_away() {
+ select_none();
+ assert_nothing_selected();
+});
+
+/**
+ * Verify that we update summarization when switching amongst tabs.
+ */
+add_task(async function test_folder_tabs_update_correctly() {
+ // tab with summary
+ let tabA = await be_in_folder(folder);
+ select_click_row(0);
+ select_control_click_row(2);
+ assert_selected_and_displayed(0, 2);
+
+ // tab with nothing
+ let tabB = await open_folder_in_new_tab(folder);
+ wait_for_blank_content_pane();
+ assert_nothing_selected();
+
+ // correct changes, none <=> summary
+ await switch_tab(tabA);
+ assert_selected_and_displayed(0, 2);
+ await switch_tab(tabB);
+ assert_nothing_selected();
+
+ // correct changes, one <=> summary
+ select_click_row(0);
+ assert_selected_and_displayed(0);
+ await switch_tab(tabA);
+ assert_selected_and_displayed(0, 2);
+ await switch_tab(tabB);
+ assert_selected_and_displayed(0);
+
+ // correct changes, summary <=> summary
+ select_shift_click_row(3);
+ assert_selected_and_displayed([0, 3]);
+ await switch_tab(tabA);
+ assert_selected_and_displayed(0, 2);
+ await switch_tab(tabB);
+ assert_selected_and_displayed([0, 3]);
+
+ // closing tab returns state correctly...
+ close_tab(tabB);
+ assert_selected_and_displayed(0, 2);
+});
+
+add_task(async function test_message_tabs_update_correctly() {
+ let tabFolder = await be_in_folder(folder);
+ let message = select_click_row(0);
+ assert_selected_and_displayed(0);
+
+ let tabMessage = await open_selected_message_in_new_tab();
+ assert_selected_and_displayed(message);
+
+ await switch_tab(tabFolder);
+ select_shift_click_row(2);
+ assert_selected_and_displayed([0, 2]);
+
+ await switch_tab(tabMessage);
+ assert_selected_and_displayed(message);
+
+ await switch_tab(tabFolder);
+ assert_selected_and_displayed([0, 2]);
+
+ close_tab(tabMessage);
+});
+
+/**
+ * Test the stabilization logic by making the stabilization interval absurd and
+ * then manually clearing things up.
+ */
+add_task(async function test_selection_stabilization_logic() {
+ // make sure all summarization has run to completion.
+ await new Promise(resolve => setTimeout(resolve));
+ // does not summarize anything, does not affect timer
+ select_click_row(0);
+ // does summarize things. timer will be tick tick ticking!
+ select_shift_click_row(1);
+ // verify that things were summarized...
+ assert_selected_and_displayed([0, 1]);
+ // save the set of messages so we can verify the summary sticks to this.
+ let messages = mc.window.gFolderDisplay.selectedMessages;
+
+ // make sure the
+
+ // this will not summarize!
+ select_shift_click_row(2, mc, true);
+ // verify that our summary is still just 0 and 1.
+ assert_messages_summarized(mc, messages);
+
+ // - pretend the timer fired.
+ // we need to de-schedule the timer, but do not need to clear the variable
+ // because it will just get overwritten anyways
+ mc.window.clearTimeout(mc.messageDisplay._summaryStabilityTimeout);
+ mc.messageDisplay._showSummary(true);
+
+ // - the summary should now be up-to-date
+ assert_selected_and_displayed([0, 2]);
+});
+
+add_task(function test_summarization_thread_detection() {
+ select_none();
+ assert_nothing_selected();
+ make_display_threaded();
+ select_click_row(0);
+ select_shift_click_row(9);
+ let messages = mc.window.gFolderDisplay.selectedMessages;
+ toggle_thread_row(0);
+ assert_messages_summarized(mc, messages);
+ // count the number of messages represented
+ assert_summary_contains_N_elts("#message_list > li", 10);
+ select_shift_click_row(1);
+ // this should have shifted to the multi-message view
+ assert_summary_contains_N_elts(".item_header > .date", 0);
+ assert_summary_contains_N_elts(".item_header > .subject", 2);
+ select_none();
+ assert_nothing_selected();
+ select_click_row(1); // select a single message
+ select_shift_click_row(2); // add a thread
+ assert_summary_contains_N_elts(".item_header > .date", 0);
+ assert_summary_contains_N_elts(".item_header > .subject", 2);
+});
+
+/**
+ * If you are looking at a message that becomes part of a thread because of the
+ * arrival of a new message, expand the thread so you do not have the message
+ * turn into a summary beneath your feet.
+ *
+ * There are really two cases here:
+ * - The thread gets moved because its sorted position changes.
+ * - The thread does not move.
+ */
+add_task(async function test_new_thread_that_was_not_summarized_expands() {
+ await be_in_folder(folder);
+ make_display_threaded();
+ // - create the base messages
+ let [willMoveMsg, willNotMoveMsg] = await make_message_sets_in_folders(
+ [folder],
+ [{ count: 1 }, { count: 1 }]
+ );
+
+ // - do the non-move case
+ // XXX actually, this still gets treated as a move. I don't know why...
+ // select it
+ select_click_row(willNotMoveMsg);
+ assert_selected_and_displayed(willNotMoveMsg);
+
+ // give it a friend...
+ await make_message_sets_in_folders(
+ [folder],
+ [{ count: 1, inReplyTo: willNotMoveMsg }]
+ );
+ assert_expanded(willNotMoveMsg);
+ assert_selected_and_displayed(willNotMoveMsg);
+
+ // - do the move case
+ select_click_row(willMoveMsg);
+ assert_selected_and_displayed(willMoveMsg);
+
+ // give it a friend...
+ await make_message_sets_in_folders(
+ [folder],
+ [{ count: 1, inReplyTo: willMoveMsg }]
+ );
+ assert_expanded(willMoveMsg);
+ assert_selected_and_displayed(willMoveMsg);
+});
+
+/**
+ * Selecting an existing (and collapsed) thread, then add a message and make
+ * sure the summary updates.
+ */
+add_task(
+ async function test_summary_updates_when_new_message_added_to_collapsed_thread() {
+ await be_in_folder(folder);
+ make_display_threaded();
+ collapse_all_threads();
+
+ // - select the thread root, thereby summarizing it
+ let thread1Root = select_click_row(thread1); // this just uses the root msg
+ assert_collapsed(thread1Root);
+ // just the thread root should be selected
+ assert_selected(thread1Root);
+ // but the whole thread should be summarized
+ assert_messages_summarized(mc, thread1);
+
+ // - add a new message, make sure it's in the summary now.
+ let [thread1Extra] = await make_message_sets_in_folders(
+ [folder],
+ [{ count: 1, inReplyTo: thread1 }]
+ );
+ let thread1All = thread1.union(thread1Extra);
+ assert_selected(thread1Root);
+ assert_messages_summarized(mc, thread1All);
+ }
+);
+
+add_task(async function test_summary_when_multiple_identities() {
+ // First half of the test, makes sure messageDisplay.js understands there's
+ // only one thread
+ let folder1 = await create_folder("Search1");
+ await be_in_folder(folder1);
+ let thread1 = create_thread(1);
+ await add_message_sets_to_folders([folder1], [thread1]);
+
+ let folder2 = await create_folder("Search2");
+ await be_in_folder(folder2);
+ await make_message_sets_in_folders(
+ [folder2],
+ [{ count: 1, inReplyTo: thread1 }]
+ );
+
+ let folderVirtual = create_virtual_folder(
+ [folder1, folder2],
+ {},
+ true,
+ "SearchBoth"
+ );
+
+ // Do the needed tricks
+ await be_in_folder(folder1);
+ select_click_row(0);
+ plan_to_wait_for_folder_events(
+ "DeleteOrMoveMsgCompleted",
+ "DeleteOrMoveMsgFailed"
+ );
+ mc.window.MsgMoveMessage(folder2);
+ wait_for_folder_events();
+
+ await be_in_folder(folder2);
+ select_click_row(1);
+ plan_to_wait_for_folder_events(
+ "DeleteOrMoveMsgCompleted",
+ "DeleteOrMoveMsgFailed"
+ );
+ mc.window.MsgMoveMessage(folder1);
+ wait_for_folder_events();
+
+ await be_in_folder(folderVirtual);
+ make_display_threaded();
+ collapse_all_threads();
+
+ // Assertions
+ select_click_row(0);
+ assert_messages_summarized(mc, mc.window.gFolderDisplay.selectedMessages);
+ // Thread summary shows a date, while multimessage summary shows a subject.
+ assert_summary_contains_N_elts(".item_header > .subject", 0);
+ assert_summary_contains_N_elts(".item_header > .date", 2);
+
+ // Second half of the test, makes sure MultiMessageSummary groups messages
+ // according to their view thread id
+ thread1 = create_thread(1);
+ await add_message_sets_to_folders([folder1], [thread1]);
+ await be_in_folder(folderVirtual);
+ select_shift_click_row(1);
+
+ assert_summary_contains_N_elts(".item_header > .subject", 2);
+});
+
+function extract_first_address(thread) {
+ let addresses = MailServices.headerParser.parseEncodedHeader(
+ thread1.getMsgHdr(0).mime2DecodedAuthor
+ );
+ return addresses[0];
+}
+
+function check_address_name(name) {
+ let htmlframe = mc.window.document.getElementById("multimessage");
+ let match = htmlframe.contentDocument.querySelector(".author");
+ if (match.textContent != name) {
+ throw new Error(
+ "Expected to find sender named '" +
+ name +
+ "', found '" +
+ match.textContent +
+ "'"
+ );
+ }
+}
+
+add_task(async function test_display_name_no_abook() {
+ await be_in_folder(folder);
+
+ let address = extract_first_address(thread1);
+ ensure_no_card_exists(address.email);
+
+ collapse_all_threads();
+ select_click_row(thread1);
+
+ // No address book entry, we display name and e-mail address.
+ check_address_name(address.name + " <" + address.email + ">");
+});
+
+add_task(async function test_display_name_abook() {
+ await be_in_folder(folder);
+
+ let address = extract_first_address(thread1);
+ ensure_card_exists(address.email, "My Friend", true);
+
+ collapse_all_threads();
+ select_click_row(thread1);
+
+ check_address_name("My Friend");
+});
+
+add_task(async function test_display_name_abook_no_pdn() {
+ await be_in_folder(folder);
+
+ let address = extract_first_address(thread1);
+ ensure_card_exists(address.email, "My Friend", false);
+
+ collapse_all_threads();
+ select_click_row(thread1);
+
+ // With address book entry but display name not preferred, we display name and
+ // e-mail address.
+ check_address_name(address.name + " <" + address.email + ">");
+
+ Assert.report(
+ false,
+ undefined,
+ undefined,
+ "Test ran to completion successfully"
+ );
+});
+
+add_task(async function test_archive_and_delete_messages() {
+ await be_in_folder(folder);
+ select_none();
+ assert_nothing_selected();
+ make_display_unthreaded();
+ select_click_row(0);
+ select_shift_click_row(2);
+ let messages = mc.window.gFolderDisplay.selectedMessages;
+
+ let contentWindow =
+ mc.window.document.getElementById("multimessage").contentWindow;
+ // Archive selected messages.
+ plan_to_wait_for_folder_events(
+ "DeleteOrMoveMsgCompleted",
+ "DeleteOrMoveMsgFailed"
+ );
+ EventUtils.synthesizeMouseAtCenter(
+ contentWindow.document.getElementById("hdrArchiveButton"),
+ {},
+ contentWindow
+ );
+
+ wait_for_folder_events();
+ assert_message_not_in_view(messages);
+
+ select_none();
+ assert_nothing_selected();
+ select_click_row(0);
+ select_shift_click_row(2);
+ messages = mc.window.gFolderDisplay.selectedMessages;
+
+ // Delete selected messages.
+ plan_to_wait_for_folder_events(
+ "DeleteOrMoveMsgCompleted",
+ "DeleteOrMoveMsgFailed"
+ );
+ EventUtils.synthesizeMouseAtCenter(
+ contentWindow.document.getElementById("hdrTrashButton"),
+ {},
+ contentWindow
+ );
+ wait_for_folder_events();
+ assert_message_not_in_view(messages);
+});