browser_tabdetach.js (3932B)
1 "use strict"; 2 3 /** 4 * WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This 5 * list should slowly go away as we improve the performance of the front-end. 6 * Instead of adding more reflows to the list, you should be modifying your code 7 * to avoid the reflow. 8 * 9 * See https://firefox-source-docs.mozilla.org/performance/bestpractices.html 10 * for tips on how to do that. 11 */ 12 const EXPECTED_REFLOWS = [ 13 { 14 stack: [ 15 "clientPos@chrome://browser/content/tabbrowser/drag-and-drop.js", 16 "startTabDrag@chrome://browser/content/tabbrowser/drag-and-drop.js", 17 "handle_dragstart@chrome://browser/content/tabbrowser/drag-and-drop.js", 18 "on_dragstart@chrome://browser/content/tabbrowser/tabs.js", 19 "handleEvent@chrome://browser/content/tabbrowser/tabs.js", 20 "synthesizeMouseAtPoint@chrome://mochikit/content/tests/SimpleTest/EventUtils.js", 21 "synthesizeMouse@chrome://mochikit/content/tests/SimpleTest/EventUtils.js", 22 "synthesizePlainDragAndDrop@chrome://mochikit/content/tests/SimpleTest/EventUtils.js", 23 ], 24 maxCount: 2, 25 }, 26 27 { 28 stack: [ 29 "get scrollPosition@chrome://global/content/elements/arrowscrollbox.js", 30 "startTabDrag@chrome://browser/content/tabbrowser/drag-and-drop.js", 31 "handle_dragstart@chrome://browser/content/tabbrowser/drag-and-drop.js", 32 "on_dragstart@chrome://browser/content/tabbrowser/tabs.js", 33 "handleEvent@chrome://browser/content/tabbrowser/tabs.js", 34 "synthesizeMouseAtPoint@chrome://mochikit/content/tests/SimpleTest/EventUtils.js", 35 "synthesizeMouse@chrome://mochikit/content/tests/SimpleTest/EventUtils.js", 36 "synthesizePlainDragAndDrop@chrome://mochikit/content/tests/SimpleTest/EventUtils.js", 37 ], 38 }, 39 ]; 40 41 /** 42 * This test ensures that there are no unexpected uninterruptible reflows when 43 * detaching a tab via drag and drop. The first testcase tests a non-overflowed 44 * tab strip, and the second tests an overflowed one. 45 */ 46 47 add_task(async function test_detach_not_overflowed() { 48 await ensureNoPreloadedBrowser(); 49 await createTabs(1); 50 51 // Make sure we didn't overflow, as expected 52 await TestUtils.waitForCondition(() => { 53 return !gBrowser.tabContainer.overflowing; 54 }); 55 56 let win; 57 await withPerfObserver( 58 async function () { 59 win = await detachTab(gBrowser.tabs[1]); 60 }, 61 { 62 expectedReflows: EXPECTED_REFLOWS, 63 // we are opening a whole new window, so there's no point in tracking 64 // rects being painted 65 frames: { filter: () => [] }, 66 } 67 ); 68 69 await BrowserTestUtils.closeWindow(win); 70 win = null; 71 }); 72 73 add_task(async function test_detach_overflowed() { 74 const TAB_COUNT_FOR_OVERFLOW = computeMaxTabCount(); 75 await createTabs(TAB_COUNT_FOR_OVERFLOW + 1); 76 77 // Make sure we overflowed, as expected 78 await TestUtils.waitForCondition(() => { 79 return gBrowser.tabContainer.overflowing; 80 }); 81 82 let win; 83 await withPerfObserver( 84 async function () { 85 win = await detachTab( 86 gBrowser.tabs[Math.floor(TAB_COUNT_FOR_OVERFLOW / 2)] 87 ); 88 }, 89 { 90 expectedReflows: EXPECTED_REFLOWS, 91 // we are opening a whole new window, so there's no point in tracking 92 // rects being painted 93 frames: { filter: () => [] }, 94 } 95 ); 96 97 await BrowserTestUtils.closeWindow(win); 98 win = null; 99 100 await removeAllButFirstTab(); 101 }); 102 103 async function detachTab(tab) { 104 let newWindowPromise = BrowserTestUtils.waitForNewWindow(); 105 106 await EventUtils.synthesizePlainDragAndDrop({ 107 srcElement: tab, 108 109 // destElement is null because tab detaching happens due 110 // to a drag'n'drop on an invalid drop target. 111 destElement: null, 112 113 // don't move horizontally because that could cause a tab move 114 // animation, and there's code to prevent a tab detaching if 115 // the dragged tab is released while the animation is running. 116 stepX: 0, 117 stepY: 100, 118 }); 119 120 return newWindowPromise; 121 }