summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/performance/browser_tabdetach.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/base/content/test/performance/browser_tabdetach.js')
-rw-r--r--browser/base/content/test/performance/browser_tabdetach.js118
1 files changed, 118 insertions, 0 deletions
diff --git a/browser/base/content/test/performance/browser_tabdetach.js b/browser/base/content/test/performance/browser_tabdetach.js
new file mode 100644
index 0000000000..a860362f1f
--- /dev/null
+++ b/browser/base/content/test/performance/browser_tabdetach.js
@@ -0,0 +1,118 @@
+"use strict";
+
+/**
+ * WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
+ * list should slowly go away as we improve the performance of the front-end.
+ * Instead of adding more reflows to the list, you should be modifying your code
+ * to avoid the reflow.
+ *
+ * See https://firefox-source-docs.mozilla.org/performance/bestpractices.html
+ * for tips on how to do that.
+ */
+const EXPECTED_REFLOWS = [
+ {
+ stack: [
+ "clientX@chrome://browser/content/tabbrowser-tabs.js",
+ "startTabDrag@chrome://browser/content/tabbrowser-tabs.js",
+ "on_dragstart@chrome://browser/content/tabbrowser-tabs.js",
+ "handleEvent@chrome://browser/content/tabbrowser-tabs.js",
+ "synthesizeMouseAtPoint@chrome://mochikit/content/tests/SimpleTest/EventUtils.js",
+ "synthesizeMouse@chrome://mochikit/content/tests/SimpleTest/EventUtils.js",
+ "synthesizePlainDragAndDrop@chrome://mochikit/content/tests/SimpleTest/EventUtils.js",
+ ],
+ maxCount: 2,
+ },
+
+ {
+ stack: [
+ "startTabDrag@chrome://browser/content/tabbrowser-tabs.js",
+ "on_dragstart@chrome://browser/content/tabbrowser-tabs.js",
+ "handleEvent@chrome://browser/content/tabbrowser-tabs.js",
+ "synthesizeMouseAtPoint@chrome://mochikit/content/tests/SimpleTest/EventUtils.js",
+ "synthesizeMouse@chrome://mochikit/content/tests/SimpleTest/EventUtils.js",
+ "synthesizePlainDragAndDrop@chrome://mochikit/content/tests/SimpleTest/EventUtils.js",
+ ],
+ },
+];
+
+/**
+ * This test ensures that there are no unexpected uninterruptible reflows when
+ * detaching a tab via drag and drop. The first testcase tests a non-overflowed
+ * tab strip, and the second tests an overflowed one.
+ */
+
+add_task(async function test_detach_not_overflowed() {
+ await ensureNoPreloadedBrowser();
+ await createTabs(1);
+
+ // Make sure we didn't overflow, as expected
+ await TestUtils.waitForCondition(() => {
+ return !gBrowser.tabContainer.hasAttribute("overflow");
+ });
+
+ let win;
+ await withPerfObserver(
+ async function () {
+ win = await detachTab(gBrowser.tabs[1]);
+ },
+ {
+ expectedReflows: EXPECTED_REFLOWS,
+ // we are opening a whole new window, so there's no point in tracking
+ // rects being painted
+ frames: { filter: rects => [] },
+ }
+ );
+
+ await BrowserTestUtils.closeWindow(win);
+ win = null;
+});
+
+add_task(async function test_detach_overflowed() {
+ const TAB_COUNT_FOR_OVERFLOW = computeMaxTabCount();
+ await createTabs(TAB_COUNT_FOR_OVERFLOW + 1);
+
+ // Make sure we overflowed, as expected
+ await TestUtils.waitForCondition(() => {
+ return gBrowser.tabContainer.hasAttribute("overflow");
+ });
+
+ let win;
+ await withPerfObserver(
+ async function () {
+ win = await detachTab(
+ gBrowser.tabs[Math.floor(TAB_COUNT_FOR_OVERFLOW / 2)]
+ );
+ },
+ {
+ expectedReflows: EXPECTED_REFLOWS,
+ // we are opening a whole new window, so there's no point in tracking
+ // rects being painted
+ frames: { filter: rects => [] },
+ }
+ );
+
+ await BrowserTestUtils.closeWindow(win);
+ win = null;
+
+ await removeAllButFirstTab();
+});
+
+async function detachTab(tab) {
+ let newWindowPromise = BrowserTestUtils.waitForNewWindow();
+
+ await EventUtils.synthesizePlainDragAndDrop({
+ srcElement: tab,
+
+ // destElement is null because tab detaching happens due
+ // to a drag'n'drop on an invalid drop target.
+ destElement: null,
+
+ // don't move horizontally because that could cause a tab move
+ // animation, and there's code to prevent a tab detaching if
+ // the dragged tab is released while the animation is running.
+ stepX: 0,
+ stepY: 100,
+ });
+
+ return newWindowPromise;
+}