test_unified_extensions_migration.js (10353B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // We're in an xpcshell test but have an eslint browser test env applied; 7 // We definitely do need to manually import CustomizableUI. 8 // eslint-disable-next-line mozilla/no-redeclare-with-import-autofix 9 const { CustomizableUI } = ChromeUtils.importESModule( 10 "moz-src:///browser/components/customizableui/CustomizableUI.sys.mjs" 11 ); 12 13 do_get_profile(); 14 15 // Make Cu.isInAutomation true. This is necessary so that we can use 16 // CustomizableUIInternal. 17 Services.prefs.setBoolPref( 18 "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer", 19 true 20 ); 21 22 const CustomizableUIInternal = CustomizableUI.getTestOnlyInternalProp( 23 "CustomizableUIInternal" 24 ); 25 26 // Migration 19 was the Unified Extensions migration version introduced 27 // in 109, so we'll run tests by artificially setting the migration version 28 // to one value earlier. 29 const PRIOR_MIGRATION_VERSION = 18; 30 31 /** 32 * Writes customization state into CustomizableUI and then performs the forward migration 33 * for Unified Extensions. 34 * 35 * @param {object|null} stateObj An object that will be structure-cloned and 36 * written into CustomizableUI's internal `gSavedState` state variable. Should 37 * not include the currentVersion property, as this will be set automatically by 38 * function if stateObj is not null. 39 * @returns {object} 40 * the saved state object (minus the currentVersion property). 41 */ 42 function migrateForward(stateObj) { 43 // We make sure to use structuredClone here so that we don't end up comparing 44 // SAVED_STATE against itself. 45 let stateToSave = structuredClone(stateObj); 46 if (stateToSave) { 47 stateToSave.currentVersion = PRIOR_MIGRATION_VERSION; 48 } 49 50 CustomizableUI.setTestOnlyInternalProp("gSavedState", stateToSave); 51 CustomizableUIInternal.updateForNewVersion(); 52 53 let migratedState = CustomizableUI.getTestOnlyInternalProp("gSavedState"); 54 if (migratedState) { 55 delete migratedState.currentVersion; 56 } 57 return migratedState; 58 } 59 60 /** 61 * Test that attempting a migration on a new profile with no saved 62 * state exits safely. 63 */ 64 add_task(async function test_no_saved_state() { 65 let migratedState = migrateForward(null); 66 67 Assert.deepEqual( 68 migratedState, 69 null, 70 "gSavedState should not have been modified" 71 ); 72 }); 73 74 /** 75 * Test that attempting a migration on a new profile with no saved 76 * state exits safely. 77 */ 78 add_task(async function test_no_saved_placements() { 79 let migratedState = migrateForward({}); 80 81 Assert.deepEqual( 82 migratedState, 83 {}, 84 "gSavedState should not have been modified" 85 ); 86 }); 87 88 /** 89 * Test that placements that don't involve any extension buttons are 90 * not changed during the migration. 91 */ 92 add_task(async function test_no_extensions() { 93 const SAVED_STATE = { 94 placements: { 95 "nav-bar": [ 96 "back-button", 97 "forward-button", 98 "spring", 99 "vertical-spacer", 100 "urlbar-container", 101 "reset-pbm-toolbar-button", 102 ], 103 "toolbar-menubar": [ 104 "home-button", 105 "menubar-items", 106 "spring", 107 "downloads-button", 108 ], 109 TabsToolbar: [ 110 "firefox-view-button", 111 "tabbrowser-tabs", 112 "new-tab-button", 113 "alltabs-button", 114 "developer-button", 115 ], 116 PersonalToolbar: ["personal-bookmarks", "fxa-toolbar-menu-button"], 117 "widget-overflow-fixed-list": ["privatebrowsing-button", "panic-button"], 118 }, 119 }; 120 121 // ADDONS_AREA should end up with an empty array as its set of placements. 122 const EXPECTED_STATE = structuredClone(SAVED_STATE); 123 EXPECTED_STATE.placements[CustomizableUI.AREA_ADDONS] = []; 124 125 let migratedState = migrateForward(SAVED_STATE); 126 127 Assert.deepEqual( 128 migratedState, 129 EXPECTED_STATE, 130 "Got the expected state after the migration." 131 ); 132 }); 133 134 /** 135 * Test that if there's an existing set of items in CustomizableUI.AREA_ADDONS, 136 * and no extension buttons to migrate from the overflow menu, then we don't 137 * change the state at all. 138 */ 139 add_task(async function test_existing_browser_actions_no_movement() { 140 const SAVED_STATE = { 141 placements: { 142 "nav-bar": [ 143 "back-button", 144 "forward-button", 145 "spring", 146 "vertical-spacer", 147 "urlbar-container", 148 "reset-pbm-toolbar-button", 149 ], 150 "toolbar-menubar": [ 151 "home-button", 152 "menubar-items", 153 "spring", 154 "downloads-button", 155 ], 156 TabsToolbar: [ 157 "firefox-view-button", 158 "tabbrowser-tabs", 159 "new-tab-button", 160 "alltabs-button", 161 "developer-button", 162 ], 163 PersonalToolbar: ["personal-bookmarks", "fxa-toolbar-menu-button"], 164 "widget-overflow-fixed-list": ["privatebrowsing-button", "panic-button"], 165 "unified-extensions-area": ["ext0-browser-action", "ext1-browser-action"], 166 }, 167 }; 168 169 let migratedState = migrateForward(SAVED_STATE); 170 171 Assert.deepEqual( 172 migratedState, 173 SAVED_STATE, 174 "The saved state should not have changed after migration." 175 ); 176 }); 177 178 /** 179 * Test that we can migrate extension buttons out from the overflow panel 180 * into the addons panel. 181 */ 182 add_task(async function test_migrate_extension_buttons() { 183 const SAVED_STATE = { 184 placements: { 185 "nav-bar": [ 186 "back-button", 187 "forward-button", 188 "spring", 189 "vertical-spacer", 190 "urlbar-container", 191 "reset-pbm-toolbar-button", 192 ], 193 "toolbar-menubar": [ 194 "home-button", 195 "menubar-items", 196 "spring", 197 "downloads-button", 198 ], 199 TabsToolbar: [ 200 "firefox-view-button", 201 "tabbrowser-tabs", 202 "new-tab-button", 203 "alltabs-button", 204 "developer-button", 205 ], 206 PersonalToolbar: ["personal-bookmarks", "fxa-toolbar-menu-button"], 207 "widget-overflow-fixed-list": [ 208 "ext0-browser-action", 209 "privatebrowsing-button", 210 "ext1-browser-action", 211 "panic-button", 212 "ext2-browser-action", 213 ], 214 }, 215 }; 216 const EXPECTED_STATE = structuredClone(SAVED_STATE); 217 EXPECTED_STATE.placements[CustomizableUI.AREA_FIXED_OVERFLOW_PANEL] = [ 218 "privatebrowsing-button", 219 "panic-button", 220 ]; 221 EXPECTED_STATE.placements[CustomizableUI.AREA_ADDONS] = [ 222 "ext0-browser-action", 223 "ext1-browser-action", 224 "ext2-browser-action", 225 ]; 226 227 let migratedState = migrateForward(SAVED_STATE); 228 229 Assert.deepEqual( 230 migratedState, 231 EXPECTED_STATE, 232 "The saved state should not have changed after migration." 233 ); 234 }); 235 236 /** 237 * Test that we won't overwrite existing placements within the addons panel 238 * if we migrate things over from the overflow panel. We'll prepend the 239 * migrated items to the addons panel instead. 240 */ 241 add_task(async function test_migrate_extension_buttons_no_overwrite() { 242 const SAVED_STATE = { 243 placements: { 244 "nav-bar": [ 245 "back-button", 246 "forward-button", 247 "spring", 248 "vertical-spacer", 249 "urlbar-container", 250 "reset-pbm-toolbar-button", 251 ], 252 "toolbar-menubar": [ 253 "home-button", 254 "menubar-items", 255 "spring", 256 "downloads-button", 257 ], 258 TabsToolbar: [ 259 "firefox-view-button", 260 "tabbrowser-tabs", 261 "new-tab-button", 262 "alltabs-button", 263 "developer-button", 264 ], 265 PersonalToolbar: ["personal-bookmarks", "fxa-toolbar-menu-button"], 266 "widget-overflow-fixed-list": [ 267 "ext0-browser-action", 268 "privatebrowsing-button", 269 "ext1-browser-action", 270 "panic-button", 271 "ext2-browser-action", 272 ], 273 "unified-extensions-area": ["ext3-browser-action", "ext4-browser-action"], 274 }, 275 }; 276 const EXPECTED_STATE = structuredClone(SAVED_STATE); 277 EXPECTED_STATE.placements[CustomizableUI.AREA_FIXED_OVERFLOW_PANEL] = [ 278 "privatebrowsing-button", 279 "panic-button", 280 ]; 281 EXPECTED_STATE.placements[CustomizableUI.AREA_ADDONS] = [ 282 "ext0-browser-action", 283 "ext1-browser-action", 284 "ext2-browser-action", 285 "ext3-browser-action", 286 "ext4-browser-action", 287 ]; 288 289 let migratedState = migrateForward(SAVED_STATE); 290 291 Assert.deepEqual( 292 migratedState, 293 EXPECTED_STATE, 294 "The saved state should not have changed after migration." 295 ); 296 }); 297 298 /** 299 * Test that extension buttons from areas other than the overflow panel 300 * won't be moved. 301 */ 302 add_task(async function test_migrate_extension_buttons_elsewhere() { 303 const SAVED_STATE = { 304 placements: { 305 "nav-bar": [ 306 "back-button", 307 "ext0-browser-action", 308 "forward-button", 309 "ext1-browser-action", 310 "spring", 311 "ext2-browser-action", 312 "vertical-spacer", 313 "urlbar-container", 314 "ext3-browser-action", 315 "reset-pbm-toolbar-button", 316 "ext4-browser-action", 317 ], 318 "toolbar-menubar": [ 319 "home-button", 320 "ext5-browser-action", 321 "menubar-items", 322 "ext6-browser-action", 323 "spring", 324 "ext7-browser-action", 325 "downloads-button", 326 "ext8-browser-action", 327 ], 328 TabsToolbar: [ 329 "firefox-view-button", 330 "ext9-browser-action", 331 "tabbrowser-tabs", 332 "ext10-browser-action", 333 "new-tab-button", 334 "ext11-browser-action", 335 "alltabs-button", 336 "ext12-browser-action", 337 "developer-button", 338 "ext13-browser-action", 339 ], 340 PersonalToolbar: [ 341 "personal-bookmarks", 342 "ext14-browser-action", 343 "fxa-toolbar-menu-button", 344 "ext15-browser-action", 345 ], 346 "widget-overflow-fixed-list": [ 347 "ext16-browser-action", 348 "privatebrowsing-button", 349 "ext17-browser-action", 350 "panic-button", 351 "ext18-browser-action", 352 ], 353 }, 354 }; 355 const EXPECTED_STATE = structuredClone(SAVED_STATE); 356 EXPECTED_STATE.placements[CustomizableUI.AREA_FIXED_OVERFLOW_PANEL] = [ 357 "privatebrowsing-button", 358 "panic-button", 359 ]; 360 EXPECTED_STATE.placements[CustomizableUI.AREA_ADDONS] = [ 361 "ext16-browser-action", 362 "ext17-browser-action", 363 "ext18-browser-action", 364 ]; 365 366 let migratedState = migrateForward(SAVED_STATE); 367 368 Assert.deepEqual( 369 migratedState, 370 EXPECTED_STATE, 371 "The saved state should not have changed after migration." 372 ); 373 });