1/* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5"use strict"; 6 7const EXPORTED_SYMBOLS = [ 8 "assert_quick_filter_button_enabled", 9 "assert_quick_filter_bar_visible", 10 "toggle_quick_filter_bar", 11 "assert_constraints_expressed", 12 "toggle_boolean_constraints", 13 "toggle_tag_constraints", 14 "toggle_tag_mode", 15 "assert_tag_constraints_visible", 16 "assert_tag_constraints_checked", 17 "toggle_text_constraints", 18 "assert_text_constraints_checked", 19 "set_filter_text", 20 "assert_filter_text", 21 "assert_results_label_count", 22 "clear_constraints", 23]; 24 25var fdh = ChromeUtils.import( 26 "resource://testing-common/mozmill/FolderDisplayHelpers.jsm" 27); 28 29var { Assert } = ChromeUtils.import("resource://testing-common/Assert.jsm"); 30 31var mc = fdh.mc; 32// disable the deferred search processing! 33mc.window.QuickFilterBarMuxer.deferredUpdateSearch = 34 mc.window.QuickFilterBarMuxer.updateSearch; 35 36/** 37 * Maps names to bar DOM ids to simplify checking. 38 */ 39var nameToBarDomId = { 40 sticky: "qfb-sticky", 41 unread: "qfb-unread", 42 starred: "qfb-starred", 43 addrbook: "qfb-inaddrbook", 44 tags: "qfb-tags", 45 attachments: "qfb-attachment", 46}; 47 48function assert_quick_filter_button_enabled(aEnabled) { 49 if (mc.e("qfb-show-filter-bar").disabled == aEnabled) { 50 throw new Error( 51 "Quick filter bar button should be " + (aEnabled ? "enabled" : "disabled") 52 ); 53 } 54} 55 56function assert_quick_filter_bar_visible(aVisible) { 57 if (mc.e("quick-filter-bar").getBoundingClientRect().height > 0 != aVisible) { 58 throw new Error( 59 "Quick filter bar should be " + (aVisible ? "visible" : "collapsed") 60 ); 61 } 62} 63 64/** 65 * Toggle the state of the message filter bar as if by a mouse click. 66 */ 67function toggle_quick_filter_bar() { 68 mc.click(mc.e("qfb-show-filter-bar")); 69 fdh.wait_for_all_messages_to_load(); 70} 71 72/** 73 * Assert that the state of the constraints visually expressed by the bar is 74 * consistent with the passed-in constraints. This method does not verify 75 * that the search constraints are in effect. Check that elsewhere. 76 */ 77function assert_constraints_expressed(aConstraints) { 78 for (let name in nameToBarDomId) { 79 let domId = nameToBarDomId[name]; 80 let expectedValue = name in aConstraints ? aConstraints[name] : false; 81 let domNode = mc.e(domId); 82 if (domNode.checked !== expectedValue) { 83 throw new Error(name + "'s checked state should be " + expectedValue); 84 } 85 } 86} 87 88/** 89 * Toggle the given filter buttons by name (from nameToBarDomId); variable 90 * argument magic enabled. 91 */ 92function toggle_boolean_constraints(...aArgs) { 93 aArgs.forEach(arg => mc.click(mc.e(nameToBarDomId[arg]))); 94 fdh.wait_for_all_messages_to_load(mc); 95} 96 97/** 98 * Toggle the tag faceting buttons by tag key. Wait for messages after. 99 */ 100function toggle_tag_constraints(...aArgs) { 101 let qfbButtons = mc.e("quick-filter-bar-tab-bar"); 102 aArgs.forEach(function(arg) { 103 let tagId = "qfb-tag-" + arg; 104 qfbButtons.ensureElementIsVisible(mc.e(tagId)); 105 mc.click(mc.e(tagId)); 106 }); 107 fdh.wait_for_all_messages_to_load(mc); 108} 109 110/** 111 * Set the tag filtering mode. Wait for messages after. 112 */ 113function toggle_tag_mode() { 114 let qbm = mc.e("qfb-boolean-mode"); 115 if (qbm.value === "AND") { 116 qbm.selectedIndex--; // = move to "OR"; 117 Assert.equal(qbm.value, "OR", "qfb-boolean-mode has wrong state"); 118 } else if (qbm.value === "OR") { 119 qbm.selectedIndex++; // = move to "AND"; 120 Assert.equal(qbm.value, "AND", "qfb-boolean-mode has wrong state"); 121 } else { 122 throw new Error("qfb-boolean-mode value=" + qbm.value); 123 } 124 fdh.wait_for_all_messages_to_load(mc); 125} 126 127/** 128 * Verify that tag buttons exist for exactly the given set of tag keys in the 129 * provided variable argument list. Ordering is significant. 130 */ 131function assert_tag_constraints_visible(...aArgs) { 132 // the stupid bar should be visible if any arguments are specified 133 if (aArgs.length > 0 && mc.e("quick-filter-bar-tab-bar").collapsed) { 134 throw new Error("The tag bar should not be collapsed!"); 135 } 136 137 let kids = mc.e("quick-filter-bar-tab-bar").children; 138 let tagLength = kids.length - 1; // -1 for the qfb-boolean-mode widget 139 // this is bad error reporting in here for now. 140 if (tagLength != aArgs.length) { 141 throw new Error( 142 "Mismatch in expected tag count and actual. " + 143 "Expected " + 144 aArgs.length + 145 " actual " + 146 tagLength 147 ); 148 } 149 for (let iArg = 0; iArg < aArgs.length; iArg++) { 150 let nodeId = "qfb-tag-" + aArgs[iArg]; 151 if (nodeId != kids[iArg + 1].id) { 152 throw new Error( 153 "Mismatch at tag " + 154 iArg + 155 " expected " + 156 nodeId + 157 " but got " + 158 kids[iArg + 1].id 159 ); 160 } 161 } 162} 163 164/** 165 * Verify that only the buttons corresponding to the provided tag keys are 166 * checked. 167 */ 168function assert_tag_constraints_checked(...aArgs) { 169 let expected = {}; 170 for (let arg of aArgs) { 171 let nodeId = "qfb-tag-" + arg; 172 expected[nodeId] = true; 173 } 174 175 let kids = mc.e("quick-filter-bar-tab-bar").children; 176 for (let iNode = 0; iNode < kids.length; iNode++) { 177 let node = kids[iNode]; 178 if (node.checked != node.id in expected) { 179 throw new Error( 180 "node " + 181 node.id + 182 " should " + 183 (node.id in expected ? "be " : "not be ") + 184 "checked." 185 ); 186 } 187 } 188} 189 190var nameToTextDomId = { 191 sender: "qfb-qs-sender", 192 recipients: "qfb-qs-recipients", 193 subject: "qfb-qs-subject", 194 body: "qfb-qs-body", 195}; 196 197function toggle_text_constraints(...aArgs) { 198 aArgs.forEach(arg => mc.click(mc.e(nameToTextDomId[arg]))); 199 fdh.wait_for_all_messages_to_load(mc); 200} 201 202/** 203 * Assert that the text constraint buttons are checked. Variable-argument 204 * support where the arguments are one of sender/recipients/subject/body. 205 */ 206function assert_text_constraints_checked(...aArgs) { 207 let expected = {}; 208 for (let arg of aArgs) { 209 let nodeId = nameToTextDomId[arg]; 210 expected[nodeId] = true; 211 } 212 213 let kids = mc.e("quick-filter-bar-filter-text-bar").children; 214 for (let iNode = 0; iNode < kids.length; iNode++) { 215 let node = kids[iNode]; 216 if (node.tagName == "label") { 217 continue; 218 } 219 if (node.checked != node.id in expected) { 220 throw new Error( 221 "node " + 222 node.id + 223 " should " + 224 (node.id in expected ? "be " : "not be ") + 225 "checked." 226 ); 227 } 228 } 229} 230 231/** 232 * Set the text in the text filter box, trigger it like enter was pressed, then 233 * wait for all messages to load. 234 */ 235function set_filter_text(aText) { 236 // We're not testing the reliability of the textbox widget; just poke our text 237 // in and trigger the command logic. 238 let textbox = mc.e("qfb-qs-textbox"); 239 textbox.value = aText; 240 textbox.doCommand(); 241 fdh.wait_for_all_messages_to_load(mc); 242} 243 244function assert_filter_text(aText) { 245 let textbox = mc.e("qfb-qs-textbox"); 246 if (textbox.value != aText) { 247 throw new Error( 248 "Expected text filter value of '" + aText + "' but got '" + textbox.value 249 ); 250 } 251} 252 253/** 254 * Assert that the results label is telling us there are aCount messages 255 * using the appropriate string. 256 */ 257function assert_results_label_count(aCount) { 258 let resultsLabel = mc.e("qfb-results-label"); 259 if (aCount == 0) { 260 if (resultsLabel.value != resultsLabel.getAttribute("noresultsstring")) { 261 throw new Error( 262 "results label should be displaying the no messages case" 263 ); 264 } 265 } else { 266 let s = resultsLabel.value; 267 s = s.substring(0, s.indexOf(" ")); 268 if (parseInt(s) !== aCount) { 269 throw new Error( 270 "Result count is displaying " + s + " but should show " + aCount 271 ); 272 } 273 } 274} 275 276/** 277 * Clear active constraints via any means necessary; state cleanup for testing, 278 * not to be used as part of a test. Unlike normal clearing, this will kill 279 * the sticky bit. 280 * 281 * This is automatically called by the test teardown helper. 282 */ 283function clear_constraints() { 284 mc.window.QuickFilterBarMuxer._testHelperResetFilterState(); 285} 286