browser_search_firefoxSuggest.js (13758B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 // This tests the Search pane's Firefox Suggest UI. 5 6 "use strict"; 7 8 ChromeUtils.defineESModuleGetters(this, { 9 QuickSuggest: "moz-src:///browser/components/urlbar/QuickSuggest.sys.mjs", 10 }); 11 12 const ONLINE_ENABLED_TOGGLE_ID = "firefoxSuggestOnlineEnabledToggle"; 13 const BUTTON_RESTORE_DISMISSED_ID = "restoreDismissedSuggestions"; 14 15 // Maps `SETTINGS_UI` values to expected visibility state objects. See 16 // `assertSuggestVisibility()` in `head.js` for info on the state objects. 17 const EXPECTED = { 18 [QuickSuggest.SETTINGS_UI.FULL]: { 19 [ONLINE_ENABLED_TOGGLE_ID]: { isVisible: true }, 20 locationBarGroupHeader: { 21 isVisible: true, 22 l10nId: "addressbar-header-firefox-suggest-2", 23 }, 24 }, 25 [QuickSuggest.SETTINGS_UI.NONE]: { 26 locationBarGroupHeader: { isVisible: true, l10nId: "addressbar-header-1" }, 27 }, 28 [QuickSuggest.SETTINGS_UI.OFFLINE_ONLY]: { 29 [ONLINE_ENABLED_TOGGLE_ID]: { isVisible: false }, 30 locationBarGroupHeader: { 31 isVisible: true, 32 l10nId: "addressbar-header-firefox-suggest-2", 33 }, 34 }, 35 }; 36 37 // This test can take a while due to the many permutations some of these tasks 38 // run through, so request a longer timeout. 39 requestLongerTimeout(10); 40 41 add_setup(async function () { 42 // Suggest needs to be initialized in order to dismiss a suggestion. 43 await QuickSuggestTestUtils.ensureQuickSuggestInit(); 44 45 // Set the default value of the preference to FULL, since that's what the 46 // test was originally written with. 47 await SpecialPowers.pushPrefEnv({ 48 set: [ 49 ["browser.urlbar.quicksuggest.settingsUi", QuickSuggest.SETTINGS_UI.FULL], 50 ], 51 }); 52 }); 53 54 // The following tasks check the initial visibility of the Firefox Suggest UI 55 // and the visibility after installing a Nimbus experiment. 56 57 add_task(async function initiallyDisabled_disable() { 58 await doSuggestVisibilityTest({ 59 initialSuggestEnabled: false, 60 initialExpected: EXPECTED[QuickSuggest.SETTINGS_UI.NONE], 61 nimbusVariables: { 62 quickSuggestEnabled: false, 63 }, 64 }); 65 }); 66 67 add_task(async function initiallyDisabled_disable_settingsUiFull() { 68 await doSuggestVisibilityTest({ 69 initialSuggestEnabled: false, 70 initialExpected: EXPECTED[QuickSuggest.SETTINGS_UI.NONE], 71 nimbusVariables: { 72 quickSuggestEnabled: false, 73 // `quickSuggestEnabled: false` should override this, so the Suggest 74 // settings should not be visible (`initialExpected` should persist). 75 quickSuggestSettingsUi: QuickSuggest.SETTINGS_UI.FULL, 76 }, 77 }); 78 }); 79 80 add_task(async function initiallyDisabled_enable() { 81 await doSuggestVisibilityTest({ 82 initialSuggestEnabled: false, 83 initialExpected: EXPECTED[QuickSuggest.SETTINGS_UI.NONE], 84 nimbusVariables: { 85 quickSuggestEnabled: true, 86 }, 87 newExpected: EXPECTED[QuickSuggest.SETTINGS_UI.FULL], 88 }); 89 }); 90 91 add_task(async function initiallyDisabled_enable_settingsUiFull() { 92 await doSuggestVisibilityTest({ 93 initialSuggestEnabled: false, 94 initialExpected: EXPECTED[QuickSuggest.SETTINGS_UI.NONE], 95 nimbusVariables: { 96 quickSuggestEnabled: true, 97 quickSuggestSettingsUi: QuickSuggest.SETTINGS_UI.FULL, 98 }, 99 newExpected: EXPECTED[QuickSuggest.SETTINGS_UI.FULL], 100 }); 101 }); 102 103 add_task(async function initiallyDisabled_enable_settingsUiNone() { 104 await doSuggestVisibilityTest({ 105 initialSuggestEnabled: false, 106 initialExpected: EXPECTED[QuickSuggest.SETTINGS_UI.NONE], 107 nimbusVariables: { 108 quickSuggestEnabled: true, 109 quickSuggestSettingsUi: QuickSuggest.SETTINGS_UI.NONE, 110 }, 111 }); 112 }); 113 114 add_task(async function initiallyDisabled_enable_settingsUiOfflineOnly() { 115 await doSuggestVisibilityTest({ 116 initialSuggestEnabled: false, 117 initialExpected: EXPECTED[QuickSuggest.SETTINGS_UI.NONE], 118 nimbusVariables: { 119 quickSuggestEnabled: true, 120 quickSuggestSettingsUi: QuickSuggest.SETTINGS_UI.OFFLINE_ONLY, 121 }, 122 newExpected: EXPECTED[QuickSuggest.SETTINGS_UI.OFFLINE_ONLY], 123 }); 124 }); 125 126 add_task(async function initiallyEnabled_disable() { 127 await doSuggestVisibilityTest({ 128 initialSuggestEnabled: true, 129 initialExpected: EXPECTED[QuickSuggest.SETTINGS_UI.FULL], 130 nimbusVariables: { 131 quickSuggestEnabled: false, 132 }, 133 newExpected: EXPECTED[QuickSuggest.SETTINGS_UI.NONE], 134 }); 135 }); 136 137 add_task(async function initiallyEnabled_disable_settingsUiFull() { 138 await doSuggestVisibilityTest({ 139 initialSuggestEnabled: true, 140 initialExpected: EXPECTED[QuickSuggest.SETTINGS_UI.FULL], 141 nimbusVariables: { 142 quickSuggestEnabled: false, 143 // `quickSuggestEnabled: false` should override this, so the Suggest 144 // settings should not be visible. 145 quickSuggestSettingsUi: QuickSuggest.SETTINGS_UI.FULL, 146 }, 147 newExpected: EXPECTED[QuickSuggest.SETTINGS_UI.NONE], 148 }); 149 }); 150 151 add_task(async function initiallyEnabled_enable() { 152 await doSuggestVisibilityTest({ 153 initialSuggestEnabled: true, 154 initialExpected: EXPECTED[QuickSuggest.SETTINGS_UI.FULL], 155 nimbusVariables: { 156 quickSuggestEnabled: true, 157 }, 158 }); 159 }); 160 161 add_task(async function initiallyEnabled_settingsUiFull() { 162 await doSuggestVisibilityTest({ 163 initialSuggestEnabled: true, 164 initialExpected: EXPECTED[QuickSuggest.SETTINGS_UI.FULL], 165 nimbusVariables: { 166 quickSuggestSettingsUi: QuickSuggest.SETTINGS_UI.FULL, 167 }, 168 }); 169 }); 170 171 add_task(async function initiallyEnabled_settingsUiNone() { 172 await doSuggestVisibilityTest({ 173 initialSuggestEnabled: true, 174 initialExpected: EXPECTED[QuickSuggest.SETTINGS_UI.FULL], 175 nimbusVariables: { 176 quickSuggestSettingsUi: QuickSuggest.SETTINGS_UI.NONE, 177 }, 178 newExpected: EXPECTED[QuickSuggest.SETTINGS_UI.NONE], 179 }); 180 }); 181 182 add_task(async function initiallyEnabled_settingsUiOfflineOnly() { 183 await doSuggestVisibilityTest({ 184 initialSuggestEnabled: true, 185 initialExpected: EXPECTED[QuickSuggest.SETTINGS_UI.FULL], 186 nimbusVariables: { 187 quickSuggestSettingsUi: QuickSuggest.SETTINGS_UI.OFFLINE_ONLY, 188 }, 189 newExpected: EXPECTED[QuickSuggest.SETTINGS_UI.OFFLINE_ONLY], 190 }); 191 }); 192 193 add_task(async function toggling_all_firefoxsuggest_disables_other_options() { 194 // Enable quicksuggest since it could be off by default depending on location. 195 await SpecialPowers.pushPrefEnv({ 196 set: [["browser.urlbar.suggest.quicksuggest.all", true]], 197 }); 198 199 await openPreferencesViaOpenPreferencesAPI("search", { leaveOpen: true }); 200 201 let doc = gBrowser.selectedBrowser.contentDocument; 202 let allCheckbox = doc.getElementById("firefoxSuggestAll"); 203 let sponsoredCheckbox = doc.getElementById("firefoxSuggestSponsored"); 204 let onlineEnabledCheckbox = doc.getElementById( 205 "firefoxSuggestOnlineEnabledToggle" 206 ); 207 208 // Initial state. 209 Assert.ok( 210 allCheckbox.checked, 211 "firefoxSuggestAll should initially be checked" 212 ); 213 Assert.ok( 214 !sponsoredCheckbox.disabled, 215 "sponsoredCheckbox should initially be enabled" 216 ); 217 Assert.ok( 218 !onlineEnabledCheckbox.disabled, 219 "onlineEnabledCheckbox should initially be enabled" 220 ); 221 222 allCheckbox.click(); 223 await allCheckbox.parentElement.updateComplete; 224 225 Assert.ok(!allCheckbox.checked, "firefoxSuggestAll should now be unchecked"); 226 Assert.ok(sponsoredCheckbox.disabled, "sponsoredCheckbox should be disabled"); 227 Assert.ok( 228 onlineEnabledCheckbox.disabled, 229 "onlineEnabledCheckbox should be disabled" 230 ); 231 232 allCheckbox.click(); 233 await allCheckbox.parentElement.updateComplete; 234 235 Assert.ok(allCheckbox.checked, "firefoxSuggestAll should be checked"); 236 Assert.ok( 237 !sponsoredCheckbox.disabled, 238 "sponsoredCheckbox should be enabled again" 239 ); 240 Assert.ok( 241 !onlineEnabledCheckbox.disabled, 242 "onlineEnabledCheckbox should be enabled again" 243 ); 244 245 gBrowser.removeCurrentTab(); 246 }); 247 248 add_task( 249 async function all_firefoxsuggest_disabled_disables_other_options_on_open() { 250 // Disable the "all" preference and enable the others before opening settings. 251 await SpecialPowers.pushPrefEnv({ 252 set: [ 253 ["browser.urlbar.suggest.quicksuggest.all", false], 254 ["browser.urlbar.suggest.quicksuggest.sponsored", true], 255 ["browser.urlbar.quicksuggest.online.enabled", true], 256 ], 257 }); 258 259 await openPreferencesViaOpenPreferencesAPI("search", { leaveOpen: true }); 260 261 let doc = gBrowser.selectedBrowser.contentDocument; 262 let allCheckbox = doc.getElementById("firefoxSuggestAll"); 263 let sponsoredCheckbox = doc.getElementById("firefoxSuggestSponsored"); 264 let onlineEnabledCheckbox = doc.getElementById( 265 "firefoxSuggestOnlineEnabledToggle" 266 ); 267 268 // Initial state. 269 Assert.ok(!allCheckbox.checked, "firefoxSuggestAll should not be checked"); 270 Assert.ok( 271 sponsoredCheckbox.disabled, 272 "sponsoredCheckbox should initially be disabled" 273 ); 274 Assert.ok( 275 onlineEnabledCheckbox.disabled, 276 "onlineEnabledCheckbox should initially be disabled" 277 ); 278 279 gBrowser.removeCurrentTab(); 280 281 await SpecialPowers.popPrefEnv(); 282 } 283 ); 284 285 // Tests the "Restore" button for dismissed suggestions. 286 add_task(async function restoreDismissedSuggestions() { 287 // Start with no dismissed suggestions. 288 await QuickSuggest.clearDismissedSuggestions(); 289 Assert.ok( 290 !(await QuickSuggest.canClearDismissedSuggestions()), 291 "canClearDismissedSuggestions should be false after clearing suggestions" 292 ); 293 294 await openPreferencesViaOpenPreferencesAPI("search", { leaveOpen: true }); 295 296 let doc = gBrowser.selectedBrowser.contentDocument; 297 let addressBarSection = doc.getElementById("locationBarGroup"); 298 addressBarSection.scrollIntoView(); 299 300 let button = doc.getElementById(BUTTON_RESTORE_DISMISSED_ID); 301 Assert.ok(button.disabled, "Restore button is disabled initially."); 302 303 await QuickSuggest.dismissResult(QuickSuggestTestUtils.ampResult()); 304 305 Assert.ok( 306 await QuickSuggest.canClearDismissedSuggestions(), 307 "canClearDismissedSuggestions should return true after dismissing a suggestion" 308 ); 309 await TestUtils.waitForCondition( 310 () => !button.disabled, 311 "Waiting for Restore button to become enabled after dismissing suggestion" 312 ); 313 Assert.ok( 314 !button.disabled, 315 "Restore button should be enabled after dismissing suggestion" 316 ); 317 318 let clearPromise = TestUtils.topicObserved("quicksuggest-dismissals-cleared"); 319 button.click(); 320 await clearPromise; 321 322 Assert.ok( 323 !(await QuickSuggest.canClearDismissedSuggestions()), 324 "canClearDismissedSuggestions should return false after restoring dismissals" 325 ); 326 await TestUtils.waitForCondition( 327 () => button.disabled, 328 "Waiting for Restore button to become disabled after clicking it" 329 ); 330 Assert.ok( 331 button.disabled, 332 "Restore button should be disabled after clearing suggestions" 333 ); 334 335 gBrowser.removeCurrentTab(); 336 }); 337 338 // If the pane is open while Suggest is still initializing and there are 339 // dismissed suggestions, the "Restore" button should become enabled when init 340 // finishes. 341 add_task(async function restoreDismissedSuggestions_init_enabled() { 342 // Dismiss a suggestion. 343 await QuickSuggest.dismissResult(QuickSuggestTestUtils.ampResult()); 344 Assert.ok( 345 await QuickSuggest.canClearDismissedSuggestions(), 346 "canClearDismissedSuggestions should be true after dismissing suggestion" 347 ); 348 349 await doRestoreInitTest(async button => { 350 // The button should become enabled since we dismissed a suggestion above. 351 await TestUtils.waitForCondition( 352 () => !button.disabled, 353 "Waiting for Restore button to become enabled after re-enabling Rust backend" 354 ); 355 Assert.ok( 356 !button.disabled, 357 "Restore button should be enabled after re-enabling Rust backend" 358 ); 359 }); 360 }); 361 362 // If the pane is open while Suggest is still initializing and there are no 363 // dismissed suggestions, the "Restore" button should remain disabled when init 364 // finishes. 365 add_task(async function restoreDismissedSuggestions_init_disabled() { 366 // Clear dismissed suggestions. 367 await QuickSuggest.clearDismissedSuggestions(); 368 Assert.ok( 369 !(await QuickSuggest.canClearDismissedSuggestions()), 370 "canClearDismissedSuggestions should be false after clearing suggestions" 371 ); 372 373 await doRestoreInitTest(async button => { 374 // The button should remain disabled since there are no dismissed 375 // suggestions. 376 await TestUtils.waitForTick(); 377 Assert.ok( 378 button.disabled, 379 "Restore button should remain disabled after re-enabling Rust backend" 380 ); 381 }); 382 }); 383 384 async function doRestoreInitTest(checkButton) { 385 // Disable the Suggest Rust backend, which manages individually dismissed 386 // suggestions. While Rust is disabled, Suggest won't be able to tell whether 387 // there are any individually dismissed suggestions. 388 await SpecialPowers.pushPrefEnv({ 389 set: [["browser.urlbar.quicksuggest.rustEnabled", false]], 390 }); 391 392 // Open the pane. 393 await openPreferencesViaOpenPreferencesAPI("search", { leaveOpen: true }); 394 395 let doc = gBrowser.selectedBrowser.contentDocument; 396 let addressBarSection = doc.getElementById("locationBarGroup"); 397 addressBarSection.scrollIntoView(); 398 399 let button = doc.getElementById(BUTTON_RESTORE_DISMISSED_ID); 400 Assert.ok(button.disabled, "Restore button is disabled initially."); 401 402 // Re-enable the Rust backend. It will send `quicksuggest-dismissals-changed` 403 // when it finishes initialization. 404 let changedPromise = TestUtils.topicObserved( 405 "quicksuggest-dismissals-changed" 406 ); 407 await SpecialPowers.popPrefEnv(); 408 409 info( 410 "Waiting for quicksuggest-dismissals-changed after re-enabling Rust backend" 411 ); 412 await changedPromise; 413 414 await checkButton(button); 415 416 // Clean up. 417 await QuickSuggest.clearDismissedSuggestions(); 418 gBrowser.removeCurrentTab(); 419 }