test_providerOmnibox.js (25504B)
1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- 2 * vim:set ts=2 sw=2 sts=2 et: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 const { ExtensionSearchHandler } = ChromeUtils.importESModule( 8 "resource://gre/modules/ExtensionSearchHandler.sys.mjs" 9 ); 10 11 let controller = Cc["@mozilla.org/autocomplete/controller;1"].getService( 12 Ci.nsIAutoCompleteController 13 ); 14 15 const SUGGEST_PREF = "browser.urlbar.suggest.searches"; 16 const SUGGEST_ENABLED_PREF = "browser.search.suggest.enabled"; 17 18 async function cleanup() { 19 await PlacesUtils.bookmarks.eraseEverything(); 20 await PlacesUtils.history.clear(); 21 } 22 23 add_setup(function () { 24 Services.prefs.setBoolPref(SUGGEST_PREF, false); 25 Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, false); 26 27 registerCleanupFunction(async () => { 28 Services.prefs.clearUserPref(SUGGEST_PREF); 29 Services.prefs.clearUserPref(SUGGEST_ENABLED_PREF); 30 }); 31 }); 32 33 add_task(async function test_correct_errors_are_thrown() { 34 let keyword = "foo"; 35 let anotherKeyword = "bar"; 36 let unregisteredKeyword = "baz"; 37 38 // Register a keyword. 39 ExtensionSearchHandler.registerKeyword(keyword, { emit: () => {} }); 40 41 // Try registering the keyword again. 42 Assert.throws( 43 () => ExtensionSearchHandler.registerKeyword(keyword, { emit: () => {} }), 44 /The keyword provided is already registered/ 45 ); 46 47 // Register a different keyword. 48 ExtensionSearchHandler.registerKeyword(anotherKeyword, { emit: () => {} }); 49 50 // Try calling handleSearch for an unregistered keyword. 51 let searchData = { 52 keyword: unregisteredKeyword, 53 text: `${unregisteredKeyword} `, 54 }; 55 Assert.throws( 56 () => ExtensionSearchHandler.handleSearch(searchData, () => {}), 57 /The keyword provided is not registered/ 58 ); 59 60 // Try calling handleSearch without a callback. 61 Assert.throws( 62 () => ExtensionSearchHandler.handleSearch(searchData), 63 /The keyword provided is not registered/ 64 ); 65 66 // Try getting the description for a keyword which isn't registered. 67 Assert.throws( 68 () => ExtensionSearchHandler.getDescription(unregisteredKeyword), 69 /The keyword provided is not registered/ 70 ); 71 72 // Try setting the default suggestion for a keyword which isn't registered. 73 Assert.throws( 74 () => 75 ExtensionSearchHandler.setDefaultSuggestion( 76 unregisteredKeyword, 77 "suggestion" 78 ), 79 /The keyword provided is not registered/ 80 ); 81 82 // Try calling handleInputCancelled when there is no active input session. 83 Assert.throws( 84 () => ExtensionSearchHandler.handleInputCancelled(), 85 /There is no active input session/ 86 ); 87 88 // Try calling handleInputEntered when there is no active input session. 89 Assert.throws( 90 () => 91 ExtensionSearchHandler.handleInputEntered( 92 anotherKeyword, 93 `${anotherKeyword} test`, 94 "tab" 95 ), 96 /There is no active input session/ 97 ); 98 99 // Start a session by calling handleSearch with the registered keyword. 100 searchData = { 101 keyword, 102 text: `${keyword} test`, 103 }; 104 ExtensionSearchHandler.handleSearch(searchData, () => {}); 105 106 // Try providing suggestions for an unregistered keyword. 107 Assert.throws( 108 () => ExtensionSearchHandler.addSuggestions(unregisteredKeyword, 0, []), 109 /The keyword provided is not registered/ 110 ); 111 112 // Try providing suggestions for an inactive keyword. 113 Assert.throws( 114 () => ExtensionSearchHandler.addSuggestions(anotherKeyword, 0, []), 115 /The keyword provided is not apart of an active input session/ 116 ); 117 118 // Try calling handleSearch for an inactive keyword. 119 searchData = { 120 keyword: anotherKeyword, 121 text: `${anotherKeyword} `, 122 }; 123 Assert.throws( 124 () => ExtensionSearchHandler.handleSearch(searchData, () => {}), 125 /A different input session is already ongoing/ 126 ); 127 128 // Try calling addSuggestions with an old callback ID. 129 Assert.throws( 130 () => ExtensionSearchHandler.addSuggestions(keyword, 0, []), 131 /The callback is no longer active for the keyword provided/ 132 ); 133 134 // Add suggestions with a valid callback ID. 135 ExtensionSearchHandler.addSuggestions(keyword, 1, []); 136 137 // Add suggestions again with a valid callback ID. 138 ExtensionSearchHandler.addSuggestions(keyword, 1, []); 139 140 // Try calling addSuggestions with a future callback ID. 141 Assert.throws( 142 () => ExtensionSearchHandler.addSuggestions(keyword, 2, []), 143 /The callback is no longer active for the keyword provided/ 144 ); 145 146 // End the input session by calling handleInputCancelled. 147 ExtensionSearchHandler.handleInputCancelled(); 148 149 // Try calling handleInputCancelled after the session has ended. 150 Assert.throws( 151 () => ExtensionSearchHandler.handleInputCancelled(), 152 /There is no active input sessio/ 153 ); 154 155 // Try calling handleSearch that doesn't have a space after the keyword. 156 searchData = { 157 keyword: anotherKeyword, 158 text: `${anotherKeyword}`, 159 }; 160 Assert.throws( 161 () => ExtensionSearchHandler.handleSearch(searchData, () => {}), 162 /The text provided must start with/ 163 ); 164 165 // Try calling handleSearch with text starting with the wrong keyword. 166 searchData = { 167 keyword: anotherKeyword, 168 text: `${keyword} test`, 169 }; 170 Assert.throws( 171 () => ExtensionSearchHandler.handleSearch(searchData, () => {}), 172 /The text provided must start with/ 173 ); 174 175 // Start a new session by calling handleSearch with a different keyword 176 searchData = { 177 keyword: anotherKeyword, 178 text: `${anotherKeyword} test`, 179 }; 180 ExtensionSearchHandler.handleSearch(searchData, () => {}); 181 182 // Try adding suggestions again with the same callback ID now that the input session has ended. 183 Assert.throws( 184 () => ExtensionSearchHandler.addSuggestions(keyword, 1, []), 185 /The keyword provided is not apart of an active input session/ 186 ); 187 188 // Add suggestions with a valid callback ID. 189 ExtensionSearchHandler.addSuggestions(anotherKeyword, 2, []); 190 191 // Try adding suggestions with a valid callback ID but a different keyword. 192 Assert.throws( 193 () => ExtensionSearchHandler.addSuggestions(keyword, 2, []), 194 /The keyword provided is not apart of an active input session/ 195 ); 196 197 // Try adding suggestions with a valid callback ID but an unregistered keyword. 198 Assert.throws( 199 () => ExtensionSearchHandler.addSuggestions(unregisteredKeyword, 2, []), 200 /The keyword provided is not registered/ 201 ); 202 203 // Set the default suggestion. 204 ExtensionSearchHandler.setDefaultSuggestion(anotherKeyword, { 205 description: "test result", 206 }); 207 208 // Try ending the session using handleInputEntered with a different keyword. 209 Assert.throws( 210 () => 211 ExtensionSearchHandler.handleInputEntered( 212 keyword, 213 `${keyword} test`, 214 "tab" 215 ), 216 /A different input session is already ongoing/ 217 ); 218 219 // Try calling handleInputEntered with invalid text. 220 Assert.throws( 221 () => 222 ExtensionSearchHandler.handleInputEntered(anotherKeyword, ` test`, "tab"), 223 /The text provided must start with/ 224 ); 225 226 // Try calling handleInputEntered with an invalid disposition. 227 Assert.throws( 228 () => 229 ExtensionSearchHandler.handleInputEntered( 230 anotherKeyword, 231 `${anotherKeyword} test`, 232 "invalid" 233 ), 234 /Invalid "where" argument/ 235 ); 236 237 // End the session by calling handleInputEntered. 238 ExtensionSearchHandler.handleInputEntered( 239 anotherKeyword, 240 `${anotherKeyword} test`, 241 "tab" 242 ); 243 244 // Try calling handleInputEntered after the session has ended. 245 Assert.throws( 246 () => 247 ExtensionSearchHandler.handleInputEntered( 248 anotherKeyword, 249 `${anotherKeyword} test`, 250 "tab" 251 ), 252 /There is no active input session/ 253 ); 254 255 // Unregister the keyword. 256 ExtensionSearchHandler.unregisterKeyword(keyword); 257 258 // Try setting the default suggestion for the unregistered keyword. 259 Assert.throws( 260 () => 261 ExtensionSearchHandler.setDefaultSuggestion(keyword, { 262 description: "test", 263 }), 264 /The keyword provided is not registered/ 265 ); 266 267 // Try handling a search with the unregistered keyword. 268 searchData = { 269 keyword, 270 text: `${keyword} test`, 271 }; 272 Assert.throws( 273 () => ExtensionSearchHandler.handleSearch(searchData, () => {}), 274 /The keyword provided is not registered/ 275 ); 276 277 // Try unregistering the keyword again. 278 Assert.throws( 279 () => ExtensionSearchHandler.unregisterKeyword(keyword), 280 /The keyword provided is not registered/ 281 ); 282 283 // Unregister the other keyword. 284 ExtensionSearchHandler.unregisterKeyword(anotherKeyword); 285 286 // Try unregistering the word which was never registered. 287 Assert.throws( 288 () => ExtensionSearchHandler.unregisterKeyword(unregisteredKeyword), 289 /The keyword provided is not registered/ 290 ); 291 292 // Try setting the default suggestion for a word that was never registered. 293 Assert.throws( 294 () => 295 ExtensionSearchHandler.setDefaultSuggestion(unregisteredKeyword, { 296 description: "test", 297 }), 298 /The keyword provided is not registered/ 299 ); 300 301 await cleanup(); 302 }); 303 304 add_task(async function test_extension_private_browsing() { 305 let events = []; 306 let mockExtension = { 307 emit: message => events.push(message), 308 privateBrowsingAllowed: false, 309 }; 310 311 let keyword = "foo"; 312 313 ExtensionSearchHandler.registerKeyword(keyword, mockExtension); 314 315 let searchData = { 316 keyword, 317 text: `${keyword} test`, 318 inPrivateWindow: true, 319 }; 320 let result = await ExtensionSearchHandler.handleSearch(searchData); 321 Assert.equal(result, false, "unable to handle search for private window"); 322 323 // Try calling handleInputEntered after the session has ended. 324 Assert.throws( 325 () => 326 ExtensionSearchHandler.handleInputEntered( 327 keyword, 328 `${keyword} test`, 329 "tab" 330 ), 331 /There is no active input session/ 332 ); 333 334 ExtensionSearchHandler.unregisterKeyword(keyword); 335 await cleanup(); 336 }); 337 338 add_task(async function test_extension_private_browsing_allowed() { 339 let extensionName = "Foo Bar"; 340 let mockExtension = { 341 name: extensionName, 342 emit: (message, text, id) => { 343 if (message === ExtensionSearchHandler.MSG_INPUT_CHANGED) { 344 ExtensionSearchHandler.addSuggestions(keyword, id, [ 345 { content: "foo", description: "first suggestion" }, 346 { content: "foobar", description: "second suggestion" }, 347 ]); 348 // The API doesn't have a way to notify when addition is complete. 349 do_timeout(1000, () => { 350 controller.stopSearch(); 351 }); 352 } 353 }, 354 privateBrowsingAllowed: true, 355 }; 356 357 let keyword = "foo"; 358 ExtensionSearchHandler.registerKeyword(keyword, mockExtension); 359 360 let query = `${keyword} foo`; 361 let context = createContext(query, { isPrivate: true }); 362 await check_results({ 363 context, 364 matches: [ 365 makeOmniboxResult(context, { 366 heuristic: true, 367 keyword, 368 description: extensionName, 369 content: query, 370 }), 371 makeOmniboxResult(context, { 372 keyword, 373 content: `${keyword} foobar`, 374 description: "second suggestion", 375 }), 376 ], 377 }); 378 379 ExtensionSearchHandler.unregisterKeyword(keyword); 380 await cleanup(); 381 }); 382 383 add_task(async function test_correct_events_are_emitted() { 384 let events = []; 385 function checkEvents(expectedEvents) { 386 Assert.equal( 387 events.length, 388 expectedEvents.length, 389 "The correct number of events fired" 390 ); 391 expectedEvents.forEach((e, i) => 392 Assert.equal(e, events[i], `Expected "${e}" event to fire`) 393 ); 394 events = []; 395 } 396 397 let mockExtension = { emit: message => events.push(message) }; 398 399 let keyword = "foo"; 400 let anotherKeyword = "bar"; 401 402 ExtensionSearchHandler.registerKeyword(keyword, mockExtension); 403 ExtensionSearchHandler.registerKeyword(anotherKeyword, mockExtension); 404 405 let searchData = { 406 keyword, 407 text: `${keyword} `, 408 }; 409 ExtensionSearchHandler.handleSearch(searchData, () => {}); 410 checkEvents([ExtensionSearchHandler.MSG_INPUT_STARTED]); 411 412 searchData.text = `${keyword} f`; 413 ExtensionSearchHandler.handleSearch(searchData, () => {}); 414 checkEvents([ExtensionSearchHandler.MSG_INPUT_CHANGED]); 415 416 ExtensionSearchHandler.handleInputEntered(keyword, searchData.text, "tab"); 417 checkEvents([ExtensionSearchHandler.MSG_INPUT_ENTERED]); 418 419 ExtensionSearchHandler.handleSearch(searchData, () => {}); 420 checkEvents([ 421 ExtensionSearchHandler.MSG_INPUT_STARTED, 422 ExtensionSearchHandler.MSG_INPUT_CHANGED, 423 ]); 424 425 ExtensionSearchHandler.handleInputCancelled(); 426 checkEvents([ExtensionSearchHandler.MSG_INPUT_CANCELLED]); 427 428 ExtensionSearchHandler.handleSearch( 429 { 430 keyword: anotherKeyword, 431 text: `${anotherKeyword} baz`, 432 }, 433 () => {} 434 ); 435 checkEvents([ 436 ExtensionSearchHandler.MSG_INPUT_STARTED, 437 ExtensionSearchHandler.MSG_INPUT_CHANGED, 438 ]); 439 440 ExtensionSearchHandler.handleInputEntered( 441 anotherKeyword, 442 `${anotherKeyword} baz`, 443 "tab" 444 ); 445 checkEvents([ExtensionSearchHandler.MSG_INPUT_ENTERED]); 446 447 ExtensionSearchHandler.unregisterKeyword(keyword); 448 }); 449 450 add_task(async function test_removes_suggestion_if_its_content_is_typed_in() { 451 let keyword = "test"; 452 let extensionName = "Foo Bar"; 453 454 let mockExtension = { 455 name: extensionName, 456 emit(message, text, id) { 457 if (message === ExtensionSearchHandler.MSG_INPUT_CHANGED) { 458 ExtensionSearchHandler.addSuggestions(keyword, id, [ 459 { content: "foo", description: "first suggestion" }, 460 { content: "bar", description: "second suggestion" }, 461 { content: "baz", description: "third suggestion" }, 462 ]); 463 // The API doesn't have a way to notify when addition is complete. 464 do_timeout(1000, () => { 465 controller.stopSearch(); 466 }); 467 } 468 }, 469 }; 470 471 ExtensionSearchHandler.registerKeyword(keyword, mockExtension); 472 473 let query = `${keyword} unmatched`; 474 let context = createContext(query, { isPrivate: false }); 475 await check_results({ 476 context, 477 matches: [ 478 makeOmniboxResult(context, { 479 heuristic: true, 480 keyword, 481 description: extensionName, 482 content: `${keyword} unmatched`, 483 }), 484 makeOmniboxResult(context, { 485 keyword, 486 content: `${keyword} foo`, 487 description: "first suggestion", 488 }), 489 makeOmniboxResult(context, { 490 keyword, 491 content: `${keyword} bar`, 492 description: "second suggestion", 493 }), 494 makeOmniboxResult(context, { 495 keyword, 496 content: `${keyword} baz`, 497 description: "third suggestion", 498 }), 499 ], 500 }); 501 502 query = `${keyword} foo`; 503 context = createContext(query, { isPrivate: false }); 504 await check_results({ 505 context, 506 matches: [ 507 makeOmniboxResult(context, { 508 heuristic: true, 509 keyword, 510 description: extensionName, 511 content: `${keyword} foo`, 512 }), 513 makeOmniboxResult(context, { 514 keyword, 515 content: `${keyword} bar`, 516 description: "second suggestion", 517 }), 518 makeOmniboxResult(context, { 519 keyword, 520 content: `${keyword} baz`, 521 description: "third suggestion", 522 }), 523 ], 524 }); 525 526 query = `${keyword} bar`; 527 context = createContext(query, { isPrivate: false }); 528 await check_results({ 529 context, 530 matches: [ 531 makeOmniboxResult(context, { 532 heuristic: true, 533 keyword, 534 description: extensionName, 535 content: `${keyword} bar`, 536 }), 537 makeOmniboxResult(context, { 538 keyword, 539 content: `${keyword} foo`, 540 description: "first suggestion", 541 }), 542 makeOmniboxResult(context, { 543 keyword, 544 content: `${keyword} baz`, 545 description: "third suggestion", 546 }), 547 ], 548 }); 549 550 query = `${keyword} baz`; 551 context = createContext(query, { isPrivate: false }); 552 await check_results({ 553 context, 554 matches: [ 555 makeOmniboxResult(context, { 556 heuristic: true, 557 keyword, 558 description: extensionName, 559 content: `${keyword} baz`, 560 }), 561 makeOmniboxResult(context, { 562 keyword, 563 content: `${keyword} foo`, 564 description: "first suggestion", 565 }), 566 makeOmniboxResult(context, { 567 keyword, 568 content: `${keyword} bar`, 569 description: "second suggestion", 570 }), 571 ], 572 }); 573 574 ExtensionSearchHandler.unregisterKeyword(keyword); 575 await cleanup(); 576 }); 577 578 add_task(async function test_extension_results_should_come_first() { 579 let keyword = "test"; 580 let extensionName = "Omnibox Example"; 581 582 let uri = Services.io.newURI(`http://a.com/b`); 583 await PlacesTestUtils.addVisits([{ uri, title: `${keyword} -` }]); 584 585 let mockExtension = { 586 name: extensionName, 587 emit(message, text, id) { 588 if (message === ExtensionSearchHandler.MSG_INPUT_CHANGED) { 589 ExtensionSearchHandler.addSuggestions(keyword, id, [ 590 { content: "foo", description: "first suggestion" }, 591 { content: "bar", description: "second suggestion" }, 592 { content: "baz", description: "third suggestion" }, 593 ]); 594 } 595 }, 596 }; 597 598 ExtensionSearchHandler.registerKeyword(keyword, mockExtension); 599 600 // Start an input session before testing MSG_INPUT_CHANGED. 601 ExtensionSearchHandler.handleSearch( 602 { keyword, text: `${keyword} ` }, 603 () => {} 604 ); 605 606 let query = `${keyword} -`; 607 let context = createContext(query, { isPrivate: false }); 608 await check_results({ 609 context, 610 matches: [ 611 makeOmniboxResult(context, { 612 heuristic: true, 613 keyword, 614 description: extensionName, 615 content: `${keyword} -`, 616 }), 617 makeOmniboxResult(context, { 618 keyword, 619 content: `${keyword} foo`, 620 description: "first suggestion", 621 }), 622 makeOmniboxResult(context, { 623 keyword, 624 content: `${keyword} bar`, 625 description: "second suggestion", 626 }), 627 makeOmniboxResult(context, { 628 keyword, 629 content: `${keyword} baz`, 630 description: "third suggestion", 631 }), 632 makeVisitResult(context, { 633 uri: `http://a.com/b`, 634 title: `${keyword} -`, 635 }), 636 ], 637 }); 638 639 ExtensionSearchHandler.unregisterKeyword(keyword); 640 await cleanup(); 641 }); 642 643 add_task(async function test_setting_the_default_suggestion() { 644 let keyword = "test"; 645 let extensionName = "Omnibox Example"; 646 647 let mockExtension = { 648 name: extensionName, 649 emit(message, text, id) { 650 if (message === ExtensionSearchHandler.MSG_INPUT_CHANGED) { 651 ExtensionSearchHandler.addSuggestions(keyword, id, []); 652 // The API doesn't have a way to notify when addition is complete. 653 do_timeout(1000, () => { 654 controller.stopSearch(); 655 }); 656 } 657 }, 658 }; 659 660 ExtensionSearchHandler.registerKeyword(keyword, mockExtension); 661 662 ExtensionSearchHandler.setDefaultSuggestion(keyword, { 663 description: "hello world", 664 }); 665 666 let query = `${keyword} search query`; 667 let context = createContext(query, { isPrivate: false }); 668 await check_results({ 669 context, 670 matches: [ 671 makeOmniboxResult(context, { 672 heuristic: true, 673 keyword, 674 description: "hello world", 675 content: query, 676 }), 677 ], 678 }); 679 680 ExtensionSearchHandler.setDefaultSuggestion(keyword, { 681 description: "foo bar", 682 }); 683 684 context = createContext(query, { isPrivate: false }); 685 await check_results({ 686 context, 687 searchParam: "enable-actions", 688 matches: [ 689 makeOmniboxResult(context, { 690 heuristic: true, 691 keyword, 692 description: "foo bar", 693 content: query, 694 }), 695 ], 696 }); 697 698 ExtensionSearchHandler.unregisterKeyword(keyword); 699 await cleanup(); 700 }); 701 702 add_task(async function test_maximum_number_of_suggestions_is_enforced() { 703 let keyword = "test"; 704 let extensionName = "Omnibox Example"; 705 706 let mockExtension = { 707 name: extensionName, 708 emit(message, text, id) { 709 if (message === ExtensionSearchHandler.MSG_INPUT_CHANGED) { 710 ExtensionSearchHandler.addSuggestions(keyword, id, [ 711 { content: "a", description: "first suggestion" }, 712 { content: "b", description: "second suggestion" }, 713 { content: "c", description: "third suggestion" }, 714 { content: "d", description: "fourth suggestion" }, 715 { content: "e", description: "fifth suggestion" }, 716 { content: "f", description: "sixth suggestion" }, 717 { content: "g", description: "seventh suggestion" }, 718 { content: "h", description: "eigth suggestion" }, 719 { content: "i", description: "ninth suggestion" }, 720 { content: "j", description: "tenth suggestion" }, 721 { content: "k", description: "eleventh suggestion" }, 722 { content: "l", description: "twelfth suggestion" }, 723 ]); 724 // The API doesn't have a way to notify when addition is complete. 725 do_timeout(1000, () => { 726 controller.stopSearch(); 727 }); 728 } 729 }, 730 }; 731 732 ExtensionSearchHandler.registerKeyword(keyword, mockExtension); 733 734 // Start an input session before testing MSG_INPUT_CHANGED. 735 ExtensionSearchHandler.handleSearch( 736 { keyword, text: `${keyword} ` }, 737 () => {} 738 ); 739 740 let query = `${keyword} #`; 741 let context = createContext(query, { isPrivate: false }); 742 await check_results({ 743 context, 744 matches: [ 745 makeOmniboxResult(context, { 746 heuristic: true, 747 keyword, 748 description: extensionName, 749 content: `${keyword} #`, 750 }), 751 makeOmniboxResult(context, { 752 keyword, 753 content: `${keyword} a`, 754 description: "first suggestion", 755 }), 756 makeOmniboxResult(context, { 757 keyword, 758 content: `${keyword} b`, 759 description: "second suggestion", 760 }), 761 makeOmniboxResult(context, { 762 keyword, 763 content: `${keyword} c`, 764 description: "third suggestion", 765 }), 766 makeOmniboxResult(context, { 767 keyword, 768 content: `${keyword} d`, 769 description: "fourth suggestion", 770 }), 771 makeOmniboxResult(context, { 772 keyword, 773 content: `${keyword} e`, 774 description: "fifth suggestion", 775 }), 776 makeOmniboxResult(context, { 777 keyword, 778 content: `${keyword} f`, 779 description: "sixth suggestion", 780 }), 781 makeOmniboxResult(context, { 782 keyword, 783 content: `${keyword} g`, 784 description: "seventh suggestion", 785 }), 786 makeOmniboxResult(context, { 787 keyword, 788 content: `${keyword} h`, 789 description: "eigth suggestion", 790 }), 791 makeOmniboxResult(context, { 792 keyword, 793 content: `${keyword} i`, 794 description: "ninth suggestion", 795 }), 796 ], 797 }); 798 799 ExtensionSearchHandler.unregisterKeyword(keyword); 800 await cleanup(); 801 }); 802 803 add_task(async function conflicting_alias() { 804 Services.prefs.setBoolPref(SUGGEST_PREF, true); 805 Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); 806 807 let engine = await addTestSuggestionsEngine(); 808 let keyword = "test"; 809 engine.alias = keyword; 810 let oldDefaultEngine = await Services.search.getDefault(); 811 Services.search.setDefault(engine, Ci.nsISearchService.CHANGE_REASON_UNKNOWN); 812 813 let extensionName = "Omnibox Example"; 814 815 let mockExtension = { 816 name: extensionName, 817 emit(message, text, id) { 818 if (message === ExtensionSearchHandler.MSG_INPUT_CHANGED) { 819 ExtensionSearchHandler.addSuggestions(keyword, id, [ 820 { content: "foo", description: "first suggestion" }, 821 { content: "bar", description: "second suggestion" }, 822 { content: "baz", description: "third suggestion" }, 823 ]); 824 // The API doesn't have a way to notify when addition is complete. 825 do_timeout(1000, () => { 826 controller.stopSearch(); 827 }); 828 } 829 }, 830 }; 831 832 ExtensionSearchHandler.registerKeyword(keyword, mockExtension); 833 let query = `${keyword} unmatched`; 834 let context = createContext(query, { isPrivate: false }); 835 await check_results({ 836 context, 837 matches: [ 838 makeOmniboxResult(context, { 839 heuristic: true, 840 keyword, 841 description: extensionName, 842 content: `${keyword} unmatched`, 843 }), 844 makeOmniboxResult(context, { 845 keyword, 846 content: `${keyword} foo`, 847 description: "first suggestion", 848 }), 849 makeOmniboxResult(context, { 850 keyword, 851 content: `${keyword} bar`, 852 description: "second suggestion", 853 }), 854 makeOmniboxResult(context, { 855 keyword, 856 content: `${keyword} baz`, 857 description: "third suggestion", 858 }), 859 makeSearchResult(context, { 860 query: "unmatched", 861 engineName: SUGGESTIONS_ENGINE_NAME, 862 alias: keyword, 863 suggestion: "unmatched", 864 }), 865 makeSearchResult(context, { 866 query: "unmatched", 867 engineName: SUGGESTIONS_ENGINE_NAME, 868 alias: keyword, 869 suggestion: "unmatched foo", 870 }), 871 makeSearchResult(context, { 872 query: "unmatched", 873 engineName: SUGGESTIONS_ENGINE_NAME, 874 alias: keyword, 875 suggestion: "unmatched bar", 876 }), 877 ], 878 }); 879 880 Services.search.setDefault( 881 oldDefaultEngine, 882 Ci.nsISearchService.CHANGE_REASON_UNKNOWN 883 ); 884 Services.prefs.setBoolPref(SUGGEST_PREF, false); 885 Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, false); 886 await cleanup(); 887 });