browser_tableWidget_basic.js (11450B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 // We test sorting of strings, which Assert.greater/less etc. don't do. 5 /* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ 6 7 // Tests that the table widget api works fine 8 9 "use strict"; 10 11 const TEST_URI = CHROME_URL_ROOT + "doc_tableWidget_basic.html"; 12 13 const { 14 TableWidget, 15 } = require("resource://devtools/client/shared/widgets/TableWidget.js"); 16 17 add_task(async function () { 18 await addTab("about:blank"); 19 const { host, doc } = await createHost("bottom", TEST_URI); 20 21 const table = new TableWidget(doc.querySelector("box"), { 22 initialColumns: { 23 col1: "Column 1", 24 col2: "Column 2", 25 col3: "Column 3", 26 col4: "Column 4", 27 }, 28 uniqueId: "col1", 29 emptyText: "dummy-text", 30 highlightUpdated: true, 31 removableColumns: true, 32 firstColumn: "col4", 33 l10n: { 34 setAttributes() {}, 35 }, 36 }); 37 38 startTests(doc, table); 39 endTests(doc, host, table); 40 }); 41 42 function startTests(doc, table) { 43 populateTable(doc, table); 44 45 testTreeItemInsertedCorrectly(doc, table); 46 testAPI(doc, table); 47 } 48 49 function endTests(doc, host, table) { 50 table.destroy(); 51 host.destroy(); 52 gBrowser.removeCurrentTab(); 53 table = null; 54 finish(); 55 } 56 57 function populateTable(doc, table) { 58 table.push({ 59 col1: "id1", 60 col2: "value10", 61 col3: "value20", 62 col4: "value30", 63 }); 64 table.push({ 65 col1: "id2", 66 col2: "value14", 67 col3: "value29", 68 col4: "value32", 69 }); 70 table.push({ 71 col1: "id3", 72 col2: "value17", 73 col3: "value21", 74 col4: "value31", 75 extraData: "foobar", 76 extraData2: 42, 77 }); 78 table.push({ 79 col1: "id4", 80 col2: "value12", 81 col3: "value26", 82 col4: "value33", 83 }); 84 table.push({ 85 col1: "id5", 86 col2: "value19", 87 col3: "value26", 88 col4: "value37", 89 }); 90 table.push({ 91 col1: "id6", 92 col2: "value15", 93 col3: "value25", 94 col4: "value37", 95 }); 96 table.push({ 97 col1: "id7", 98 col2: "value18", 99 col3: "value21", 100 col4: "value36", 101 somethingExtra: "Hello World!", 102 }); 103 table.push({ 104 col1: "id8", 105 col2: "value11", 106 col3: "value27", 107 col4: "value34", 108 }); 109 110 const span = doc.createElement("span"); 111 span.textContent = "domnode"; 112 113 table.push({ 114 col1: "id9", 115 col2: "value11", 116 col3: "value23", 117 col4: span, 118 }); 119 } 120 121 /** 122 * Test if the nodes are inserted correctly in the table. 123 */ 124 function testTreeItemInsertedCorrectly(doc, table) { 125 // double because of splitters 126 is(table.tbody.children.length, 4 * 2, "4 columns exist"); 127 128 // Test firstColumn option and check if the nodes are inserted correctly 129 is( 130 table.tbody.children[0].children.length, 131 9 + 1, 132 "Correct rows in column 4" 133 ); 134 is( 135 table.tbody.children[0].firstChild.value, 136 "Column 4", 137 "Correct column header value" 138 ); 139 140 for (let i = 1; i < 4; i++) { 141 is( 142 table.tbody.children[i * 2].children.length, 143 9 + 1, 144 `Correct rows in column ${i}` 145 ); 146 is( 147 table.tbody.children[i * 2].firstChild.value, 148 `Column ${i}`, 149 "Correct column header value" 150 ); 151 } 152 for (let i = 1; i < 10; i++) { 153 is( 154 table.tbody.children[2].children[i].value, 155 `id${i}`, 156 `Correct value in row ${i}` 157 ); 158 } 159 160 // Remove firstColumn option and reset the table 161 info("resetting table"); 162 table.clear(); 163 table.firstColumn = ""; 164 table.setColumns({ 165 col1: "Column 1", 166 col2: "Column 2", 167 col3: "Column 3", 168 col4: "Column 4", 169 }); 170 populateTable(doc, table); 171 172 // Check if the nodes are inserted correctly without firstColumn option 173 for (let i = 0; i < 4; i++) { 174 is( 175 table.tbody.children[i * 2].children.length, 176 9 + 1, 177 `Correct rows in column ${i}` 178 ); 179 is( 180 table.tbody.children[i * 2].firstChild.value, 181 `Column ${i + 1}`, 182 "Correct column header value" 183 ); 184 } 185 186 for (let i = 1; i < 10; i++) { 187 is( 188 table.tbody.firstChild.children[i].value, 189 `id${i}`, 190 `Correct value in row ${i}` 191 ); 192 } 193 } 194 195 /** 196 * Tests if the API exposed by TableWidget works properly 197 */ 198 function testAPI(doc, table) { 199 info("Testing TableWidget API"); 200 // Check if selectRow and selectedRow setter works as expected 201 // Nothing should be selected beforehand 202 ok(!doc.querySelector(".theme-selected"), "Nothing is selected"); 203 table.selectRow("id4"); 204 const node = doc.querySelector(".theme-selected"); 205 ok(!!node, "Somthing got selected"); 206 is(node.getAttribute("data-id"), "id4", "Correct node selected"); 207 208 table.selectRow("id7"); 209 const node2 = doc.querySelector(".theme-selected"); 210 ok(!!node2, "Somthing is still selected"); 211 isnot(node, node2, "Newly selected node is different from previous"); 212 is(node2.getAttribute("data-id"), "id7", "Correct node selected"); 213 214 // test if selectedIRow getter works 215 is(table.selectedRow.col1, "id7", "Correct result of selectedRow getter"); 216 217 // test if isSelected works 218 ok(table.isSelected("id7"), "isSelected with column id works"); 219 ok( 220 table.isSelected({ 221 col1: "id7", 222 col2: "value18", 223 col3: "value21", 224 col4: "value36", 225 somethingExtra: "Hello World!", 226 }), 227 "isSelected with json works" 228 ); 229 230 table.selectedRow = "id4"; 231 const node3 = doc.querySelector(".theme-selected"); 232 ok(!!node3, "Somthing is still selected"); 233 isnot(node2, node3, "Newly selected node is different from previous"); 234 is(node3, node, "First and third selected nodes should be same"); 235 is(node3.getAttribute("data-id"), "id4", "Correct node selected"); 236 237 // test if selectedRow getter works 238 is(table.selectedRow.col1, "id4", "Correct result of selectedRow getter"); 239 240 // test if clear selection works 241 table.clearSelection(); 242 ok( 243 !doc.querySelector(".theme-selected"), 244 "Nothing selected after clear selection call" 245 ); 246 247 // test if selectNextRow and selectPreviousRow work 248 table.selectedRow = "id7"; 249 ok(table.isSelected("id7"), "Correct row selected"); 250 table.selectNextRow(); 251 ok(table.isSelected("id8"), "Correct row selected after selectNextRow call"); 252 253 table.selectNextRow(); 254 ok(table.isSelected("id9"), "Correct row selected after selectNextRow call"); 255 256 table.selectNextRow(); 257 ok( 258 table.isSelected("id1"), 259 "Properly cycled to first row after selectNextRow call on last row" 260 ); 261 262 table.selectNextRow(); 263 ok(table.isSelected("id2"), "Correct row selected after selectNextRow call"); 264 265 table.selectPreviousRow(); 266 ok( 267 table.isSelected("id1"), 268 "Correct row selected after selectPreviousRow call" 269 ); 270 271 table.selectPreviousRow(); 272 ok( 273 table.isSelected("id9"), 274 "Properly cycled to last row after selectPreviousRow call on first row" 275 ); 276 277 // test if remove works 278 ok(doc.querySelector("[data-id='id4']"), "id4 row exists before removal"); 279 table.remove("id4"); 280 ok( 281 !doc.querySelector("[data-id='id4']"), 282 "id4 row does not exist after removal through id" 283 ); 284 285 ok(doc.querySelector("[data-id='id6']"), "id6 row exists before removal"); 286 table.remove({ 287 col1: "id6", 288 col2: "value15", 289 col3: "value25", 290 col4: "value37", 291 }); 292 ok( 293 !doc.querySelector("[data-id='id6']"), 294 "id6 row does not exist after removal through json" 295 ); 296 297 table.push({ 298 col1: "id4", 299 col2: "value12", 300 col3: "value26", 301 col4: "value33", 302 }); 303 table.push({ 304 col1: "id6", 305 col2: "value15", 306 col3: "value25", 307 col4: "value37", 308 }); 309 310 // test if selectedIndex getter setter works 311 table.selectedIndex = 2; 312 ok(table.isSelected("id3"), "Correct row selected by selectedIndex setter"); 313 314 table.selectedIndex = 4; 315 ok(table.isSelected("id5"), "Correct row selected by selectedIndex setter"); 316 317 table.selectRow("id8"); 318 is(table.selectedIndex, 7, "Correct value of selectedIndex getter"); 319 320 // testing if clear works 321 table.clear(); 322 // double because splitters 323 is(table.tbody.children.length, 4 * 2, "4 columns exist even after clear"); 324 for (let i = 0; i < 4; i++) { 325 is( 326 table.tbody.children[i * 2].children.length, 327 1, 328 `Only header in the column ${i} after clear call` 329 ); 330 is( 331 table.tbody.children[i * 2].firstChild.value, 332 `Column ${i + 1}`, 333 "Correct column header value" 334 ); 335 } 336 337 // testing if setColumns work 338 table.setColumns({ 339 col1: "Foobar", 340 col2: "Testing", 341 }); 342 343 // double because splitters 344 is( 345 table.tbody.children.length, 346 2 * 2, 347 "2 columns exist after setColumn call" 348 ); 349 is( 350 table.tbody.children[0].firstChild.getAttribute("value"), 351 "Foobar", 352 "Correct column header value for first column" 353 ); 354 is( 355 table.tbody.children[2].firstChild.getAttribute("value"), 356 "Testing", 357 "Correct column header value for second column" 358 ); 359 360 table.setColumns({ 361 col1: "Column 1", 362 col2: "Column 2", 363 col3: "Column 3", 364 col4: "Column 4", 365 }); 366 // double because splitters 367 is( 368 table.tbody.children.length, 369 4 * 2, 370 "4 columns exist after second setColumn call" 371 ); 372 373 populateTable(doc, table); 374 375 // testing if update works 376 is( 377 doc.querySelectorAll("[data-id='id4']")[1].value, 378 "value12", 379 "Correct value before update" 380 ); 381 table.update({ 382 col1: "id4", 383 col2: "UPDATED", 384 col3: "value26", 385 col4: "value33", 386 }); 387 is( 388 doc.querySelectorAll("[data-id='id4']")[1].value, 389 "UPDATED", 390 "Correct value after update" 391 ); 392 393 // testing if sorting works by calling it once on an already sorted column 394 // should sort descending 395 table.sortBy("col1"); 396 for (let i = 1; i < 10; i++) { 397 is( 398 table.tbody.firstChild.children[i].value, 399 `id${10 - i}`, 400 `Correct value in row ${i} after descending sort by on col1` 401 ); 402 } 403 // Calling it on an unsorted column should sort by it in ascending manner 404 table.sortBy("col2"); 405 let cell = table.tbody.children[2].firstChild.children[2]; 406 checkAscendingOrder(cell); 407 408 // Calling it again should sort by it in descending manner 409 table.sortBy("col2"); 410 cell = table.tbody.children[2].lastChild.previousSibling; 411 checkDescendingOrder(cell); 412 413 // Calling it again should sort by it in ascending manner 414 table.sortBy("col2"); 415 cell = table.tbody.children[2].firstChild.children[2]; 416 checkAscendingOrder(cell); 417 418 table.clear(); 419 populateTable(doc, table); 420 421 // testing if sorting works should sort by ascending manner 422 table.sortBy("col4"); 423 cell = table.tbody.children[6].children[1]; 424 is(cell.textContent, "domnode", "DOMNode sorted correctly"); 425 checkAscendingOrder(cell.nextSibling); 426 427 // Calling it again should sort it in descending order 428 table.sortBy("col4"); 429 cell = table.tbody.children[6].children[9]; 430 is(cell.textContent, "domnode", "DOMNode sorted correctly"); 431 checkDescendingOrder(cell.previousSibling); 432 } 433 434 function checkAscendingOrder(cell) { 435 while (cell) { 436 const currentCell = cell.value || cell.textContent; 437 const prevCell = 438 cell.previousSibling.value || cell.previousSibling.textContent; 439 ok(currentCell >= prevCell, "Sorting is in ascending order"); 440 cell = cell.nextSibling; 441 } 442 } 443 444 function checkDescendingOrder(cell) { 445 while (cell != cell.parentNode.firstChild) { 446 const currentCell = cell.value || cell.textContent; 447 const nextCell = cell.nextSibling.value || cell.nextSibling.textContent; 448 ok(currentCell >= nextCell, "Sorting is in descending order"); 449 cell = cell.previousSibling; 450 } 451 }