test_suggestedIndexRelativeToGroup.js (16849B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 // Tests results with `suggestedIndex` and `isSuggestedIndexRelativeToGroup`. 5 6 "use strict"; 7 8 const lazy = {}; 9 10 ChromeUtils.defineESModuleGetters(lazy, { 11 sinon: "resource://testing-common/Sinon.sys.mjs", 12 }); 13 14 const MAX_RESULTS = 10; 15 16 // Default result groups used in the tests below. 17 const RESULT_GROUPS = { 18 children: [ 19 { 20 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 21 flexChildren: true, 22 children: [ 23 { 24 flex: 1, 25 group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, 26 }, 27 { 28 flex: 1, 29 group: UrlbarUtils.RESULT_GROUP.GENERAL, 30 }, 31 { 32 flex: 1, 33 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 34 }, 35 ], 36 }, 37 ], 38 }; 39 40 let sandbox; 41 add_setup(async () => { 42 sandbox = lazy.sinon.createSandbox(); 43 registerCleanupFunction(() => { 44 sandbox.restore(); 45 }); 46 }); 47 48 add_task(async function test() { 49 // Create the default non-suggestedIndex results we'll use for tests that 50 // don't specify `otherResults`. 51 let basicResults = [ 52 ...makeHistoryResults(), 53 ...makeFormHistoryResults(), 54 ...makeRemoteSuggestionResults(), 55 ]; 56 57 // Test cases follow. Each object in `tests` has the following properties: 58 // 59 // * {string} desc 60 // * {object} suggestedIndexResults 61 // Describes the suggestedIndex results the test provider should return. 62 // Properties: 63 // * {number} suggestedIndex 64 // * {UrlbarUtils.RESULT_GROUP} group 65 // This will force the result to have the given group. 66 // * {array} expected 67 // Describes the expected results the muxer should return, i.e., the search 68 // results. Each object in the array describes a slice of expected results. 69 // The size of the slice is defined by the `count` property. 70 // * {UrlbarUtils.RESULT_GROUP} group 71 // The expected group of the results in the slice. 72 // * {number} count 73 // The number of results in the slice. 74 // * {number} [offset] 75 // Can be used to offset the starting index of the slice in the results. 76 // * {array} [otherResults] 77 // An array of results besides the group-relative suggestedIndex results 78 // that the provider should return. If not specified `basicResults` is used. 79 // * {array} [resultGroups] 80 // The result groups to use. If not specified `RESULT_GROUPS` is used. 81 // * {number} [maxRichResults] 82 // The `maxRichResults` pref will be set to this value. If not specified 83 // `MAX_RESULTS` is used. 84 let tests = [ 85 { 86 desc: "First result in GENERAL", 87 suggestedIndexResults: [ 88 { 89 suggestedIndex: 0, 90 group: UrlbarUtils.RESULT_GROUP.GENERAL, 91 }, 92 ], 93 expected: [ 94 { 95 group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, 96 count: 4, 97 }, 98 { 99 group: UrlbarUtils.RESULT_GROUP.GENERAL, 100 suggestedIndex: 0, 101 }, 102 { 103 group: UrlbarUtils.RESULT_GROUP.GENERAL, 104 count: 2, 105 }, 106 { 107 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 108 // The muxer will remove the first 4 remote suggestions because they 109 // dupe the earlier form history. 110 offset: 4, 111 count: 3, 112 }, 113 ], 114 }, 115 116 { 117 desc: "Last result in GENERAL", 118 suggestedIndexResults: [ 119 { 120 suggestedIndex: -1, 121 group: UrlbarUtils.RESULT_GROUP.GENERAL, 122 }, 123 ], 124 expected: [ 125 { 126 group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, 127 count: 4, 128 }, 129 { 130 group: UrlbarUtils.RESULT_GROUP.GENERAL, 131 count: 2, 132 }, 133 { 134 group: UrlbarUtils.RESULT_GROUP.GENERAL, 135 suggestedIndex: -1, 136 }, 137 { 138 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 139 // The muxer will remove the first 4 remote suggestions because they 140 // dupe the earlier form history. 141 offset: 4, 142 count: 3, 143 }, 144 ], 145 }, 146 147 { 148 desc: "First result in GENERAL_PARENT", 149 suggestedIndexResults: [ 150 { 151 suggestedIndex: 0, 152 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 153 }, 154 ], 155 expected: [ 156 { 157 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 158 suggestedIndex: 0, 159 }, 160 { 161 group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, 162 count: 3, 163 }, 164 { 165 group: UrlbarUtils.RESULT_GROUP.GENERAL, 166 count: 3, 167 }, 168 { 169 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 170 // The muxer will remove the first 3 remote suggestions because they 171 // dupe the earlier form history. 172 offset: 3, 173 count: 3, 174 }, 175 ], 176 }, 177 178 { 179 desc: "Last result in GENERAL_PARENT", 180 suggestedIndexResults: [ 181 { 182 suggestedIndex: -1, 183 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 184 }, 185 ], 186 expected: [ 187 { 188 group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, 189 count: 3, 190 }, 191 { 192 group: UrlbarUtils.RESULT_GROUP.GENERAL, 193 count: 3, 194 }, 195 { 196 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 197 // The muxer will remove the first 3 remote suggestions because they 198 // dupe the earlier form history. 199 offset: 3, 200 count: 3, 201 }, 202 { 203 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 204 suggestedIndex: -1, 205 }, 206 ], 207 }, 208 209 { 210 desc: "First and last results in GENERAL", 211 suggestedIndexResults: [ 212 { 213 suggestedIndex: 0, 214 group: UrlbarUtils.RESULT_GROUP.GENERAL, 215 }, 216 { 217 suggestedIndex: -1, 218 group: UrlbarUtils.RESULT_GROUP.GENERAL, 219 }, 220 ], 221 expected: [ 222 { 223 group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, 224 count: 4, 225 }, 226 { 227 group: UrlbarUtils.RESULT_GROUP.GENERAL, 228 suggestedIndex: 0, 229 }, 230 { 231 group: UrlbarUtils.RESULT_GROUP.GENERAL, 232 count: 1, 233 }, 234 { 235 group: UrlbarUtils.RESULT_GROUP.GENERAL, 236 suggestedIndex: -1, 237 }, 238 { 239 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 240 // The muxer will remove the first 4 remote suggestions because they 241 // dupe the earlier form history. 242 offset: 4, 243 count: 3, 244 }, 245 ], 246 }, 247 248 { 249 desc: "First and last results in GENERAL_PARENT", 250 suggestedIndexResults: [ 251 { 252 suggestedIndex: 0, 253 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 254 }, 255 { 256 suggestedIndex: -1, 257 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 258 }, 259 ], 260 expected: [ 261 { 262 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 263 suggestedIndex: 0, 264 }, 265 { 266 group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, 267 count: 3, 268 }, 269 { 270 group: UrlbarUtils.RESULT_GROUP.GENERAL, 271 count: 3, 272 }, 273 { 274 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 275 // The muxer will remove the first 3 remote suggestions because they 276 // dupe the earlier form history. 277 offset: 3, 278 count: 2, 279 }, 280 { 281 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 282 suggestedIndex: -1, 283 }, 284 ], 285 }, 286 287 { 288 desc: "First result in GENERAL_PARENT, first result in GENERAL", 289 suggestedIndexResults: [ 290 { 291 suggestedIndex: 0, 292 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 293 }, 294 { 295 suggestedIndex: 0, 296 group: UrlbarUtils.RESULT_GROUP.GENERAL, 297 }, 298 ], 299 expected: [ 300 { 301 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 302 suggestedIndex: 0, 303 }, 304 { 305 group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, 306 count: 3, 307 }, 308 { 309 group: UrlbarUtils.RESULT_GROUP.GENERAL, 310 suggestedIndex: 0, 311 }, 312 { 313 group: UrlbarUtils.RESULT_GROUP.GENERAL, 314 count: 2, 315 }, 316 { 317 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 318 // The muxer will remove the first 3 remote suggestions because they 319 // dupe the earlier form history. 320 offset: 3, 321 count: 3, 322 }, 323 ], 324 }, 325 326 { 327 desc: "Results in sibling group, no other results in same group", 328 otherResults: makeFormHistoryResults(), 329 suggestedIndexResults: [ 330 { 331 suggestedIndex: -1, 332 group: UrlbarUtils.RESULT_GROUP.GENERAL, 333 }, 334 ], 335 expected: [ 336 { 337 group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, 338 count: 9, 339 }, 340 { 341 group: UrlbarUtils.RESULT_GROUP.GENERAL, 342 suggestedIndex: -1, 343 }, 344 ], 345 }, 346 347 { 348 desc: "Results in sibling group, no other results in same group, has child group", 349 resultGroups: { 350 flexChildren: true, 351 children: [ 352 { 353 flex: 2, 354 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 355 }, 356 { 357 flex: 1, 358 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 359 children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }], 360 }, 361 ], 362 }, 363 otherResults: makeRemoteSuggestionResults(), 364 suggestedIndexResults: [ 365 { 366 suggestedIndex: -1, 367 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 368 }, 369 ], 370 expected: [ 371 { 372 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 373 count: 9, 374 }, 375 { 376 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 377 suggestedIndex: -1, 378 }, 379 ], 380 }, 381 382 { 383 desc: "Complex group nesting with global suggestedIndex with resultSpan", 384 resultGroups: { 385 children: [ 386 { 387 maxResultCount: 1, 388 children: [{ group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST }], 389 }, 390 { 391 flexChildren: true, 392 children: [ 393 { 394 flex: 2, 395 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 396 }, 397 { 398 flex: 1, 399 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 400 children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }], 401 }, 402 ], 403 }, 404 ], 405 }, 406 otherResults: [ 407 // heuristic 408 new UrlbarResult({ 409 type: UrlbarUtils.RESULT_TYPE.SEARCH, 410 source: UrlbarUtils.RESULT_SOURCE.SEARCH, 411 heuristic: true, 412 group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST, 413 payload: { 414 engine: "test", 415 suggestion: "foo", 416 lowerCaseSuggestion: "foo", 417 }, 418 }), 419 // global suggestedIndex with resultSpan = 2 420 new UrlbarResult({ 421 type: UrlbarUtils.RESULT_TYPE.SEARCH, 422 source: UrlbarUtils.RESULT_SOURCE.SEARCH, 423 suggestedIndex: 1, 424 resultSpan: 2, 425 payload: { 426 engine: "test", 427 }, 428 }), 429 // remote suggestions 430 ...makeRemoteSuggestionResults(), 431 ], 432 suggestedIndexResults: [ 433 { 434 suggestedIndex: -1, 435 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 436 }, 437 ], 438 expected: [ 439 { 440 group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST, 441 count: 1, 442 }, 443 { 444 group: UrlbarUtils.RESULT_GROUP.SUGGESTED_INDEX, 445 suggestedIndex: 1, 446 resultSpan: 2, 447 count: 1, 448 }, 449 { 450 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 451 count: 6, 452 }, 453 { 454 group: UrlbarUtils.RESULT_GROUP.GENERAL_PARENT, 455 suggestedIndex: -1, 456 }, 457 ], 458 }, 459 460 { 461 desc: "Last result in REMOTE_SUGGESTION, maxRichResults too small to add any REMOTE_SUGGESTION", 462 maxRichResults: 2, 463 suggestedIndexResults: [ 464 { 465 suggestedIndex: -1, 466 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 467 }, 468 ], 469 expected: [ 470 { 471 group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, 472 count: 1, 473 }, 474 { 475 group: UrlbarUtils.RESULT_GROUP.GENERAL, 476 count: 1, 477 }, 478 // The suggestedIndex result should not be added. 479 ], 480 }, 481 482 { 483 desc: "Last result in REMOTE_SUGGESTION, maxRichResults just big enough to show one REMOTE_SUGGESTION", 484 maxRichResults: 3, 485 suggestedIndexResults: [ 486 { 487 suggestedIndex: -1, 488 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 489 }, 490 ], 491 expected: [ 492 { 493 group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, 494 count: 1, 495 }, 496 { 497 group: UrlbarUtils.RESULT_GROUP.GENERAL, 498 count: 1, 499 }, 500 { 501 group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, 502 suggestedIndex: -1, 503 }, 504 ], 505 }, 506 ]; 507 508 let controller = UrlbarTestUtils.newMockController(); 509 510 for (let { 511 desc, 512 suggestedIndexResults, 513 expected, 514 resultGroups, 515 otherResults, 516 maxRichResults = MAX_RESULTS, 517 } of tests) { 518 info(`Running test: ${desc}`); 519 520 setResultGroups(resultGroups || RESULT_GROUPS); 521 522 UrlbarPrefs.set("maxRichResults", maxRichResults); 523 524 // Make the array of all results and do a search. 525 let results = (otherResults || basicResults).concat( 526 makeSuggestedIndexResults(suggestedIndexResults) 527 ); 528 let provider = registerBasicTestProvider(results); 529 let context = createContext(undefined, { providers: [provider.name] }); 530 await UrlbarProvidersManager.startQuery(context, controller); 531 532 // Make the list of expected results. 533 let expectedResults = []; 534 for (let { group, offset, count, suggestedIndex } of expected) { 535 // Find the index in `results` of the expected result. 536 let index = results.findIndex( 537 r => 538 UrlbarUtils.getResultGroup(r) == group && 539 r.suggestedIndex === suggestedIndex 540 ); 541 Assert.notEqual( 542 index, 543 -1, 544 "Sanity check: Expected result is in `results`" 545 ); 546 if (offset) { 547 index += offset; 548 } 549 550 // Extract the expected number of results from `results` and append them 551 // to the expected results array. 552 count = count || 1; 553 expectedResults.push(...results.slice(index, index + count)); 554 } 555 556 Assert.deepEqual(context.results, expectedResults); 557 558 UrlbarProvidersManager.unregisterProvider(provider); 559 } 560 }); 561 562 function makeHistoryResults(count = MAX_RESULTS) { 563 let results = []; 564 for (let i = 0; i < count; i++) { 565 results.push( 566 new UrlbarResult({ 567 type: UrlbarUtils.RESULT_TYPE.URL, 568 source: UrlbarUtils.RESULT_SOURCE.HISTORY, 569 payload: { url: "http://example.com/" + i }, 570 }) 571 ); 572 } 573 return results; 574 } 575 576 function makeRemoteSuggestionResults(count = MAX_RESULTS) { 577 let results = []; 578 for (let i = 0; i < count; i++) { 579 results.push( 580 new UrlbarResult({ 581 type: UrlbarUtils.RESULT_TYPE.SEARCH, 582 source: UrlbarUtils.RESULT_SOURCE.SEARCH, 583 payload: { 584 engine: "test", 585 query: "test", 586 suggestion: "test " + i, 587 lowerCaseSuggestion: "test " + i, 588 }, 589 }) 590 ); 591 } 592 return results; 593 } 594 595 function makeFormHistoryResults(count = MAX_RESULTS) { 596 let results = []; 597 for (let i = 0; i < count; i++) { 598 results.push( 599 new UrlbarResult({ 600 type: UrlbarUtils.RESULT_TYPE.SEARCH, 601 source: UrlbarUtils.RESULT_SOURCE.HISTORY, 602 payload: { 603 engine: "test", 604 suggestion: "test " + i, 605 lowerCaseSuggestion: "test " + i, 606 }, 607 }) 608 ); 609 } 610 return results; 611 } 612 613 function makeSuggestedIndexResults(objects) { 614 return objects.map(({ suggestedIndex, group }) => 615 Object.assign( 616 new UrlbarResult({ 617 type: UrlbarUtils.RESULT_TYPE.URL, 618 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, 619 group, 620 suggestedIndex, 621 isSuggestedIndexRelativeToGroup: true, 622 payload: { 623 url: "http://example.com/si " + suggestedIndex, 624 }, 625 }) 626 ) 627 ); 628 } 629 630 function setResultGroups(resultGroups) { 631 sandbox.restore(); 632 if (resultGroups) { 633 sandbox.stub(UrlbarPrefs, "getResultGroups").returns(resultGroups); 634 } 635 }