browser_signed_out_avatar_variants.js (7122B)
1 /* Any copyright is dedicated to the Public Domain. 2 https://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const { NimbusTestUtils } = ChromeUtils.importESModule( 7 "resource://testing-common/NimbusTestUtils.sys.mjs" 8 ); 9 10 const { ToolbarBadgeHub } = ChromeUtils.importESModule( 11 "resource:///modules/asrouter/ToolbarBadgeHub.sys.mjs" 12 ); 13 14 const DEFAULT_ICON = "avatar-empty.svg"; 15 const HUMAN_CIRCLE_BADGED = "avatar-empty.svg"; 16 const HUMAN_CIRCLE = "avatar-empty-circle.svg"; 17 const FOX_CIRCLE_BADGED = "avatar-fox.svg"; 18 const FOX_CIRCLE = "avatar-fox-circle.svg"; 19 20 // No matter which branch we're in, we expect this icon to be used for the 21 // signed-in state by default. 22 const SIGNED_IN_ICON = "avatar.svg"; 23 24 /** 25 * Checks that the current icon for the FxA avatar menu button matches 26 * iconFilename. 27 * 28 * @param {DOMWindow} win 29 * The browser window to test the icon for. 30 * @param {string} iconFilename 31 * The expected iconFilename. This is not the full path to the image. 32 * Example: "avatar-empty.svg". 33 * @param {string} message 34 * The assertion message to display. 35 */ 36 function assertCurrentIcon(win, iconFilename, message) { 37 let image = win.document.querySelector("#fxa-avatar-image"); 38 let avatarURL = win.getComputedStyle(image).listStyleImage; 39 let expectedURL = `url("chrome://browser/skin/fxa/${iconFilename}")`; 40 Assert.equal(avatarURL, expectedURL, message); 41 } 42 43 /** 44 * Asserts that we're in the signed-out state, and that the signed-out icon 45 * in win matches our iconFilename. 46 * 47 * @param {DOMWindow} win 48 * The browser window to test the icon for. 49 * @param {string} iconFilename 50 * The expected iconFilename. This is not the full path to the image. 51 * Example: "avatar-empty.svg". 52 */ 53 function assertSignedOutIcon(win, iconFilename) { 54 Assert.equal( 55 UIState.get().status, 56 UIState.STATUS_NOT_CONFIGURED, 57 "Currently signed out." 58 ); 59 assertCurrentIcon( 60 win, 61 iconFilename, 62 `Signed-out avatar image is ${iconFilename}` 63 ); 64 } 65 66 /** 67 * Fakes out a signed-in state and then asserts that the signed-in icon 68 * is the generic signed-in icon that we always use. Then we revert the 69 * faked signed-in state. 70 * 71 * @param {DOMWindow} win 72 * The browser window to test the icon for. 73 */ 74 function assertSignedInIcon(win) { 75 const oldUIState = UIState.get; 76 77 UIState.get = () => ({ 78 status: UIState.STATUS_SIGNED_IN, 79 lastSync: new Date(), 80 email: "foo@bar.com", 81 }); 82 Services.obs.notifyObservers(null, UIState.ON_UPDATE); 83 84 assertCurrentIcon( 85 win, 86 SIGNED_IN_ICON, 87 `Signed-in avatar image is ${SIGNED_IN_ICON}` 88 ); 89 90 UIState.get = oldUIState; 91 Services.obs.notifyObservers(null, UIState.ON_UPDATE); 92 } 93 94 /** 95 * Asserts that we're in the signed-out state, and that when badged, we're 96 * showing the iconFilename icon in the window. This reverts any badging state 97 * on the window before returning. 98 * 99 * @param {DOMWindow} win 100 * The browser window to test the icon for. 101 * @param {string} iconFilename 102 * The expected iconFilename. This is not the full path to the image. 103 * Example: "avatar-empty.svg". 104 */ 105 function assertBadgedIcon(win, iconFilename) { 106 Assert.equal( 107 UIState.get().status, 108 UIState.STATUS_NOT_CONFIGURED, 109 "Currently signed out." 110 ); 111 112 let button = win.document.querySelector("#fxa-toolbar-menu-button"); 113 let badge = button.querySelector(".toolbarbutton-badge"); 114 badge.classList.add("feature-callout"); 115 button.setAttribute("badged", true); 116 button.toggleAttribute("showing-callout", true); 117 118 assertCurrentIcon( 119 win, 120 iconFilename, 121 `Badged avatar image is ${iconFilename}` 122 ); 123 124 badge.classList.remove("feature-callout"); 125 button.removeAttribute("badged"); 126 button.toggleAttribute("showing-callout", false); 127 } 128 129 /** 130 * Opens up a new browser window, makes sure its FxA state is initialized, and 131 * then runs taskFn (passing it the opened window). When taskFn resolves, the 132 * window is closed and an (optional) cleanup function is run. 133 * 134 * @param {Function|null} doCleanup 135 * An optional async cleanup function to call once the browser window has 136 * closed. 137 * @param {Function} taskFn 138 * An async function to run once the browser window has opened and its FxA 139 * state has initialized. This is passed the opened window as its only 140 * argument. 141 * @returns {Promise<undefined>} 142 */ 143 async function testInNewWindow(doCleanup, taskFn) { 144 let win = await BrowserTestUtils.openNewBrowserWindow(); 145 win.gSync.init(); 146 147 await taskFn(win); 148 await BrowserTestUtils.closeWindow(win); 149 if (doCleanup) { 150 await doCleanup(); 151 } 152 } 153 154 /** 155 * Tests that we can change the signed-out icon for the FxA avatar menu via 156 * Experimenter. Also ensures that the signed-in icon is not affected by these 157 * signed-out variants. 158 */ 159 160 add_setup(async () => { 161 UIState.get = () => ({ 162 status: UIState.STATUS_NOT_CONFIGURED, 163 }); 164 Services.obs.notifyObservers(null, UIState.ON_UPDATE); 165 gSync.init(); 166 }); 167 168 /** 169 * Tests that we use the default icon when not enrolled in the experiment. 170 */ 171 add_task(async function test_default() { 172 Assert.equal( 173 NimbusFeatures.fxaButtonVisibility.getVariable("avatarIconVariant"), 174 undefined, 175 "Should not start with a NimbusFeature set for the signed-out icon." 176 ); 177 178 await testInNewWindow(null /* no cleanup */, async win => { 179 assertSignedOutIcon(win, DEFAULT_ICON); 180 assertSignedInIcon(win); 181 }); 182 }); 183 184 /** 185 * Tests that we use the default icon when enrolled in the control branch. 186 */ 187 add_task(async function test_control() { 188 let doCleanup = await NimbusTestUtils.enrollWithFeatureConfig( 189 { 190 featureId: NimbusFeatures.fxaButtonVisibility.featureId, 191 value: { 192 avatarIconVariant: "control", 193 }, 194 }, 195 { isRollout: true } 196 ); 197 198 await testInNewWindow(doCleanup, async win => { 199 assertSignedOutIcon(win, DEFAULT_ICON); 200 assertSignedInIcon(win); 201 }); 202 }); 203 204 /** 205 * Tests that we use the human-circle icon when enrolled in the human-circle 206 * branch, and that we hide the circle when in the badged state. 207 */ 208 add_task(async function test_human_circle() { 209 let doCleanup = await NimbusTestUtils.enrollWithFeatureConfig( 210 { 211 featureId: NimbusFeatures.fxaButtonVisibility.featureId, 212 value: { 213 avatarIconVariant: "human-circle", 214 }, 215 }, 216 { isRollout: true } 217 ); 218 219 await testInNewWindow(doCleanup, async win => { 220 assertSignedOutIcon(win, HUMAN_CIRCLE); 221 assertBadgedIcon(win, HUMAN_CIRCLE_BADGED); 222 assertSignedInIcon(win); 223 }); 224 }); 225 226 /** 227 * Tests that we use the fox-circle icon when enrolled in the fox-circle 228 * branch, and that we hide the circle when in the badged state. 229 */ 230 add_task(async function test_fox_circle() { 231 let doCleanup = await NimbusTestUtils.enrollWithFeatureConfig( 232 { 233 featureId: NimbusFeatures.fxaButtonVisibility.featureId, 234 value: { 235 avatarIconVariant: "fox-circle", 236 }, 237 }, 238 { isRollout: true } 239 ); 240 241 await testInNewWindow(doCleanup, async win => { 242 assertSignedOutIcon(win, FOX_CIRCLE); 243 assertBadgedIcon(win, FOX_CIRCLE_BADGED); 244 assertSignedInIcon(win); 245 }); 246 });