test_menu_message.html (11681B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>Tests for the FxA Menu Message component</title> 6 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> 7 <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> 8 <script 9 src="chrome://browser/content/asrouter/components/menu-message.mjs" 10 type="module" 11 ></script> 12 <link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> 13 <script> 14 const { BrowserTestUtils } = ChromeUtils.importESModule( 15 "resource://testing-common/BrowserTestUtils.sys.mjs" 16 ); 17 18 /** 19 * Tests that the exposed properties of the component are reflected 20 * as expected in the shadow DOM. 21 */ 22 add_task(async function test_exposed_properties() { 23 let message = document.createElement("menu-message"); 24 const TEST_IMAGE_URL = "chrome://activity-stream/content/data/content/assets/fox-doodle-waving-static.png"; 25 message.imageURL = TEST_IMAGE_URL; 26 const TEST_LOGO_URL = "chrome://branding/content/about-logo.svg"; 27 message.logoURL = TEST_LOGO_URL; 28 const TEST_BUTTON_TEXT = "Howdy, partner! Sign up!"; 29 message.buttonText = TEST_BUTTON_TEXT; 30 const PRIMARY_TEXT = "This is the primary text"; 31 message.primaryText = PRIMARY_TEXT; 32 const SECONDARY_TEXT = "This is the secondary text"; 33 message.secondaryText = SECONDARY_TEXT; 34 35 let content = document.getElementById("content"); 36 content.appendChild(message); 37 await message.updateComplete; 38 39 let shadow = message.shadowRoot; 40 let image = shadow.querySelector("#illustration"); 41 is(image.src, TEST_IMAGE_URL, "The illustration img element got the expected URL"); 42 43 let logo = shadow.querySelector("#logo"); 44 is(logo.src, TEST_LOGO_URL, "The logo element got the expected URL"); 45 46 let button = shadow.querySelector("#primary-button"); 47 is(button.textContent.trim(), TEST_BUTTON_TEXT, "The primary button got the right text."); 48 49 let primaryText = shadow.querySelector("#primary"); 50 is(primaryText.textContent, PRIMARY_TEXT, "The primary text was correct."); 51 52 let secondaryText = shadow.querySelector("#secondary"); 53 is(secondaryText.textContent, SECONDARY_TEXT, "The secondary text was correct."); 54 55 let container = shadow.querySelector("#container"); 56 is(container.getAttribute("layout"), "column", "The layout should default to 'column' when no layout is explicitly set."); 57 58 const TEST_ROW_LAYOUT = "row"; 59 message.layout = TEST_ROW_LAYOUT 60 await message.updateComplete; 61 is(container.getAttribute("layout"), TEST_ROW_LAYOUT, "The layout attribute should update to 'row' when set."); 62 63 message.remove(); 64 }); 65 66 /** 67 * Tests that the buttons exposed by the component emit the expected 68 * events. 69 */ 70 add_task(async function test_button_properties() { 71 let message = document.createElement("menu-message"); 72 const TEST_BUTTON_TEXT = "Howdy, partner! Sign up!"; 73 message.buttonText = TEST_BUTTON_TEXT; 74 75 let content = document.getElementById("content"); 76 content.appendChild(message); 77 await message.updateComplete; 78 79 let shadow = message.shadowRoot; 80 81 let primaryEventPromise = BrowserTestUtils.waitForEvent(message, "MenuMessage:PrimaryButton"); 82 let primaryButton = shadow.querySelector("#primary-button"); 83 primaryButton.click(); 84 await primaryEventPromise; 85 ok(true, "Got the MenuMessage:PrimaryButton event"); 86 87 let closeEventPromise = BrowserTestUtils.waitForEvent(message, "MenuMessage:Close"); 88 let closeButton = shadow.querySelector("#close-button"); 89 closeButton.click(); 90 await closeEventPromise; 91 ok(true, "Got the MenuMessage:Close event"); 92 93 message.remove(); 94 }); 95 96 /** 97 * Tests that the primary button is focused by default, and that focus 98 * can be changed via the keyboard. 99 */ 100 add_task(async function test_primary_button_focus() { 101 let message = document.createElement("menu-message"); 102 const TEST_BUTTON_TEXT = "Howdy, partner! Sign up!"; 103 message.buttonText = TEST_BUTTON_TEXT; 104 105 let content = document.getElementById("content"); 106 content.appendChild(message); 107 await message.updateComplete; 108 109 message.focus(); 110 111 let shadow = message.shadowRoot; 112 let primaryButton = shadow.querySelector("#primary-button"); 113 is(shadow.activeElement, primaryButton, "primary button is focused by default."); 114 115 let closeButton = shadow.querySelector("#close-button"); 116 const FOCUS_CHANGING_KEYS = [ 117 "ArrowLeft", 118 "ArrowRight", 119 "ArrowUp", 120 "ArrowDown", 121 ]; 122 123 for (let keyName of FOCUS_CHANGING_KEYS) { 124 synthesizeKey(`KEY_${keyName}`); 125 // Now the close button should be focused. 126 is(shadow.activeElement, closeButton, "Close button is now focused."); 127 128 synthesizeKey(`KEY_${keyName}`); 129 // And pressing the same key should swap focus back to the primary 130 // button. 131 is(shadow.activeElement, primaryButton, "primary button is now focused."); 132 } 133 134 message.remove(); 135 }); 136 137 /** 138 * Tests that setting no imageURL makes it so that the image element is 139 * not visible, and setting one makes it visible. 140 */ 141 add_task(async function test_image_visibility() { 142 let message = document.createElement("menu-message"); 143 const TEST_BUTTON_TEXT = "Howdy, partner! Sign up!"; 144 message.buttonText = TEST_BUTTON_TEXT; 145 146 let content = document.getElementById("content"); 147 content.appendChild(message); 148 await message.updateComplete; 149 150 let illustrationContainer = message.shadowRoot.querySelector("#illustration-container"); 151 ok(isHidden(illustrationContainer), "Illustration container should be hidden."); 152 153 message.imageURL = "some-image.png"; 154 await message.updateComplete; 155 ok(!isHidden(illustrationContainer), "Illustration container should be visible."); 156 157 message.remove(); 158 }); 159 160 async function testIllustrationOffset({ 161 layout, 162 offsetVar, 163 cssProperty, 164 checkContainerOffset = false, 165 }) { 166 const TEST_DEFAULT_VALUE = "0px"; 167 const TEST_CONTAINER_OFFSET = "10px"; 168 const TEST_ILLUSTRATION_OFFSET = "123px"; 169 const TEST_IMAGE_URL = 170 "chrome://activity-stream/content/data/content/assets/fox-doodle-waving-static.png"; 171 172 let message = document.createElement("menu-message"); 173 message.imageURL = TEST_IMAGE_URL; 174 if (layout) { 175 message.layout = layout; 176 } 177 178 document.getElementById("content").appendChild(message); 179 await message.updateComplete; 180 181 let illustrationContainer = message.shadowRoot.querySelector( 182 "#illustration-container" 183 ); 184 ok( 185 !isHidden(illustrationContainer), 186 "Illustration container should not be hidden." 187 ); 188 189 let computedStyle = window.getComputedStyle(illustrationContainer); 190 is( 191 computedStyle[cssProperty], 192 TEST_DEFAULT_VALUE, 193 "Illustration offset should default to 0px" 194 ); 195 196 message.style.setProperty(offsetVar, TEST_ILLUSTRATION_OFFSET); 197 computedStyle = window.getComputedStyle(illustrationContainer); 198 is( 199 computedStyle[cssProperty], 200 TEST_ILLUSTRATION_OFFSET, 201 "Illustration offset should have been forwarded to the container." 202 ); 203 204 if (checkContainerOffset) { 205 const container = message.shadowRoot.querySelector("#container"); 206 let containerStyle = window.getComputedStyle(container); 207 is( 208 containerStyle.marginBlockEnd, 209 TEST_DEFAULT_VALUE, 210 "Container offset should default to 0px." 211 ); 212 message.style.setProperty( 213 "--container-margin-block-end-offset", 214 TEST_CONTAINER_OFFSET 215 ); 216 containerStyle = window.getComputedStyle(container); 217 is( 218 containerStyle.marginBlockEnd, 219 TEST_CONTAINER_OFFSET, 220 "Container offset should have been applied." 221 ); 222 } 223 message.remove(); 224 } 225 226 /** 227 * Tests that setting the --illustration-margin-block-start-offset forwards that 228 * offset to the illustration container for 'column' layout. 229 */ 230 add_task(async function test_column_layout_illustration_offset() { 231 await testIllustrationOffset({ 232 layout: null, 233 offsetVar: "--illustration-margin-block-start-offset", 234 cssProperty: "marginBlockStart", 235 }); 236 }); 237 238 /** 239 * Tests that setting the --illustration-margin-block-end-offset forwards that 240 * offset to the illustration container for 'row' layout. 241 */ 242 add_task(async function test_row_layout_illustration_offset() { 243 await testIllustrationOffset({ 244 layout: "row", 245 offsetVar: "--illustration-margin-block-end-offset", 246 cssProperty: "marginBlockEnd", 247 checkContainerOffset: true, 248 }); 249 }); 250 251 /** 252 * Tests that the primary button supports a 'small' size and defaults to 'default'. 253 */ 254 add_task(async function test_primary_button_size() { 255 let message = document.createElement("menu-message"); 256 message.buttonText = "Test button"; 257 document.getElementById("content").appendChild(message); 258 await message.updateComplete; 259 260 let shadow = message.shadowRoot; 261 let btn = shadow.querySelector("#primary-button"); 262 is(btn.getAttribute("size"), "default", "Button size defaults to 'default'."); 263 264 message.primaryButtonSize = "small"; 265 await message.updateComplete; 266 is(btn.getAttribute("size"), "small", "Button size updates to 'small'."); 267 268 message.remove(); 269 }); 270 271 /** 272 * Tests "simple" layout, which only displays primary text and primary button. 273 */ 274 add_task(async function test_simple_layout() { 275 let message = document.createElement("menu-message"); 276 message.layout = "simple"; 277 message.buttonText = "Set as default"; 278 message.primaryText = "Firefox is not your default browser"; 279 message.secondaryText = "You should not see me!"; 280 // Provide URLs to ensure images exist but are hidden by the CSS 281 message.logoURL = "chrome://branding/content/about-logo.svg"; 282 message.imageURL = 283 "chrome://browser/content/asrouter/assets/fox-with-devices.svg"; 284 285 document.getElementById("content").appendChild(message); 286 await message.updateComplete; 287 const shadow = message.shadowRoot; 288 const container = shadow.querySelector("#container"); 289 is( 290 container.getAttribute("layout"), 291 "simple", 292 "Layout for container is 'simple'." 293 ); 294 295 const primary = shadow.querySelector("#primary"); 296 ok(!isHidden(primary), "Primary text is visible."); 297 const btn = shadow.querySelector("#primary-button"); 298 ok(!isHidden(btn), "Primary button is visible."); 299 300 const closeBtn = shadow.querySelector("#close-button"); 301 is( 302 getComputedStyle(closeBtn).display, 303 "none", 304 "Close button is hidden." 305 ); 306 307 const secondary = shadow.querySelector("#secondary"); 308 is( 309 getComputedStyle(secondary).display, 310 "none", 311 "Secondary text is hidden." 312 ); 313 314 for (const img of shadow.querySelectorAll("img")) { 315 is( 316 getComputedStyle(img).display, 317 "none", 318 "Images are hidden." 319 ); 320 } 321 message.remove(); 322 }); 323 </script> 324 </head> 325 <body> 326 <p id="display"></p> 327 <div id="content"></div> 328 <pre id="test"></pre> 329 </body> 330 </html>