mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-10-31 16:28:05 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			811 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			811 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
|  * This test checks that focus is adjusted properly when switching tabs.
 | |
|  */
 | |
| 
 | |
| var testPage1 =
 | |
|   "<html id='html1'><body id='body1'><button id='button1'>Tab 1</button></body></html>";
 | |
| var testPage2 =
 | |
|   "<html id='html2'><body id='body2'><button id='button2'>Tab 2</button></body></html>";
 | |
| var testPage3 =
 | |
|   "<html id='html3'><body id='body3'><button id='button3'>Tab 3</button></body></html>";
 | |
| 
 | |
| const fm = Services.focus;
 | |
| 
 | |
| function EventStore() {
 | |
|   this["main-window"] = [];
 | |
|   this.window1 = [];
 | |
|   this.window2 = [];
 | |
| }
 | |
| 
 | |
| EventStore.prototype = {
 | |
|   push(event) {
 | |
|     if (event.includes("browser1") || event.includes("browser2")) {
 | |
|       this["main-window"].push(event);
 | |
|     } else if (event.includes("1")) {
 | |
|       this.window1.push(event);
 | |
|     } else if (event.includes("2")) {
 | |
|       this.window2.push(event);
 | |
|     } else {
 | |
|       this["main-window"].push(event);
 | |
|     }
 | |
|   },
 | |
| };
 | |
| 
 | |
| var tab1 = null;
 | |
| var tab2 = null;
 | |
| var browser1 = null;
 | |
| var browser2 = null;
 | |
| var _lastfocus;
 | |
| var _lastfocuswindow = null;
 | |
| var actualEvents = new EventStore();
 | |
| var expectedEvents = new EventStore();
 | |
| var currentTestName = "";
 | |
| var _expectedElement = null;
 | |
| var _expectedWindow = null;
 | |
| 
 | |
| var currentPromiseResolver = null;
 | |
| 
 | |
| function getFocusedElementForBrowser(browser, dontCheckExtraFocus = false) {
 | |
|   return SpecialPowers.spawn(
 | |
|     browser,
 | |
|     [dontCheckExtraFocus],
 | |
|     dontCheckExtraFocusChild => {
 | |
|       let focusedWindow = {};
 | |
|       let node = Services.focus.getFocusedElementForWindow(
 | |
|         content,
 | |
|         false,
 | |
|         focusedWindow
 | |
|       );
 | |
|       let details = "Focus is " + (node ? node.id : "<none>");
 | |
| 
 | |
|       /* Check focus manager properties. Add an error onto the string if they are
 | |
|        not what is expected which will cause matching to fail in the parent process. */
 | |
|       let doc = content.document;
 | |
|       if (!dontCheckExtraFocusChild) {
 | |
|         if (Services.focus.focusedElement != node) {
 | |
|           details += "<ERROR: focusedElement doesn't match>";
 | |
|         }
 | |
|         if (
 | |
|           Services.focus.focusedWindow &&
 | |
|           Services.focus.focusedWindow != content
 | |
|         ) {
 | |
|           details += "<ERROR: focusedWindow doesn't match>";
 | |
|         }
 | |
|         if ((Services.focus.focusedWindow == content) != doc.hasFocus()) {
 | |
|           details += "<ERROR: child hasFocus() is not correct>";
 | |
|         }
 | |
|         if (
 | |
|           (Services.focus.focusedElement &&
 | |
|             doc.activeElement != Services.focus.focusedElement) ||
 | |
|           (!Services.focus.focusedElement && doc.activeElement != doc.body)
 | |
|         ) {
 | |
|           details += "<ERROR: child activeElement is not correct>";
 | |
|         }
 | |
|       }
 | |
|       return details;
 | |
|     }
 | |
|   );
 | |
| }
 | |
| 
 | |
| function focusInChild(event) {
 | |
|   function getWindowDocId(target) {
 | |
|     return String(target.location).includes("1") ? "window1" : "window2";
 | |
|   }
 | |
| 
 | |
|   // Stop the shim code from seeing this event process.
 | |
|   event.stopImmediatePropagation();
 | |
| 
 | |
|   var id;
 | |
|   if (event.target instanceof Ci.nsIDOMWindow) {
 | |
|     id = getWindowDocId(event.originalTarget) + "-window";
 | |
|   } else if (event.target.nodeType == event.target.DOCUMENT_NODE) {
 | |
|     id = getWindowDocId(event.originalTarget) + "-document";
 | |
|   } else {
 | |
|     id = event.originalTarget.id;
 | |
|   }
 | |
| 
 | |
|   let window = event.target.ownerGlobal;
 | |
|   if (!window._eventsOccurred) {
 | |
|     window._eventsOccurred = [];
 | |
|   }
 | |
|   window._eventsOccurred.push(event.type + ": " + id);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| function focusElementInChild(elementid, elementtype) {
 | |
|   let browser = elementid.includes("1") ? browser1 : browser2;
 | |
|   return SpecialPowers.spawn(browser, [elementid, elementtype], (id, type) => {
 | |
|     content.document.getElementById(id)[type]();
 | |
|   });
 | |
| }
 | |
| 
 | |
| add_task(async function () {
 | |
|   tab1 = BrowserTestUtils.addTab(gBrowser);
 | |
|   browser1 = gBrowser.getBrowserForTab(tab1);
 | |
| 
 | |
|   tab2 = BrowserTestUtils.addTab(gBrowser);
 | |
|   browser2 = gBrowser.getBrowserForTab(tab2);
 | |
| 
 | |
|   await promiseTabLoadEvent(tab1, "data:text/html," + escape(testPage1));
 | |
|   await promiseTabLoadEvent(tab2, "data:text/html," + escape(testPage2));
 | |
| 
 | |
|   gURLBar.focus();
 | |
|   await SimpleTest.promiseFocus();
 | |
| 
 | |
|   // In these listeners, focusInChild is used to cache details about the event
 | |
|   // on a temporary on the window (window._eventsOccurred), so that it can be
 | |
|   // retrieved later within compareFocusResults. focusInChild always returns true.
 | |
|   // compareFocusResults is called each time event occurs to check that the
 | |
|   // right events happened.
 | |
|   let listenersToRemove = [];
 | |
|   listenersToRemove.push(
 | |
|     BrowserTestUtils.addContentEventListener(
 | |
|       browser1,
 | |
|       "focus",
 | |
|       compareFocusResults,
 | |
|       { capture: true },
 | |
|       focusInChild
 | |
|     )
 | |
|   );
 | |
|   listenersToRemove.push(
 | |
|     BrowserTestUtils.addContentEventListener(
 | |
|       browser1,
 | |
|       "blur",
 | |
|       compareFocusResults,
 | |
|       { capture: true },
 | |
|       focusInChild
 | |
|     )
 | |
|   );
 | |
|   listenersToRemove.push(
 | |
|     BrowserTestUtils.addContentEventListener(
 | |
|       browser2,
 | |
|       "focus",
 | |
|       compareFocusResults,
 | |
|       { capture: true },
 | |
|       focusInChild
 | |
|     )
 | |
|   );
 | |
|   listenersToRemove.push(
 | |
|     BrowserTestUtils.addContentEventListener(
 | |
|       browser2,
 | |
|       "blur",
 | |
|       compareFocusResults,
 | |
|       { capture: true },
 | |
|       focusInChild
 | |
|     )
 | |
|   );
 | |
| 
 | |
|   // Get the content processes to do something, so that we can better
 | |
|   // ensure that the listeners added above will have actually been added
 | |
|   // in the tabs.
 | |
|   await SpecialPowers.spawn(browser1, [], () => {});
 | |
|   await SpecialPowers.spawn(browser2, [], () => {});
 | |
| 
 | |
|   _lastfocus = "urlbar";
 | |
|   _lastfocuswindow = "main-window";
 | |
| 
 | |
|   window.addEventListener("focus", _browser_tabfocus_test_eventOccured, true);
 | |
|   window.addEventListener("blur", _browser_tabfocus_test_eventOccured, true);
 | |
| 
 | |
|   // make sure that the focus initially starts out blank
 | |
|   var focusedWindow = {};
 | |
| 
 | |
|   let focused = await getFocusedElementForBrowser(browser1);
 | |
|   is(focused, "Focus is <none>", "initial focus in tab 1");
 | |
| 
 | |
|   focused = await getFocusedElementForBrowser(browser2);
 | |
|   is(focused, "Focus is <none>", "initial focus in tab 2");
 | |
| 
 | |
|   is(
 | |
|     document.activeElement,
 | |
|     gURLBar.inputField,
 | |
|     "focus after loading two tabs"
 | |
|   );
 | |
| 
 | |
|   await expectFocusShiftAfterTabSwitch(
 | |
|     tab2,
 | |
|     "window2",
 | |
|     null,
 | |
|     true,
 | |
|     "after tab change, focus in new tab"
 | |
|   );
 | |
| 
 | |
|   focused = await getFocusedElementForBrowser(browser2);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is <none>",
 | |
|     "focusedElement after tab change, focus in new tab"
 | |
|   );
 | |
| 
 | |
|   // switching tabs when nothing in the new tab is focused
 | |
|   // should focus the browser
 | |
|   await expectFocusShiftAfterTabSwitch(
 | |
|     tab1,
 | |
|     "window1",
 | |
|     null,
 | |
|     true,
 | |
|     "after tab change, focus in original tab"
 | |
|   );
 | |
| 
 | |
|   focused = await getFocusedElementForBrowser(browser1);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is <none>",
 | |
|     "focusedElement after tab change, focus in original tab"
 | |
|   );
 | |
| 
 | |
|   // focusing a button in the current tab should focus it
 | |
|   await expectFocusShift(
 | |
|     () => focusElementInChild("button1", "focus"),
 | |
|     "window1",
 | |
|     "button1",
 | |
|     true,
 | |
|     "after button focused"
 | |
|   );
 | |
| 
 | |
|   focused = await getFocusedElementForBrowser(browser1);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is button1",
 | |
|     "focusedElement in first browser after button focused"
 | |
|   );
 | |
| 
 | |
|   // focusing a button in a background tab should not change the actual
 | |
|   // focus, but should set the focus that would be in that background tab to
 | |
|   // that button.
 | |
|   await expectFocusShift(
 | |
|     () => focusElementInChild("button2", "focus"),
 | |
|     "window1",
 | |
|     "button1",
 | |
|     false,
 | |
|     "after button focus in unfocused tab"
 | |
|   );
 | |
| 
 | |
|   focused = await getFocusedElementForBrowser(browser1, false);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is button1",
 | |
|     "focusedElement in first browser after button focus in unfocused tab"
 | |
|   );
 | |
|   focused = await getFocusedElementForBrowser(browser2, true);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is button2",
 | |
|     "focusedElement in second browser after button focus in unfocused tab"
 | |
|   );
 | |
| 
 | |
|   // switching tabs should now make the button in the other tab focused
 | |
|   await expectFocusShiftAfterTabSwitch(
 | |
|     tab2,
 | |
|     "window2",
 | |
|     "button2",
 | |
|     true,
 | |
|     "after tab change with button focused"
 | |
|   );
 | |
| 
 | |
|   // blurring an element in a background tab should not change the active
 | |
|   // focus, but should clear the focus in that tab.
 | |
|   await expectFocusShift(
 | |
|     () => focusElementInChild("button1", "blur"),
 | |
|     "window2",
 | |
|     "button2",
 | |
|     false,
 | |
|     "focusedWindow after blur in unfocused tab"
 | |
|   );
 | |
| 
 | |
|   focused = await getFocusedElementForBrowser(browser1, true);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is <none>",
 | |
|     "focusedElement in first browser after focus in unfocused tab"
 | |
|   );
 | |
|   focused = await getFocusedElementForBrowser(browser2, false);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is button2",
 | |
|     "focusedElement in second browser after focus in unfocused tab"
 | |
|   );
 | |
| 
 | |
|   // When focus is in the tab bar, it should be retained there
 | |
|   await expectFocusShift(
 | |
|     () => gBrowser.selectedTab.focus(),
 | |
|     "main-window",
 | |
|     "tab2",
 | |
|     true,
 | |
|     "focusing tab element"
 | |
|   );
 | |
|   await expectFocusShiftAfterTabSwitch(
 | |
|     tab1,
 | |
|     "main-window",
 | |
|     "tab1",
 | |
|     true,
 | |
|     "tab change when selected tab element was focused"
 | |
|   );
 | |
| 
 | |
|   let switchWaiter = new Promise(resolve => {
 | |
|     gBrowser.addEventListener(
 | |
|       "TabSwitchDone",
 | |
|       function () {
 | |
|         executeSoon(resolve);
 | |
|       },
 | |
|       { once: true }
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   await expectFocusShiftAfterTabSwitch(
 | |
|     tab2,
 | |
|     "main-window",
 | |
|     "tab2",
 | |
|     true,
 | |
|     "another tab change when selected tab element was focused"
 | |
|   );
 | |
| 
 | |
|   // Wait for the paint on the second browser so that any post tab-switching
 | |
|   // stuff has time to complete before blurring the tab. Otherwise, the
 | |
|   // _adjustFocusAfterTabSwitch in tabbrowser gets confused and isn't sure
 | |
|   // what tab is really focused.
 | |
|   await switchWaiter;
 | |
| 
 | |
|   await expectFocusShift(
 | |
|     () => gBrowser.selectedTab.blur(),
 | |
|     "main-window",
 | |
|     null,
 | |
|     true,
 | |
|     "blurring tab element"
 | |
|   );
 | |
| 
 | |
|   // focusing the url field should switch active focus away from the browser but
 | |
|   // not clear what would be the focus in the browser
 | |
|   await focusElementInChild("button1", "focus");
 | |
| 
 | |
|   await expectFocusShift(
 | |
|     () => gURLBar.focus(),
 | |
|     "main-window",
 | |
|     "urlbar",
 | |
|     true,
 | |
|     "focusedWindow after url field focused"
 | |
|   );
 | |
|   focused = await getFocusedElementForBrowser(browser1, true);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is button1",
 | |
|     "focusedElement after url field focused, first browser"
 | |
|   );
 | |
|   focused = await getFocusedElementForBrowser(browser2, true);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is button2",
 | |
|     "focusedElement after url field focused, second browser"
 | |
|   );
 | |
| 
 | |
|   await expectFocusShift(
 | |
|     () => gURLBar.blur(),
 | |
|     "main-window",
 | |
|     null,
 | |
|     true,
 | |
|     "blurring url field"
 | |
|   );
 | |
| 
 | |
|   // when a chrome element is focused, switching tabs to a tab with a button
 | |
|   // with the current focus should focus the button
 | |
|   await expectFocusShiftAfterTabSwitch(
 | |
|     tab1,
 | |
|     "window1",
 | |
|     "button1",
 | |
|     true,
 | |
|     "after tab change, focus in url field, button focused in new tab"
 | |
|   );
 | |
| 
 | |
|   focused = await getFocusedElementForBrowser(browser1, false);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is button1",
 | |
|     "after switch tab, focus in unfocused tab, first browser"
 | |
|   );
 | |
|   focused = await getFocusedElementForBrowser(browser2, true);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is button2",
 | |
|     "after switch tab, focus in unfocused tab, second browser"
 | |
|   );
 | |
| 
 | |
|   // blurring an element in the current tab should clear the active focus
 | |
|   await expectFocusShift(
 | |
|     () => focusElementInChild("button1", "blur"),
 | |
|     "window1",
 | |
|     null,
 | |
|     true,
 | |
|     "after blur in focused tab"
 | |
|   );
 | |
| 
 | |
|   focused = await getFocusedElementForBrowser(browser1, false);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is <none>",
 | |
|     "focusedWindow after blur in focused tab, child"
 | |
|   );
 | |
|   focusedWindow = {};
 | |
|   is(
 | |
|     fm.getFocusedElementForWindow(window, false, focusedWindow),
 | |
|     browser1,
 | |
|     "focusedElement after blur in focused tab, parent"
 | |
|   );
 | |
| 
 | |
|   // blurring an non-focused url field should have no effect
 | |
|   await expectFocusShift(
 | |
|     () => gURLBar.blur(),
 | |
|     "window1",
 | |
|     null,
 | |
|     false,
 | |
|     "after blur in unfocused url field"
 | |
|   );
 | |
| 
 | |
|   focusedWindow = {};
 | |
|   is(
 | |
|     fm.getFocusedElementForWindow(window, false, focusedWindow),
 | |
|     browser1,
 | |
|     "focusedElement after blur in unfocused url field"
 | |
|   );
 | |
| 
 | |
|   // switch focus to a tab with a currently focused element
 | |
|   await expectFocusShiftAfterTabSwitch(
 | |
|     tab2,
 | |
|     "window2",
 | |
|     "button2",
 | |
|     true,
 | |
|     "after switch from unfocused to focused tab"
 | |
|   );
 | |
|   focused = await getFocusedElementForBrowser(browser2, true);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is button2",
 | |
|     "focusedElement after switch from unfocused to focused tab"
 | |
|   );
 | |
| 
 | |
|   // clearing focus on the chrome window should switch the focus to the
 | |
|   // chrome window
 | |
|   await expectFocusShift(
 | |
|     () => fm.clearFocus(window),
 | |
|     "main-window",
 | |
|     null,
 | |
|     true,
 | |
|     "after switch to chrome with no focused element"
 | |
|   );
 | |
| 
 | |
|   focusedWindow = {};
 | |
|   is(
 | |
|     fm.getFocusedElementForWindow(window, false, focusedWindow),
 | |
|     null,
 | |
|     "focusedElement after switch to chrome with no focused element"
 | |
|   );
 | |
| 
 | |
|   // switch focus to another tab when neither have an active focus
 | |
|   await expectFocusShiftAfterTabSwitch(
 | |
|     tab1,
 | |
|     "window1",
 | |
|     null,
 | |
|     true,
 | |
|     "focusedWindow after tab switch from no focus to no focus"
 | |
|   );
 | |
| 
 | |
|   focused = await getFocusedElementForBrowser(browser1, false);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is <none>",
 | |
|     "after tab switch from no focus to no focus, first browser"
 | |
|   );
 | |
|   focused = await getFocusedElementForBrowser(browser2, true);
 | |
|   is(
 | |
|     focused,
 | |
|     "Focus is button2",
 | |
|     "after tab switch from no focus to no focus, second browser"
 | |
|   );
 | |
| 
 | |
|   // next, check whether navigating forward, focusing the urlbar and then
 | |
|   // navigating back maintains the focus in the urlbar.
 | |
|   await expectFocusShift(
 | |
|     () => focusElementInChild("button1", "focus"),
 | |
|     "window1",
 | |
|     "button1",
 | |
|     true,
 | |
|     "focus button"
 | |
|   );
 | |
| 
 | |
|   await promiseTabLoadEvent(tab1, "data:text/html," + escape(testPage3));
 | |
| 
 | |
|   // now go back again
 | |
|   gURLBar.focus();
 | |
| 
 | |
|   await new Promise(resolve => {
 | |
|     BrowserTestUtils.waitForContentEvent(
 | |
|       window.gBrowser.selectedBrowser,
 | |
|       "pageshow",
 | |
|       true
 | |
|     ).then(() => resolve());
 | |
|     document.getElementById("Browser:Back").doCommand();
 | |
|   });
 | |
| 
 | |
|   is(
 | |
|     window.document.activeElement,
 | |
|     gURLBar.inputField,
 | |
|     "urlbar still focused after navigating back"
 | |
|   );
 | |
| 
 | |
|   for (let listener of listenersToRemove) {
 | |
|     listener();
 | |
|   }
 | |
| 
 | |
|   window.removeEventListener(
 | |
|     "focus",
 | |
|     _browser_tabfocus_test_eventOccured,
 | |
|     true
 | |
|   );
 | |
|   window.removeEventListener("blur", _browser_tabfocus_test_eventOccured, true);
 | |
| 
 | |
|   gBrowser.removeCurrentTab();
 | |
|   gBrowser.removeCurrentTab();
 | |
| 
 | |
|   finish();
 | |
| });
 | |
| 
 | |
| function _browser_tabfocus_test_eventOccured(event) {
 | |
|   function getWindowDocId(target) {
 | |
|     if (
 | |
|       target == browser1.contentWindow ||
 | |
|       target == browser1.contentDocument
 | |
|     ) {
 | |
|       return "window1";
 | |
|     }
 | |
|     if (
 | |
|       target == browser2.contentWindow ||
 | |
|       target == browser2.contentDocument
 | |
|     ) {
 | |
|       return "window2";
 | |
|     }
 | |
|     return "main-window";
 | |
|   }
 | |
| 
 | |
|   var id;
 | |
| 
 | |
|   if (Window.isInstance(event.target)) {
 | |
|     id = getWindowDocId(event.originalTarget) + "-window";
 | |
|   } else if (Document.isInstance(event.target)) {
 | |
|     id = getWindowDocId(event.originalTarget) + "-document";
 | |
|   } else if (
 | |
|     event.target.id == "urlbar" &&
 | |
|     event.originalTarget.localName == "input"
 | |
|   ) {
 | |
|     id = "urlbar";
 | |
|   } else if (event.originalTarget.localName == "browser") {
 | |
|     id = event.originalTarget == browser1 ? "browser1" : "browser2";
 | |
|   } else if (event.originalTarget.localName == "tab") {
 | |
|     id = event.originalTarget == tab1 ? "tab1" : "tab2";
 | |
|   } else {
 | |
|     id = event.originalTarget.id;
 | |
|   }
 | |
| 
 | |
|   actualEvents.push(event.type + ": " + id);
 | |
|   compareFocusResults();
 | |
| }
 | |
| 
 | |
| function getId(element) {
 | |
|   if (!element) {
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   if (element.localName == "browser") {
 | |
|     return element == browser1 ? "browser1" : "browser2";
 | |
|   }
 | |
| 
 | |
|   if (element.localName == "tab") {
 | |
|     return element == tab1 ? "tab1" : "tab2";
 | |
|   }
 | |
| 
 | |
|   return element.localName == "input" ? "urlbar" : element.id;
 | |
| }
 | |
| 
 | |
| async function compareFocusResults() {
 | |
|   if (!currentPromiseResolver) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // Get the events that occurred in each child browser and store them
 | |
|   // in 'actualEvents'. This is a global so if different calls to
 | |
|   // compareFocusResults occur together, whichever one happens to get
 | |
|   // called first after pulling all the events from the child will
 | |
|   // perform the matching.
 | |
|   let events = await SpecialPowers.spawn(browser1, [], () => {
 | |
|     let eventsOccurred = content._eventsOccurred;
 | |
|     content._eventsOccurred = [];
 | |
|     return eventsOccurred || [];
 | |
|   });
 | |
|   actualEvents.window1.push(...events);
 | |
| 
 | |
|   events = await SpecialPowers.spawn(browser2, [], () => {
 | |
|     let eventsOccurred = content._eventsOccurred;
 | |
|     content._eventsOccurred = [];
 | |
|     return eventsOccurred || [];
 | |
|   });
 | |
|   actualEvents.window2.push(...events);
 | |
| 
 | |
|   // Another call to compareFocusResults may have happened in the meantime.
 | |
|   // If currentPromiseResolver is null, then that call was successful so no
 | |
|   // need to check the events again.
 | |
|   if (!currentPromiseResolver) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   let winIds = ["main-window", "window1", "window2"];
 | |
| 
 | |
|   for (let winId of winIds) {
 | |
|     if (actualEvents[winId].length < expectedEvents[winId].length) {
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (let winId of winIds) {
 | |
|     for (let e = 0; e < expectedEvents.length; e++) {
 | |
|       is(
 | |
|         actualEvents[winId][e],
 | |
|         expectedEvents[winId][e],
 | |
|         currentTestName + " events [event " + e + "]"
 | |
|       );
 | |
|     }
 | |
|     actualEvents[winId] = [];
 | |
|   }
 | |
| 
 | |
|   let matchWindow = window;
 | |
|   is(_expectedWindow, "main-window", "main-window is always expected");
 | |
|   if (_expectedWindow == "main-window") {
 | |
|     // The browser window's body doesn't have an id set usually - set one now
 | |
|     // so it can be used for id comparisons below.
 | |
|     matchWindow.document.body.id = "main-window-body";
 | |
|   }
 | |
| 
 | |
|   var focusedElement = fm.focusedElement;
 | |
|   is(
 | |
|     getId(focusedElement),
 | |
|     _expectedElement,
 | |
|     currentTestName + " focusedElement"
 | |
|   );
 | |
| 
 | |
|   is(fm.focusedWindow, matchWindow, currentTestName + " focusedWindow");
 | |
|   var focusedWindow = {};
 | |
|   is(
 | |
|     getId(fm.getFocusedElementForWindow(matchWindow, false, focusedWindow)),
 | |
|     _expectedElement,
 | |
|     currentTestName + " getFocusedElementForWindow"
 | |
|   );
 | |
|   is(
 | |
|     focusedWindow.value,
 | |
|     matchWindow,
 | |
|     currentTestName + " getFocusedElementForWindow frame"
 | |
|   );
 | |
|   is(matchWindow.document.hasFocus(), true, currentTestName + " hasFocus");
 | |
|   var expectedActive = _expectedElement;
 | |
|   if (!expectedActive) {
 | |
|     expectedActive = getId(matchWindow.document.body);
 | |
|   }
 | |
|   is(
 | |
|     getId(matchWindow.document.activeElement),
 | |
|     expectedActive,
 | |
|     currentTestName + " activeElement"
 | |
|   );
 | |
| 
 | |
|   currentPromiseResolver();
 | |
|   currentPromiseResolver = null;
 | |
| }
 | |
| 
 | |
| async function expectFocusShiftAfterTabSwitch(
 | |
|   tab,
 | |
|   expectedWindow,
 | |
|   expectedElement,
 | |
|   focusChanged,
 | |
|   testid
 | |
| ) {
 | |
|   let tabSwitchPromise = null;
 | |
|   await expectFocusShift(
 | |
|     () => {
 | |
|       tabSwitchPromise = BrowserTestUtils.switchTab(gBrowser, tab);
 | |
|     },
 | |
|     expectedWindow,
 | |
|     expectedElement,
 | |
|     focusChanged,
 | |
|     testid
 | |
|   );
 | |
|   await tabSwitchPromise;
 | |
| }
 | |
| 
 | |
| async function expectFocusShift(
 | |
|   callback,
 | |
|   expectedWindow,
 | |
|   expectedElement,
 | |
|   focusChanged,
 | |
|   testid
 | |
| ) {
 | |
|   currentPromiseResolver = null;
 | |
|   currentTestName = testid;
 | |
| 
 | |
|   expectedEvents = new EventStore();
 | |
| 
 | |
|   if (focusChanged) {
 | |
|     _expectedElement = expectedElement;
 | |
|     _expectedWindow = expectedWindow;
 | |
| 
 | |
|     // When the content is in a child process, the expected element in the chrome window
 | |
|     // will always be the urlbar or a browser element.
 | |
|     if (_expectedWindow == "window1") {
 | |
|       _expectedElement = "browser1";
 | |
|     } else if (_expectedWindow == "window2") {
 | |
|       _expectedElement = "browser2";
 | |
|     }
 | |
|     _expectedWindow = "main-window";
 | |
| 
 | |
|     if (
 | |
|       _lastfocuswindow != "main-window" &&
 | |
|       _lastfocuswindow != expectedWindow
 | |
|     ) {
 | |
|       let browserid = _lastfocuswindow == "window1" ? "browser1" : "browser2";
 | |
|       expectedEvents.push("blur: " + browserid);
 | |
|     }
 | |
| 
 | |
|     var newElementIsFocused =
 | |
|       expectedElement && !expectedElement.startsWith("html");
 | |
|     if (
 | |
|       newElementIsFocused &&
 | |
|       _lastfocuswindow != "main-window" &&
 | |
|       expectedWindow == "main-window"
 | |
|     ) {
 | |
|       // When switching from a child to a chrome element, the focus on the element will arrive first.
 | |
|       expectedEvents.push("focus: " + expectedElement);
 | |
|       newElementIsFocused = false;
 | |
|     }
 | |
| 
 | |
|     if (_lastfocus && _lastfocus != _expectedElement) {
 | |
|       expectedEvents.push("blur: " + _lastfocus);
 | |
|     }
 | |
| 
 | |
|     if (_lastfocuswindow && _lastfocuswindow != expectedWindow) {
 | |
|       if (_lastfocuswindow != "main-window") {
 | |
|         expectedEvents.push("blur: " + _lastfocuswindow + "-document");
 | |
|         expectedEvents.push("blur: " + _lastfocuswindow + "-window");
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (expectedWindow && _lastfocuswindow != expectedWindow) {
 | |
|       if (expectedWindow != "main-window") {
 | |
|         let browserid = expectedWindow == "window1" ? "browser1" : "browser2";
 | |
|         expectedEvents.push("focus: " + browserid);
 | |
|       }
 | |
| 
 | |
|       if (expectedWindow != "main-window") {
 | |
|         expectedEvents.push("focus: " + expectedWindow + "-document");
 | |
|         expectedEvents.push("focus: " + expectedWindow + "-window");
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (newElementIsFocused) {
 | |
|       expectedEvents.push("focus: " + expectedElement);
 | |
|     }
 | |
| 
 | |
|     _lastfocus = expectedElement;
 | |
|     _lastfocuswindow = expectedWindow;
 | |
|   }
 | |
| 
 | |
|   // No events are expected, so return immediately. If events do occur, the following
 | |
|   // tests will fail.
 | |
|   if (
 | |
|     expectedEvents["main-window"].length +
 | |
|       expectedEvents.window1.length +
 | |
|       expectedEvents.window2.length ==
 | |
|     0
 | |
|   ) {
 | |
|     await callback();
 | |
|     return undefined;
 | |
|   }
 | |
| 
 | |
|   return new Promise(resolve => {
 | |
|     currentPromiseResolver = resolve;
 | |
|     callback();
 | |
|   });
 | |
| }
 | 
