Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(388)

Side by Side Diff: chrome/test/data/webui/cr_elements/cr_action_menu_test.js

Issue 2966163004: [cr-action-menu] Use clientWidth for rtl flipping. (Closed)
Patch Set: fix test on mac Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview Tests for cr-action-menu element. Runs as an interactive UI 6 * @fileoverview Tests for cr-action-menu element. Runs as an interactive UI
7 * test, since many of these tests check focus behavior. 7 * test, since many of these tests check focus behavior.
8 */ 8 */
9 suite('CrActionMenu', function() { 9 suite('CrActionMenu', function() {
10 /** @type {?CrActionMenuElement} */ 10 /** @type {?CrActionMenuElement} */
11 var menu = null; 11 var menu = null;
12 12
13 /** @type {?NodeList<HTMLElement>} */ 13 /** @type {?NodeList<HTMLElement>} */
14 var items = null; 14 var items = null;
15 15
16 /** @type {HTMLElement} */
17 var dots = null;
18
16 setup(function() { 19 setup(function() {
17 PolymerTest.clearBody(); 20 PolymerTest.clearBody();
18 21
19 document.body.innerHTML = ` 22 document.body.innerHTML = `
20 <button id="dots">...</button> 23 <button id="dots">...</button>
21 <dialog is="cr-action-menu"> 24 <dialog is="cr-action-menu">
22 <button class="dropdown-item">Un</button> 25 <button class="dropdown-item">Un</button>
23 <hr> 26 <hr>
24 <button class="dropdown-item">Dos</button> 27 <button class="dropdown-item">Dos</button>
25 <button class="dropdown-item">Tres</button> 28 <button class="dropdown-item">Tres</button>
26 </dialog> 29 </dialog>
27 `; 30 `;
28 31
29 menu = document.querySelector('dialog[is=cr-action-menu]'); 32 menu = document.querySelector('dialog[is=cr-action-menu]');
30 items = menu.querySelectorAll('.dropdown-item'); 33 items = menu.querySelectorAll('.dropdown-item');
34 dots = document.querySelector('#dots');
31 assertEquals(3, items.length); 35 assertEquals(3, items.length);
32 }); 36 });
33 37
34 teardown(function() { 38 teardown(function() {
39 document.body.style.direction = 'ltr';
40
35 if (menu.open) 41 if (menu.open)
36 menu.close(); 42 menu.close();
37 }); 43 });
38 44
39 function down() { 45 function down() {
40 MockInteractions.keyDownOn(menu, 'ArrowDown', [], 'ArrowDown'); 46 MockInteractions.keyDownOn(menu, 'ArrowDown', [], 'ArrowDown');
41 } 47 }
42 48
43 function up() { 49 function up() {
44 MockInteractions.keyDownOn(menu, 'ArrowUp', [], 'ArrowUp'); 50 MockInteractions.keyDownOn(menu, 'ArrowUp', [], 'ArrowUp');
45 } 51 }
46 52
47 test('hidden or disabled items', function() { 53 test('hidden or disabled items', function() {
48 menu.showAt(document.querySelector('#dots')); 54 menu.showAt(dots);
49 down(); 55 down();
50 assertEquals(menu.root.activeElement, items[0]); 56 assertEquals(menu.root.activeElement, items[0]);
51 57
52 menu.close(); 58 menu.close();
53 items[0].hidden = true; 59 items[0].hidden = true;
54 menu.showAt(document.querySelector('#dots')); 60 menu.showAt(dots);
55 down(); 61 down();
56 assertEquals(menu.root.activeElement, items[1]); 62 assertEquals(menu.root.activeElement, items[1]);
57 63
58 menu.close(); 64 menu.close();
59 items[1].disabled = true; 65 items[1].disabled = true;
60 menu.showAt(document.querySelector('#dots')); 66 menu.showAt(dots);
61 down(); 67 down();
62 assertEquals(menu.root.activeElement, items[2]); 68 assertEquals(menu.root.activeElement, items[2]);
63 }); 69 });
64 70
65 test('focus after down/up arrow', function() { 71 test('focus after down/up arrow', function() {
66 menu.showAt(document.querySelector('#dots')); 72 menu.showAt(dots);
67 73
68 // The menu should be focused when shown, but not on any of the items. 74 // The menu should be focused when shown, but not on any of the items.
69 assertEquals(menu, document.activeElement); 75 assertEquals(menu, document.activeElement);
70 assertNotEquals(items[0], menu.root.activeElement); 76 assertNotEquals(items[0], menu.root.activeElement);
71 assertNotEquals(items[1], menu.root.activeElement); 77 assertNotEquals(items[1], menu.root.activeElement);
72 assertNotEquals(items[2], menu.root.activeElement); 78 assertNotEquals(items[2], menu.root.activeElement);
73 79
74 down(); 80 down();
75 assertEquals(items[0], menu.root.activeElement); 81 assertEquals(items[0], menu.root.activeElement);
76 down(); 82 down();
77 assertEquals(items[1], menu.root.activeElement); 83 assertEquals(items[1], menu.root.activeElement);
78 down(); 84 down();
79 assertEquals(items[2], menu.root.activeElement); 85 assertEquals(items[2], menu.root.activeElement);
80 down(); 86 down();
81 assertEquals(items[0], menu.root.activeElement); 87 assertEquals(items[0], menu.root.activeElement);
82 up(); 88 up();
83 assertEquals(items[2], menu.root.activeElement); 89 assertEquals(items[2], menu.root.activeElement);
84 up(); 90 up();
85 assertEquals(items[1], menu.root.activeElement); 91 assertEquals(items[1], menu.root.activeElement);
86 up(); 92 up();
87 assertEquals(items[0], menu.root.activeElement); 93 assertEquals(items[0], menu.root.activeElement);
88 up(); 94 up();
89 assertEquals(items[2], menu.root.activeElement); 95 assertEquals(items[2], menu.root.activeElement);
90 96
91 items[1].disabled = true; 97 items[1].disabled = true;
92 up(); 98 up();
93 assertEquals(items[0], menu.root.activeElement); 99 assertEquals(items[0], menu.root.activeElement);
94 }); 100 });
95 101
96 test('pressing up arrow when no focus will focus last item', function(){ 102 test('pressing up arrow when no focus will focus last item', function() {
97 menu.showAt(document.querySelector('#dots')); 103 menu.showAt(dots);
98 assertEquals(menu, document.activeElement); 104 assertEquals(menu, document.activeElement);
99 105
100 up(); 106 up();
101 assertEquals(items[items.length - 1], menu.root.activeElement); 107 assertEquals(items[items.length - 1], menu.root.activeElement);
102 }); 108 });
103 109
104 test('can navigate to dynamically added items', function() { 110 test('can navigate to dynamically added items', function() {
105 // Can modify children after attached() and before showAt(). 111 // Can modify children after attached() and before showAt().
106 var item = document.createElement('button'); 112 var item = document.createElement('button');
107 item.classList.add('dropdown-item'); 113 item.classList.add('dropdown-item');
108 menu.insertBefore(item, items[0]); 114 menu.insertBefore(item, items[0]);
109 menu.showAt(document.querySelector('#dots')); 115 menu.showAt(dots);
110 116
111 down(); 117 down();
112 assertEquals(item, menu.root.activeElement); 118 assertEquals(item, menu.root.activeElement);
113 down(); 119 down();
114 assertEquals(items[0], menu.root.activeElement); 120 assertEquals(items[0], menu.root.activeElement);
115 121
116 // Can modify children while menu is open. 122 // Can modify children while menu is open.
117 menu.removeChild(item); 123 menu.removeChild(item);
118 124
119 up(); 125 up();
120 // Focus should have wrapped around to final item. 126 // Focus should have wrapped around to final item.
121 assertEquals(items[2], menu.root.activeElement); 127 assertEquals(items[2], menu.root.activeElement);
122 }); 128 });
123 129
124 test('close on resize', function() { 130 test('close on resize', function() {
125 menu.showAt(document.querySelector('#dots')); 131 menu.showAt(dots);
126 assertTrue(menu.open); 132 assertTrue(menu.open);
127 133
128 window.dispatchEvent(new CustomEvent('resize')); 134 window.dispatchEvent(new CustomEvent('resize'));
129 assertFalse(menu.open); 135 assertFalse(menu.open);
130 }); 136 });
131 137
132 test('close on popstate', function() { 138 test('close on popstate', function() {
133 menu.showAt(document.querySelector('#dots')); 139 menu.showAt(dots);
134 assertTrue(menu.open); 140 assertTrue(menu.open);
135 141
136 window.dispatchEvent(new CustomEvent('popstate')); 142 window.dispatchEvent(new CustomEvent('popstate'));
137 assertFalse(menu.open); 143 assertFalse(menu.open);
138 }); 144 });
139 145
140 /** @param {string} key The key to use for closing. */ 146 /** @param {string} key The key to use for closing. */
141 function testFocusAfterClosing(key) { 147 function testFocusAfterClosing(key) {
142 return new Promise(function(resolve) { 148 return new Promise(function(resolve) {
143 var dots = document.querySelector('#dots');
144 menu.showAt(dots); 149 menu.showAt(dots);
145 assertTrue(menu.open); 150 assertTrue(menu.open);
146 151
147 // Check that focus returns to the anchor element. 152 // Check that focus returns to the anchor element.
148 dots.addEventListener('focus', resolve); 153 dots.addEventListener('focus', resolve);
149 MockInteractions.keyDownOn(menu, key, [], key); 154 MockInteractions.keyDownOn(menu, key, [], key);
150 assertFalse(menu.open); 155 assertFalse(menu.open);
151 }); 156 });
152 } 157 }
153 158
154 test('close on Tab', function() { return testFocusAfterClosing('Tab'); }); 159 test('close on Tab', function() {
160 return testFocusAfterClosing('Tab');
161 });
155 test('close on Escape', function() { 162 test('close on Escape', function() {
156 return testFocusAfterClosing('Escape'); 163 return testFocusAfterClosing('Escape');
157 }); 164 });
158 165
159 test('mouse movement focus options', function() { 166 test('mouse movement focus options', function() {
160 function makeMouseoverEvent(node) { 167 function makeMouseoverEvent(node) {
161 var e = new MouseEvent('mouseover', {bubbles: true}); 168 var e = new MouseEvent('mouseover', {bubbles: true});
162 node.dispatchEvent(e); 169 node.dispatchEvent(e);
163 } 170 }
164 171
165 menu.showAt(document.querySelector('#dots')); 172 menu.showAt(dots);
166 173
167 // Moving mouse on option 1 should focus it. 174 // Moving mouse on option 1 should focus it.
168 assertNotEquals(items[0], menu.root.activeElement); 175 assertNotEquals(items[0], menu.root.activeElement);
169 makeMouseoverEvent(items[0]); 176 makeMouseoverEvent(items[0]);
170 assertEquals(items[0], menu.root.activeElement); 177 assertEquals(items[0], menu.root.activeElement);
171 178
172 // Moving mouse on the menu (not on option) should focus the menu. 179 // Moving mouse on the menu (not on option) should focus the menu.
173 makeMouseoverEvent(menu); 180 makeMouseoverEvent(menu);
174 assertNotEquals(items[0], menu.root.activeElement); 181 assertNotEquals(items[0], menu.root.activeElement);
175 assertEquals(menu, document.activeElement); 182 assertEquals(menu, document.activeElement);
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
252 menu.close(); 259 menu.close();
253 260
254 // If the viewport can't fit the menu, align the menu to the viewport. 261 // If the viewport can't fit the menu, align the menu to the viewport.
255 menu.showAtPosition({ 262 menu.showAtPosition({
256 left: menuWidth - 5, 263 left: menuWidth - 5,
257 top: 0, 264 top: 0,
258 width: 0, 265 width: 0,
259 height: 0, 266 height: 0,
260 maxX: menuWidth * 2 - 10, 267 maxX: menuWidth * 2 - 10,
261 }); 268 });
262 assertEquals(`${menuWidth - 10}px`, menu.style.left); 269 assertEquals(`${menuWidth - 10}px`, menu.style.left);
263 assertEquals(`0px`, menu.style.top); 270 assertEquals(`0px`, menu.style.top);
264 menu.close(); 271 menu.close();
265 272
266 // Alignment is reversed in RTL. 273 // Alignment is reversed in RTL.
267 document.body.style.direction = 'rtl'; 274 document.body.style.direction = 'rtl';
268 menu.showAtPosition(config); 275 menu.showAtPosition(config);
269 assertTrue(menu.open); 276 assertTrue(menu.open);
270 assertEquals(140 - menuWidth, menu.offsetLeft); 277 assertEquals(140 - menuWidth, menu.offsetLeft);
271 assertEquals('250px', menu.style.top); 278 assertEquals('250px', menu.style.top);
272 menu.close(); 279 menu.close();
273 document.body.style.direction = 'ltr';
274 }); 280 });
275 281
276 test('offscreen scroll positioning', function() { 282 suite('offscreen scroll positioning', function() {
277 var bodyHeight = 10000; 283 var bodyHeight = 10000;
278 var bodyWidth = 20000; 284 var bodyWidth = 20000;
279 var containerLeft = 5000; 285 var containerLeft = 5000;
280 var containerTop = 10000; 286 var containerTop = 10000;
281 var containerWidth = 500; 287 var containerWidth = 500;
282 var containerHeight = 500; 288 var containerHeight = 500;
283 document.body.innerHTML = ` 289 var menuWidth = 100;
284 <style> 290 var menuHeight = 200;
285 body {
286 height: ${bodyHeight}px;
287 width: ${bodyWidth}px;
288 }
289 291
290 #container { 292 setup(function() {
291 overflow: auto; 293 document.body.scrollTop = 0;
292 position: absolute; 294 document.body.scrollLeft = 0;
293 top: ${containerTop}px; 295 document.body.innerHTML = `
294 left: ${containerLeft}px; 296 <style>
295 height: ${containerHeight}px; 297 body {
296 width: ${containerWidth}px; 298 height: ${bodyHeight}px;
297 } 299 width: ${bodyWidth}px;
300 }
298 301
299 #inner-container { 302 #container {
300 height: 1000px; 303 overflow: auto;
301 width: 1000px; 304 position: absolute;
302 } 305 top: ${containerTop}px;
303 </style> 306 left: ${containerLeft}px;
304 <div id="container"> 307 right: ${containerLeft}px;
305 <div id="inner-container"> 308 height: ${containerHeight}px;
306 <button id="dots">...</button> 309 width: ${containerWidth}px;
307 <dialog is="cr-action-menu"> 310 }
308 <button class="dropdown-item">Un</button> 311
309 <hr> 312 #inner-container {
310 <button class="dropdown-item">Dos</button> 313 height: 1000px;
311 <button class="dropdown-item">Tres</button> 314 width: 1000px;
312 </dialog> 315 }
316
317 dialog {
318 height: ${menuHeight};
319 width: ${menuWidth};
320 padding: 0;
321 }
322 </style>
323 <div id="container">
324 <div id="inner-container">
325 <button id="dots">...</button>
326 <dialog is="cr-action-menu">
327 <button class="dropdown-item">Un</button>
328 <hr>
329 <button class="dropdown-item">Dos</button>
330 <button class="dropdown-item">Tres</button>
331 </dialog>
332 </div>
313 </div> 333 </div>
314 </div> 334 `;
315 `; 335 menu = document.querySelector('dialog[is=cr-action-menu]');
316 menu = document.querySelector('dialog[is=cr-action-menu]'); 336 dots = document.querySelector('#dots');
317 var dots = document.querySelector('#dots'); 337 })
318 338
319 // Show the menu, scrolling the body to the button. 339 // Show the menu, scrolling the body to the button.
320 menu.showAt( 340 test('simple offscreen', function() {
321 dots, 341 menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START});
322 {anchorAlignmentX: AnchorAlignment.AFTER_START}); 342 assertEquals(`${containerLeft}px`, menu.style.left);
323 assertEquals(`${containerLeft}px`, menu.style.left); 343 assertEquals(`${containerTop}px`, menu.style.top);
324 assertEquals(`${containerTop}px`, menu.style.top); 344 menu.close();
325 menu.close(); 345 });
326 346
327 // Show the menu, scrolling the container to the button, and the body to the 347 // Show the menu, scrolling the container to the button, and the body to the
328 // button. 348 // button.
329 document.body.scrollLeft = bodyWidth; 349 test('offscreen and out of scroll container viewport', function() {
330 document.body.scrollTop = bodyHeight; 350 document.body.scrollLeft = bodyWidth;
351 document.body.scrollTop = bodyHeight;
352 var container = document.querySelector('#container');
331 353
332 document.querySelector('#container').scrollLeft = containerLeft; 354 container.scrollLeft = containerLeft;
333 document.querySelector('#container').scrollTop = containerTop; 355 container.scrollTop = containerTop;
334 356
335 menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START}); 357 menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START});
336 assertEquals(`${containerLeft}px`, menu.style.left); 358 assertEquals(`${containerLeft}px`, menu.style.left);
337 assertEquals(`${containerTop}px`, menu.style.top); 359 assertEquals(`${containerTop}px`, menu.style.top);
338 menu.close(); 360 menu.close();
361 });
339 362
340 // Show the menu for an already onscreen button. The anchor should be 363 // Show the menu for an already onscreen button. The anchor should be
341 // overridden so that no scrolling happens. 364 // overridden so that no scrolling happens.
342 document.body.scrollLeft = 0; 365 test('onscreen forces anchor change', function() {
343 document.body.scrollTop = 0; 366 var rect = dots.getBoundingClientRect();
367 document.body.scrollLeft = rect.right - document.body.clientWidth + 10;
368 document.body.scrollTop = rect.bottom - document.body.clientHeight + 10;
344 369
345 var rect = dots.getBoundingClientRect(); 370 menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START});
346 document.body.scrollLeft = rect.right - document.body.clientWidth; 371 var buttonWidth = dots.offsetWidth;
347 document.body.scrollTop = rect.bottom - document.body.clientHeight; 372 var buttonHeight = dots.offsetHeight;
373 assertEquals(containerLeft - menuWidth + buttonWidth, menu.offsetLeft);
374 assertEquals(containerTop - menuHeight + buttonHeight, menu.offsetTop);
375 menu.close();
376 });
348 377
349 menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START}); 378 test('scroll position maintained for showAtPosition', function() {
350 var menuWidth = menu.offsetWidth; 379 document.body.scrollLeft = 500;
351 var menuHeight = menu.offsetHeight; 380 document.body.scrollTop = 1000;
352 var buttonWidth = dots.offsetWidth; 381 menu.showAtPosition({top: 50, left: 50});
353 var buttonHeight = dots.offsetHeight; 382 assertEquals(550, menu.offsetLeft);
354 assertEquals(containerLeft - menuWidth + buttonWidth, menu.offsetLeft); 383 assertEquals(1050, menu.offsetTop);
355 assertEquals(containerTop - menuHeight + buttonHeight, menu.offsetTop); 384 menu.close();
385 });
386
387 test('rtl', function() {
388 // Anchor to an item in RTL.
389 document.body.style.direction = 'rtl';
390 menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START});
391 assertEquals(
392 container.offsetLeft + containerWidth - menuWidth,
393 menu.offsetLeft);
394 assertEquals(containerTop, menu.offsetTop);
395 menu.close();
396 });
356 }); 397 });
357 }); 398 });
OLDNEW
« no previous file with comments | « no previous file | ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698