browser_tableWidget_mouse_interaction.js (9813B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 // Tests that mosue interaction works fine with the table widget 5 6 "use strict"; 7 8 const TEST_URI = CHROME_URL_ROOT + "doc_tableWidget_mouse_interaction.xhtml"; 9 const TEST_OPT = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no"; 10 11 const { 12 TableWidget, 13 } = require("resource://devtools/client/shared/widgets/TableWidget.js"); 14 15 var doc, table; 16 17 function test() { 18 waitForExplicitFinish(); 19 const win = Services.ww.openWindow(null, TEST_URI, "_blank", TEST_OPT, null); 20 21 win.addEventListener( 22 "load", 23 function () { 24 waitForFocus(function () { 25 doc = win.document; 26 table = new TableWidget(doc.querySelector("box"), { 27 initialColumns: { 28 col1: "Column 1", 29 col2: "Column 2", 30 col3: "Column 3", 31 col4: "Column 4", 32 }, 33 uniqueId: "col1", 34 emptyText: "This is dummy empty text", 35 highlightUpdated: true, 36 removableColumns: true, 37 wrapTextInElements: true, 38 l10n: { 39 setAttributes() {}, 40 }, 41 }); 42 startTests(); 43 }); 44 }, 45 { once: true } 46 ); 47 } 48 49 function endTests() { 50 table.destroy(); 51 doc.defaultView.close(); 52 doc = table = null; 53 finish(); 54 } 55 56 var startTests = async function () { 57 populateTable(); 58 await testMouseInteraction(); 59 endTests(); 60 }; 61 62 function populateTable() { 63 table.push({ 64 col1: "id1", 65 col2: "value10", 66 col3: "value20", 67 col4: "value30", 68 }); 69 table.push({ 70 col1: "id2", 71 col2: "value14", 72 col3: "value29", 73 col4: "value32", 74 }); 75 table.push({ 76 col1: "id3", 77 col2: "value17", 78 col3: "value21", 79 col4: "value31", 80 extraData: "foobar", 81 extraData2: 42, 82 }); 83 table.push({ 84 col1: "id4", 85 col2: "value12", 86 col3: "value26", 87 col4: "value33", 88 }); 89 table.push({ 90 col1: "id5", 91 col2: "value19", 92 col3: "value26", 93 col4: "value37", 94 }); 95 table.push({ 96 col1: "id6", 97 col2: "value15", 98 col3: "value25", 99 col4: "value37", 100 }); 101 table.push({ 102 col1: "id7", 103 col2: "value18", 104 col3: "value21", 105 col4: "value36", 106 somethingExtra: "Hello World!", 107 }); 108 table.push({ 109 col1: "id8", 110 col2: "value11", 111 col3: "value27", 112 col4: "value34", 113 }); 114 table.push({ 115 col1: "id9", 116 col2: "value11", 117 col3: "value23", 118 col4: "value38", 119 }); 120 } 121 122 // Sends a click event on the passed DOM node in an async manner 123 function click(node, button = 0) { 124 if (button == 0) { 125 executeSoon(() => 126 EventUtils.synthesizeMouseAtCenter(node, {}, doc.defaultView) 127 ); 128 } else { 129 executeSoon(() => 130 EventUtils.synthesizeMouseAtCenter( 131 node, 132 { 133 button, 134 type: "contextmenu", 135 }, 136 doc.defaultView 137 ) 138 ); 139 } 140 } 141 142 async function showCol(id) { 143 const onPopupHidden = once(table.menupopup, "popuphidden"); 144 const event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU); 145 const menuItem = table.menupopup.querySelector(`[data-id='${id}']`); 146 const column = table.tbody.querySelector(`#${id}`); 147 148 info(`Showing ${id}`); 149 ok(BrowserTestUtils.isHidden(column), "Column is hidden before showing it"); 150 151 table.menupopup.activateItem(menuItem); 152 const toShow = await event; 153 await onPopupHidden; 154 155 is(toShow, id, `#${id} was selected to be shown`); 156 ok( 157 BrowserTestUtils.isVisible(column), 158 "Column is not hidden after showing it" 159 ); 160 } 161 162 async function hideCol(id) { 163 const onPopupHidden = once(table.menupopup, "popuphidden"); 164 const event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU); 165 const menuItem = table.menupopup.querySelector(`[data-id='${id}']`); 166 const column = table.tbody.querySelector(`#${id}`); 167 168 info(`selecting to hide #${id}`); 169 ok( 170 BrowserTestUtils.isVisible(column), 171 `Column #${id} is not hidden before hiding it` 172 ); 173 table.menupopup.activateItem(menuItem); 174 const toHide = await event; 175 await onPopupHidden; 176 is(toHide, id, `#${id} was selected to be hidden`); 177 ok( 178 BrowserTestUtils.isHidden(column), 179 `Column #${id} is hidden after hiding it` 180 ); 181 } 182 183 /** 184 * Tests if clicking the table items does the expected behavior 185 */ 186 var testMouseInteraction = async function () { 187 info("Testing mouse interaction with the table"); 188 ok(!table.selectedRow, "Nothing should be selected beforehand"); 189 190 let event = table.once(TableWidget.EVENTS.ROW_SELECTED); 191 const firstColumnFirstRowCell = table.tbody.querySelector("[data-id=id1]"); 192 info("clicking on the first row"); 193 ok( 194 !firstColumnFirstRowCell.classList.contains("theme-selected"), 195 "Node should not have selected class before clicking" 196 ); 197 click(firstColumnFirstRowCell); 198 let id = await event; 199 ok( 200 firstColumnFirstRowCell.classList.contains("theme-selected"), 201 "Node has selected class after click" 202 ); 203 is(id, "id1", "Correct row was selected"); 204 205 info("clicking on second row to select it"); 206 event = table.once(TableWidget.EVENTS.ROW_SELECTED); 207 const firstColumnSecondRowCell = table.tbody.firstChild.children[2]; 208 // node should not have selected class 209 ok( 210 !firstColumnSecondRowCell.classList.contains("theme-selected"), 211 "New node should not have selected class before clicking" 212 ); 213 click(firstColumnSecondRowCell); 214 id = await event; 215 ok( 216 firstColumnSecondRowCell.classList.contains("theme-selected"), 217 "New node has selected class after clicking" 218 ); 219 is(id, "id2", "Correct table path is emitted for new node"); 220 isnot( 221 firstColumnFirstRowCell, 222 firstColumnSecondRowCell, 223 "Old and new node are different" 224 ); 225 ok( 226 !firstColumnFirstRowCell.classList.contains("theme-selected"), 227 "Old node should not have selected class after the click on new node" 228 ); 229 230 info("clicking on the third row cell content to select third row"); 231 event = table.once(TableWidget.EVENTS.ROW_SELECTED); 232 const firstColumnThirdRowCell = table.tbody.firstChild.children[3]; 233 const firstColumnThirdRowCellInnerNode = 234 firstColumnThirdRowCell.querySelector("span"); 235 // node should not have selected class 236 ok( 237 !firstColumnThirdRowCell.classList.contains("theme-selected"), 238 "New node should not have selected class before clicking" 239 ); 240 click(firstColumnThirdRowCellInnerNode); 241 id = await event; 242 ok( 243 firstColumnThirdRowCell.classList.contains("theme-selected"), 244 "New node has selected class after clicking the cell content" 245 ); 246 is(id, "id3", "Correct table path is emitted for new node"); 247 248 // clicking on table header to sort by it 249 event = table.once(TableWidget.EVENTS.COLUMN_SORTED); 250 let node = table.tbody.children[6].children[0]; 251 info("clicking on the 4th coulmn header to sort the table by it"); 252 ok( 253 !node.hasAttribute("sorted"), 254 "Node should not have sorted attribute before clicking" 255 ); 256 ok( 257 doc.querySelector("[sorted]"), 258 "Although, something else should be sorted on" 259 ); 260 isnot(doc.querySelector("[sorted]"), node, "Which is not equal to this node"); 261 click(node); 262 id = await event; 263 is(id, "col4", "Correct column was sorted on"); 264 ok( 265 node.hasAttribute("sorted"), 266 "Node should now have sorted attribute after clicking" 267 ); 268 is( 269 doc.querySelectorAll("[sorted]").length, 270 1, 271 "Now only one column should be sorted on" 272 ); 273 is(doc.querySelector("[sorted]"), node, "Which should be this column"); 274 275 // test context menu opening. 276 // hiding second column 277 // event listener for popupshown 278 info("right click on the first column header"); 279 node = table.tbody.firstChild.firstChild; 280 let onPopupShown = once(table.menupopup, "popupshown"); 281 click(node, 2); 282 await onPopupShown; 283 284 is( 285 table.menupopup.querySelectorAll("menuitem[disabled]").length, 286 1, 287 "Only 1 menuitem is disabled" 288 ); 289 is( 290 table.menupopup.querySelector("menuitem[disabled]"), 291 table.menupopup.querySelector("[data-id='col1']"), 292 "Which is the unique column" 293 ); 294 295 // popup should be open now 296 // clicking on second column label 297 await hideCol("col2"); 298 299 // hiding third column 300 // event listener for popupshown 301 info("right clicking on the first column header"); 302 node = table.tbody.firstChild.firstChild; 303 onPopupShown = once(table.menupopup, "popupshown"); 304 click(node, 2); 305 await onPopupShown; 306 307 is( 308 table.menupopup.querySelectorAll("menuitem[disabled]").length, 309 1, 310 "Only 1 menuitem is disabled" 311 ); 312 313 await hideCol("col3"); 314 315 // opening again to see if 2 items are disabled now 316 // event listener for popupshown 317 info("right clicking on the first column header"); 318 node = table.tbody.firstChild.firstChild; 319 onPopupShown = once(table.menupopup, "popupshown"); 320 click(node, 2); 321 await onPopupShown; 322 323 is( 324 table.menupopup.querySelectorAll("menuitem[disabled]").length, 325 2, 326 "2 menuitems are disabled now as only 2 columns remain visible" 327 ); 328 is( 329 table.menupopup.querySelectorAll("menuitem[disabled]")[0], 330 table.menupopup.querySelector("[data-id='col1']"), 331 "First is the unique column" 332 ); 333 is( 334 table.menupopup.querySelectorAll("menuitem[disabled]")[1], 335 table.menupopup.querySelector("[data-id='col4']"), 336 "Second is the last column" 337 ); 338 339 // showing back 2nd column 340 // popup should be open now 341 // clicking on second column label 342 await showCol("col2"); 343 344 // showing back 3rd column 345 // event listener for popupshown 346 info("right clicking on the first column header"); 347 node = table.tbody.firstChild.firstChild; 348 onPopupShown = once(table.menupopup, "popupshown"); 349 click(node, 2); 350 await onPopupShown; 351 352 // popup should be open now 353 // clicking on second column label 354 await showCol("col3"); 355 356 // reset table state 357 table.clearSelection(); 358 table.sortBy("col1"); 359 };