browser_quicksuggest_realtime_flight_status.js (29376B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 const TEST_MERINO_SINGLE = [ 5 { 6 provider: "flightaware", 7 is_sponsored: false, 8 score: 0, 9 title: "Flight Suggestion", 10 custom_details: { 11 flightaware: { 12 values: [ 13 { 14 flight_number: "A1", 15 airline: { 16 name: null, 17 code: null, 18 icon: null, 19 }, 20 origin: { 21 city: "Origin", 22 code: "O", 23 }, 24 destination: { 25 city: "Destination", 26 code: "D", 27 }, 28 departure: { 29 scheduled_time: "2025-09-17T14:05:00Z", 30 }, 31 arrival: { 32 scheduled_time: "2025-09-17T18:30:00Z", 33 }, 34 status: "Scheduled", 35 url: "https://example.com/A1", 36 }, 37 ], 38 }, 39 }, 40 }, 41 ]; 42 43 const TEST_MERINO_MULTI = [ 44 { 45 provider: "flightaware", 46 is_sponsored: false, 47 score: 0, 48 title: "Flight Suggestion", 49 custom_details: { 50 flightaware: { 51 values: [ 52 { 53 flight_number: "A1", 54 airline: { 55 name: "A Air", 56 code: "A", 57 icon: "chrome://browser/skin/urlbar/market-up.svg", 58 }, 59 origin: { 60 city: "Origin 1", 61 code: "O1", 62 }, 63 destination: { 64 city: "Destination 1", 65 code: "D1", 66 }, 67 departure: { 68 scheduled_time: "2025-09-01T14:01:00Z", 69 }, 70 arrival: { 71 scheduled_time: "2025-09-01T18:31:00Z", 72 }, 73 status: "Scheduled", 74 url: "https://example.com/A1", 75 }, 76 { 77 flight_number: "A2", 78 airline: { 79 name: null, 80 code: null, 81 icon: null, 82 }, 83 origin: { 84 city: "Origin 2", 85 code: "O2", 86 }, 87 destination: { 88 city: "Destination 2", 89 code: "D2", 90 }, 91 departure: { 92 scheduled_time: "2025-09-02T14:02:00+02:00", 93 }, 94 arrival: { 95 scheduled_time: "2025-09-02T18:32:00-02:00", 96 }, 97 status: "En Route", 98 progress_percent: 0, 99 time_left_minutes: 1, 100 url: "https://example.com/A2", 101 }, 102 { 103 flight_number: "A3", 104 airline: { 105 name: null, 106 code: null, 107 icon: null, 108 }, 109 origin: { 110 city: "Origin 3", 111 code: "O3", 112 }, 113 destination: { 114 city: "Destination 3", 115 code: "D3", 116 }, 117 departure: { 118 scheduled_time: "2025-09-03T14:03:00+0300", 119 }, 120 arrival: { 121 scheduled_time: "2025-09-03T18:33:00-0300", 122 }, 123 status: "Arrived", 124 time_left_minutes: 0, 125 url: "https://example.com/A3", 126 }, 127 { 128 flight_number: "A4", 129 airline: { 130 name: null, 131 code: null, 132 icon: null, 133 }, 134 origin: { 135 city: "Origin 4", 136 code: "O4", 137 }, 138 destination: { 139 city: "Destination 4", 140 code: "D4", 141 }, 142 departure: { 143 scheduled_time: "2025-09-04T14:04:00+10:30", 144 }, 145 arrival: { 146 scheduled_time: "2025-09-04T18:34:00-10:30", 147 }, 148 status: "Cancelled", 149 url: "https://example.com/A4", 150 }, 151 ], 152 }, 153 }, 154 }, 155 ]; 156 157 add_setup(async function () { 158 await SearchTestUtils.installSearchExtension({}, { setAsDefault: true }); 159 registerCleanupFunction(async () => { 160 await PlacesUtils.history.clear(); 161 }); 162 163 await QuickSuggestTestUtils.ensureQuickSuggestInit({ 164 merinoSuggestions: TEST_MERINO_SINGLE, 165 prefs: [ 166 ["flightStatus.featureGate", true], 167 ["suggest.flightStatus", true], 168 ["suggest.quicksuggest.all", true], 169 ], 170 }); 171 }); 172 173 add_task(async function ui_basic() { 174 MerinoTestUtils.server.response.body.suggestions = TEST_MERINO_MULTI; 175 176 const expectedList = [ 177 { 178 flight_number: "A1, A Air", 179 image: "chrome://browser/skin/urlbar/market-up.svg", 180 departure_time: "2:01 PM", 181 departure_date: "Mon, Sep 1", 182 arrival_time: "6:31 PM", 183 origin_airport: "Origin 1 (O1)", 184 destination_airport: "Destination 1 (D1)", 185 status: "On time", 186 url: "https://example.com/A1", 187 }, 188 { 189 flight_number: "A2", 190 image: "", 191 departure_time: "2:02 PM", 192 departure_date: "Tue, Sep 2", 193 arrival_time: "6:32 PM", 194 origin_airport: "Origin 2 (O2)", 195 destination_airport: "Destination 2 (D2)", 196 status: "In flight", 197 time_left: "1 min left", 198 url: "https://example.com/A2", 199 }, 200 { 201 flight_number: "A3", 202 image: "chrome://browser/skin/urlbar/flight-airline.svg", 203 departure_time: "2:03 PM", 204 departure_date: "Wed, Sep 3", 205 arrival_time: "6:33 PM", 206 origin_airport: "Origin 3 (O3)", 207 destination_airport: "Destination 3 (D3)", 208 status: "Arrived", 209 url: "https://example.com/A3", 210 }, 211 { 212 flight_number: "A4", 213 image: "chrome://browser/skin/urlbar/flight-airline.svg", 214 departure_time: "2:04 PM", 215 departure_date: "Thu, Sep 4", 216 arrival_time: "6:34 PM", 217 origin_airport: "Origin 4 (O4)", 218 destination_airport: "Destination 4 (D4)", 219 status: "Cancelled", 220 url: "https://example.com/A4", 221 }, 222 ]; 223 224 await UrlbarTestUtils.promiseAutocompleteResultPopup({ 225 window, 226 value: "only match the Merino suggestion", 227 }); 228 let { element } = await UrlbarTestUtils.getDetailsOfResultAt(window, 1); 229 230 await assertUI({ row: element.row, expectedList }); 231 232 await UrlbarTestUtils.promisePopupClose(window); 233 gURLBar.handleRevert(); 234 }); 235 236 add_task(async function ui_delayed() { 237 MerinoTestUtils.server.response.body.suggestions = [ 238 { 239 provider: "flightaware", 240 is_sponsored: false, 241 score: 0, 242 title: "Flight Suggestion", 243 custom_details: { 244 flightaware: { 245 values: [ 246 { 247 flight_number: "D1", 248 airline: { 249 name: "Delay Air", 250 code: "D", 251 icon: "chrome://browser/skin/urlbar/market-unchanged.svg", 252 }, 253 origin: { 254 city: "Origin D1", 255 code: "OD1", 256 }, 257 destination: { 258 city: "Destination D1", 259 code: "DD1", 260 }, 261 departure: { 262 scheduled_time: "2025-09-05T14:05:00+1130", 263 estimated_time: "2025-09-05T15:05:00-1130", 264 }, 265 arrival: { 266 scheduled_time: "2025-09-05T18:35:00Z", 267 estimated_time: "2025-09-05T19:35:00Z", 268 }, 269 status: "Delayed", 270 delayed: true, 271 url: "https://example.com/D1", 272 }, 273 { 274 flight_number: "D2", 275 airline: { 276 name: null, 277 code: null, 278 icon: null, 279 }, 280 origin: { 281 city: "Origin D2", 282 code: "OD2", 283 }, 284 destination: { 285 city: "Destination D2", 286 code: "DD2", 287 }, 288 departure: { 289 scheduled_time: "2025-09-06T14:06:00Z", 290 estimated_time: "2025-09-06T15:06:00Z", 291 }, 292 arrival: { 293 scheduled_time: "2025-09-06T18:36:00Z", 294 estimated_time: "2025-09-06T19:36:00Z", 295 }, 296 status: "En Route", 297 progress_percent: 18, 298 time_left_minutes: 583, 299 delayed: true, 300 url: "https://example.com/D2", 301 }, 302 { 303 flight_number: "D3", 304 airline: { 305 name: null, 306 code: null, 307 icon: null, 308 }, 309 origin: { 310 city: "Origin D3", 311 code: "OD3", 312 }, 313 destination: { 314 city: "Destination D3", 315 code: "DD3", 316 }, 317 departure: { 318 scheduled_time: "2025-09-07T14:07:00Z", 319 estimated_time: "2025-09-07T15:07:00Z", 320 }, 321 arrival: { 322 scheduled_time: "2025-09-07T18:37:00Z", 323 estimated_time: "2025-09-07T19:37:00Z", 324 }, 325 status: "Arrived", 326 delayed: true, 327 time_left_minutes: 0, 328 url: "https://example.com/D3", 329 }, 330 ], 331 }, 332 }, 333 }, 334 ]; 335 336 const expectedList = [ 337 { 338 flight_number: "D1, Delay Air", 339 image: "chrome://browser/skin/urlbar/market-unchanged.svg", 340 departure_time: "2:05 PM", 341 departure_date: "Fri, Sep 5", 342 arrival_time: "6:35 PM", 343 origin_airport: "Origin D1 (OD1)", 344 destination_airport: "Destination D1 (DD1)", 345 status: "Delayed until 3:05 PM", 346 url: "https://example.com/D1", 347 }, 348 { 349 flight_number: "D2", 350 image: "", 351 departure_time: "3:06 PM", 352 departure_date: "Sat, Sep 6", 353 arrival_time: "7:36 PM", 354 origin_airport: "Origin D2 (OD2)", 355 destination_airport: "Destination D2 (DD2)", 356 status: "In flight", 357 time_left: "9 hr, 43 min left", 358 url: "https://example.com/D2", 359 }, 360 { 361 flight_number: "D3", 362 image: "chrome://browser/skin/urlbar/flight-airline.svg", 363 departure_time: "3:07 PM", 364 departure_date: "Sun, Sep 7", 365 arrival_time: "7:37 PM", 366 origin_airport: "Origin D3 (OD3)", 367 destination_airport: "Destination D3 (DD3)", 368 status: "Arrived", 369 url: "https://example.com/D3", 370 }, 371 ]; 372 373 await UrlbarTestUtils.promiseAutocompleteResultPopup({ 374 window, 375 value: "only match the Merino suggestion", 376 }); 377 let { element } = await UrlbarTestUtils.getDetailsOfResultAt(window, 1); 378 379 await assertUI({ row: element.row, expectedList }); 380 381 await UrlbarTestUtils.promisePopupClose(window); 382 gURLBar.handleRevert(); 383 }); 384 385 add_task(async function ui_inflight() { 386 MerinoTestUtils.server.response.body.suggestions = [ 387 { 388 provider: "flightaware", 389 is_sponsored: false, 390 score: 0, 391 title: "Flight Suggestion", 392 custom_details: { 393 flightaware: { 394 values: [ 395 { 396 flight_number: "I1", 397 airline: { 398 name: "In flight Air", 399 code: "I", 400 icon: "chrome://browser/skin/urlbar/flight-airline.svg", 401 color: "#f00", 402 }, 403 origin: { 404 city: "Origin I1", 405 code: "OI1", 406 }, 407 destination: { 408 city: "Destination I1", 409 code: "DI1", 410 }, 411 departure: { 412 scheduled_time: "2025-09-05T14:06:00+1130", 413 estimated_time: "2025-09-05T15:06:00-1130", 414 }, 415 arrival: { 416 scheduled_time: "2025-09-05T18:36:00Z", 417 estimated_time: "2025-09-05T19:36:00Z", 418 }, 419 status: "En Route", 420 progress_percent: 0, 421 url: "https://example.com/I1", 422 }, 423 { 424 flight_number: "I2", 425 airline: { 426 name: "In flight Up Air", 427 code: "IUP", 428 icon: "chrome://browser/skin/urlbar/market-up.svg", 429 color: null, 430 }, 431 origin: { 432 city: "Origin I2", 433 code: "OI2", 434 }, 435 destination: { 436 city: "Destination I2", 437 code: "DI2", 438 }, 439 departure: { 440 scheduled_time: "2025-09-05T14:07:00+1130", 441 estimated_time: "2025-09-05T15:07:00-1130", 442 }, 443 arrival: { 444 scheduled_time: "2025-09-05T18:37:00Z", 445 estimated_time: "2025-09-05T19:37:00Z", 446 }, 447 status: "En Route", 448 progress_percent: 19, 449 url: "https://example.com/I2", 450 }, 451 { 452 flight_number: "I3", 453 airline: { 454 name: "In flight Unchanged Air", 455 code: "IUN", 456 icon: "chrome://browser/skin/urlbar/market-unchanged.svg", 457 color: "#0f0", 458 }, 459 origin: { 460 city: "Origin I3", 461 code: "OI3", 462 }, 463 destination: { 464 city: "Destination I3", 465 code: "DI3", 466 }, 467 departure: { 468 scheduled_time: "2025-09-05T14:08:00+1130", 469 estimated_time: "2025-09-05T15:08:00-1130", 470 }, 471 arrival: { 472 scheduled_time: "2025-09-05T18:38:00Z", 473 estimated_time: "2025-09-05T19:38:00Z", 474 }, 475 status: "En Route", 476 progress_percent: 20, 477 url: "https://example.com/I3", 478 }, 479 { 480 flight_number: "I4", 481 airline: { 482 name: "In flight No Color Air", 483 code: "INC", 484 icon: "chrome://browser/skin/urlbar/flight-airline.svg", 485 color: null, 486 }, 487 origin: { 488 city: "Origin I4", 489 code: "OI4", 490 }, 491 destination: { 492 city: "Destination I4", 493 code: "DI4", 494 }, 495 departure: { 496 scheduled_time: "2025-09-05T14:09:00+1130", 497 estimated_time: "2025-09-05T15:09:00-1130", 498 }, 499 arrival: { 500 scheduled_time: "2025-09-05T18:39:00Z", 501 estimated_time: "2025-09-05T19:39:00Z", 502 }, 503 status: "En Route", 504 progress_percent: 39, 505 url: "https://example.com/I4", 506 }, 507 { 508 flight_number: "I5", 509 airline: { 510 name: null, 511 code: null, 512 icon: null, 513 color: "#00f", 514 }, 515 origin: { 516 city: "Origin I5", 517 code: "OI5", 518 }, 519 destination: { 520 city: "Destination I5", 521 code: "DI5", 522 }, 523 departure: { 524 scheduled_time: "2025-09-05T14:10:00+1130", 525 estimated_time: "2025-09-05T15:10:00-1130", 526 }, 527 arrival: { 528 scheduled_time: "2025-09-05T18:40:00Z", 529 estimated_time: "2025-09-05T19:40:00Z", 530 }, 531 status: "En Route", 532 progress_percent: 40, 533 url: "https://example.com/I5", 534 }, 535 { 536 flight_number: "I6", 537 airline: { 538 name: null, 539 code: null, 540 icon: null, 541 color: null, 542 }, 543 origin: { 544 city: "Origin I6", 545 code: "OI6", 546 }, 547 destination: { 548 city: "Destination I6", 549 code: "DI6", 550 }, 551 departure: { 552 scheduled_time: "2025-09-05T14:11:00+1130", 553 estimated_time: "2025-09-05T15:11:00-1130", 554 }, 555 arrival: { 556 scheduled_time: "2025-09-05T18:41:00Z", 557 estimated_time: "2025-09-05T19:41:00Z", 558 }, 559 status: "En Route", 560 progress_percent: 59, 561 url: "https://example.com/I6", 562 }, 563 { 564 flight_number: "I7", 565 airline: { 566 name: null, 567 code: null, 568 icon: null, 569 color: "#ff0", 570 }, 571 origin: { 572 city: "Origin I7", 573 code: "OI7", 574 }, 575 destination: { 576 city: "Destination I7", 577 code: "DI7", 578 }, 579 departure: { 580 scheduled_time: "2025-09-05T14:12:00+1130", 581 estimated_time: "2025-09-05T15:12:00-1130", 582 }, 583 arrival: { 584 scheduled_time: "2025-09-05T18:42:00Z", 585 estimated_time: "2025-09-05T19:42:00Z", 586 }, 587 status: "En Route", 588 progress_percent: 60, 589 url: "https://example.com/I7", 590 }, 591 { 592 flight_number: "I8", 593 airline: { 594 name: null, 595 code: null, 596 icon: null, 597 color: null, 598 }, 599 origin: { 600 city: "Origin I8", 601 code: "OI8", 602 }, 603 destination: { 604 city: "Destination I8", 605 code: "DI8", 606 }, 607 departure: { 608 scheduled_time: "2025-09-05T14:13:00+1130", 609 estimated_time: "2025-09-05T15:13:00-1130", 610 }, 611 arrival: { 612 scheduled_time: "2025-09-05T18:43:00Z", 613 estimated_time: "2025-09-05T19:43:00Z", 614 }, 615 status: "En Route", 616 progress_percent: 79, 617 url: "https://example.com/I8", 618 }, 619 { 620 flight_number: "I9", 621 airline: { 622 name: null, 623 code: null, 624 icon: null, 625 color: "#0ff", 626 }, 627 origin: { 628 city: "Origin I9", 629 code: "OI9", 630 }, 631 destination: { 632 city: "Destination I9", 633 code: "DI9", 634 }, 635 departure: { 636 scheduled_time: "2025-09-05T14:14:00+1130", 637 estimated_time: "2025-09-05T15:14:00-1130", 638 }, 639 arrival: { 640 scheduled_time: "2025-09-05T18:44:00Z", 641 estimated_time: "2025-09-05T19:44:00Z", 642 }, 643 status: "En Route", 644 progress_percent: 80, 645 url: "https://example.com/I9", 646 }, 647 { 648 flight_number: "I10", 649 airline: { 650 name: null, 651 code: null, 652 icon: null, 653 color: null, 654 }, 655 origin: { 656 city: "Origin I10", 657 code: "OI10", 658 }, 659 destination: { 660 city: "Destination I10", 661 code: "DI10", 662 }, 663 departure: { 664 scheduled_time: "2025-09-05T14:15:00+1130", 665 estimated_time: "2025-09-05T15:15:00-1130", 666 }, 667 arrival: { 668 scheduled_time: "2025-09-05T18:45:00Z", 669 estimated_time: "2025-09-05T19:45:00Z", 670 }, 671 status: "En Route", 672 progress_percent: 100, 673 url: "https://example.com/I10", 674 }, 675 ], 676 }, 677 }, 678 }, 679 ]; 680 681 const expectedList = [ 682 { 683 background: { 684 image: "chrome://browser/skin/urlbar/flight-inflight-progress-0.svg", 685 fill: "rgb(255, 0, 0)", 686 stroke: "rgb(255, 0, 0)", 687 }, 688 foreground: { 689 image: "chrome://browser/skin/urlbar/flight-airline.svg", 690 }, 691 }, 692 { 693 background: { 694 image: "chrome://browser/skin/urlbar/flight-inflight-progress-0.svg", 695 }, 696 foreground: { 697 image: "chrome://browser/skin/urlbar/market-up.svg", 698 }, 699 }, 700 { 701 background: { 702 image: "chrome://browser/skin/urlbar/flight-inflight-progress-1.svg", 703 fill: "rgb(0, 255, 0)", 704 stroke: "rgb(0, 255, 0)", 705 }, 706 foreground: { 707 image: "chrome://browser/skin/urlbar/market-unchanged.svg", 708 }, 709 }, 710 { 711 background: { 712 image: "chrome://browser/skin/urlbar/flight-inflight-progress-1.svg", 713 }, 714 foreground: { 715 image: "chrome://browser/skin/urlbar/flight-airline.svg", 716 }, 717 }, 718 { 719 background: { 720 image: "chrome://browser/skin/urlbar/flight-inflight-progress-2.svg", 721 fill: "rgb(0, 0, 255)", 722 stroke: "rgb(0, 0, 255)", 723 }, 724 foreground: { 725 image: "", 726 }, 727 }, 728 { 729 background: { 730 image: "chrome://browser/skin/urlbar/flight-inflight-progress-2.svg", 731 }, 732 foreground: { 733 image: "", 734 }, 735 }, 736 { 737 background: { 738 image: "chrome://browser/skin/urlbar/flight-inflight-progress-3.svg", 739 fill: "rgb(255, 255, 0)", 740 stroke: "rgb(255, 255, 0)", 741 }, 742 foreground: { 743 image: "", 744 }, 745 }, 746 { 747 background: { 748 image: "chrome://browser/skin/urlbar/flight-inflight-progress-3.svg", 749 }, 750 foreground: { 751 image: "", 752 }, 753 }, 754 { 755 background: { 756 image: "chrome://browser/skin/urlbar/flight-inflight-progress-4.svg", 757 fill: "rgb(0, 255, 255)", 758 stroke: "rgb(0, 255, 255)", 759 }, 760 foreground: { 761 image: "", 762 }, 763 }, 764 { 765 background: { 766 image: "chrome://browser/skin/urlbar/flight-inflight-progress-4.svg", 767 }, 768 foreground: { 769 image: "", 770 }, 771 }, 772 ]; 773 774 await UrlbarTestUtils.promiseAutocompleteResultPopup({ 775 window, 776 value: "only match the Merino suggestion", 777 }); 778 let { element } = await UrlbarTestUtils.getDetailsOfResultAt(window, 1); 779 780 let items = element.row.querySelectorAll(".urlbarView-realtime-item"); 781 Assert.equal(items.length, expectedList.length); 782 783 for (let i = 0; i < items.length; i++) { 784 info(`Check the item[${i}]`); 785 let item = items[i]; 786 let expected = expectedList[i]; 787 788 await TestUtils.waitForCondition( 789 () => item.querySelector(`[name=status_${i}]`).textContent == "In flight" 790 ); 791 let backgroundStyle = window.getComputedStyle( 792 item.querySelector(".urlbarView-realtime-image-container") 793 ); 794 Assert.equal( 795 backgroundStyle.backgroundImage, 796 `url("${expected.background.image}")` 797 ); 798 799 // The fill and stroke uses currentColor as the default. 800 let defaultColor = backgroundStyle.color; 801 let expectedFillColor = expected.background.fill ?? defaultColor; 802 let expectedStrokeColor = expected.background.stroke ?? defaultColor; 803 Assert.equal(backgroundStyle.fill, expectedFillColor); 804 Assert.equal(backgroundStyle.stroke, expectedStrokeColor); 805 Assert.equal( 806 item.querySelector(".urlbarView-realtime-image").src, 807 expected.foreground.image 808 ); 809 } 810 811 await UrlbarTestUtils.promisePopupClose(window); 812 gURLBar.handleRevert(); 813 }); 814 815 add_task(async function activate_single() { 816 MerinoTestUtils.server.response.body.suggestions = TEST_MERINO_SINGLE; 817 818 for (let mouse of [true, false]) { 819 await UrlbarTestUtils.promiseAutocompleteResultPopup({ 820 window, 821 value: "only match the Merino suggestion", 822 }); 823 let { element } = await UrlbarTestUtils.getDetailsOfResultAt(window, 1); 824 let { row } = element; 825 826 let target = TEST_MERINO_SINGLE[0].custom_details.flightaware.values[0]; 827 let expectedURL = target.url; 828 let newTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, expectedURL); 829 830 if (mouse) { 831 info("Activate by mouse"); 832 let root = row.querySelector(".urlbarView-realtime-root"); 833 EventUtils.synthesizeMouseAtCenter(root, {}); 834 } else { 835 info("Activate by key"); 836 EventUtils.synthesizeKey("KEY_Tab"); 837 Assert.equal( 838 UrlbarTestUtils.getSelectedRow(window), 839 row, 840 "The row should be selected" 841 ); 842 EventUtils.synthesizeKey("KEY_Enter"); 843 } 844 845 let newTab = await newTabOpened; 846 Assert.ok(true, `Expected URL is loaded [${expectedURL}]`); 847 848 await UrlbarTestUtils.promisePopupClose(window); 849 BrowserTestUtils.removeTab(newTab); 850 await PlacesUtils.history.clear(); 851 } 852 }); 853 854 add_task(async function activate_multi() { 855 MerinoTestUtils.server.response.body.suggestions = TEST_MERINO_MULTI; 856 857 for (let [ 858 index, 859 value, 860 ] of TEST_MERINO_MULTI[0].custom_details.flightaware.values.entries()) { 861 info(`Activate item[${index}] by mouse`); 862 await UrlbarTestUtils.promiseAutocompleteResultPopup({ 863 window, 864 value: "only match the Merino suggestion", 865 }); 866 let { element } = await UrlbarTestUtils.getDetailsOfResultAt(window, 1); 867 868 let items = element.row.querySelectorAll(".urlbarView-realtime-item"); 869 let item = items[index]; 870 871 let newTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, value.url); 872 await EventUtils.synthesizeMouseAtCenter(item, {}, item.ownerGlobal); 873 874 let newTab = await newTabOpened; 875 Assert.ok(true, `Expected URL is loaded [${value.url}]`); 876 BrowserTestUtils.removeTab(newTab); 877 await PlacesUtils.history.clear(); 878 } 879 880 for (let [ 881 index, 882 value, 883 ] of TEST_MERINO_MULTI[0].custom_details.flightaware.values.entries()) { 884 info(`Activate item[${index}] by key`); 885 await UrlbarTestUtils.promiseAutocompleteResultPopup({ 886 window, 887 value: "only match the Merino suggestion", 888 }); 889 let { element } = await UrlbarTestUtils.getDetailsOfResultAt(window, 1); 890 891 for (let i = 0; i < index + 1; i++) { 892 EventUtils.synthesizeKey("KEY_Tab"); 893 } 894 895 let items = element.row.querySelectorAll(".urlbarView-realtime-item"); 896 let item = items[index]; 897 898 let newTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, value.url); 899 await EventUtils.synthesizeMouseAtCenter(item, {}, item.ownerGlobal); 900 let newTab = await newTabOpened; 901 Assert.ok(true, `Expected URL is loaded [${value.url}]`); 902 BrowserTestUtils.removeTab(newTab); 903 await PlacesUtils.history.clear(); 904 } 905 906 await UrlbarTestUtils.promisePopupClose(window); 907 gURLBar.handleRevert(); 908 }); 909 910 async function assertUI({ row, expectedList }) { 911 if (expectedList.length > 1) { 912 Assert.deepEqual( 913 document.l10n.getAttributes(row._content), 914 { 915 id: "urlbar-result-aria-group-flight-status", 916 args: null, 917 }, 918 "ARIA group label should be set on the row inner" 919 ); 920 } else { 921 Assert.deepEqual( 922 document.l10n.getAttributes(row._content), 923 { 924 id: null, 925 args: null, 926 }, 927 "ARIA group label should not be set on the row inner" 928 ); 929 } 930 931 let items = row.querySelectorAll(".urlbarView-realtime-item"); 932 Assert.equal(items.length, expectedList.length); 933 934 // Select the row, which will select the first item if there are multiple 935 // items. 936 UrlbarTestUtils.setSelectedRowIndex(window, 1); 937 938 for (let i = 0; i < items.length; i++) { 939 info(`Check the item[${i}]`); 940 let item = items[i]; 941 let expected = expectedList[i]; 942 943 await TestUtils.waitForCondition( 944 () => 945 item.querySelector(`[name=status_${i}]`).textContent == expected.status, 946 "Wait until the status text will be applied by Fluent" 947 ); 948 Assert.equal( 949 item.querySelector(".urlbarView-realtime-image").src, 950 expected.image 951 ); 952 Assert.equal( 953 item.querySelector(`[name=departure_time_${i}]`).textContent, 954 expected.departure_time 955 ); 956 Assert.equal( 957 item.querySelector(`[name=departure_date_${i}]`).textContent, 958 expected.departure_date 959 ); 960 Assert.equal( 961 item.querySelector(`[name=arrival_time_${i}]`).textContent, 962 expected.arrival_time 963 ); 964 Assert.equal( 965 item.querySelector(`[name=origin_airport_${i}]`).textContent, 966 expected.origin_airport 967 ); 968 Assert.equal( 969 item.querySelector(`[name=destination_airport_${i}]`).textContent, 970 expected.destination_airport 971 ); 972 Assert.equal( 973 item.querySelector(`[name=flight_number_${i}]`).textContent, 974 expected.flight_number 975 ); 976 977 let timeLeftMinutes = item.querySelector(`[name=time_left_${i}]`); 978 if (typeof expected.time_left != "undefined") { 979 Assert.equal(timeLeftMinutes.textContent, expected.time_left); 980 } else { 981 Assert.equal(timeLeftMinutes.textContent, ""); 982 let previousSeparator = timeLeftMinutes.previousElementSibling; 983 Assert.ok(BrowserTestUtils.isHidden(previousSeparator)); 984 } 985 986 Assert.equal( 987 gURLBar.value, 988 expected.url, 989 "Input value should be the expected URL" 990 ); 991 992 // Select the next item. 993 EventUtils.synthesizeKey("KEY_Tab"); 994 } 995 996 // Clear the selection. 997 UrlbarTestUtils.setSelectedRowIndex(window, -1); 998 }