// Test for bug 343515 - Need API for tabbrowsers to tell docshells they're visible/hidden // Globals var testPath = "http://mochi.test:8888/browser/docshell/test/navigation/"; var ctx = {}; // We need to wait until the page from each testcase is fully loaded, // including all of its descendant iframes. To do that we manually count // how many load events should happen on that page (one for the toplevel doc // and one for each subframe) and wait until we receive the expected number // of events. function nShotsListener(aElem, aType, aCallback, aCount) { let count = aCount; aElem.addEventListener(aType, function listenerCallback() { if (--count == 0) { aElem.removeEventListener(aType, listenerCallback, true); // aCallback is executed asynchronously, which is handy because load // events fire before mIsDocumentLoaded is actually set to true. :( executeSoon(aCallback); } }, true); } function oneShotListener(aElem, aType, aCallback) { nShotsListener(aElem, aType, aCallback, 1); } function waitForPageshow(aBrowser, callback) { return ContentTask.spawn(aBrowser, null, function* () { yield ContentTaskUtils.waitForEvent(this, "pageshow"); }).then(callback); } // Entry point from Mochikit function test() { // Lots of callbacks going on here waitForExplicitFinish(); // Begin the test step1(); } function step1() { // Get a handle on the initial tab ctx.tab0 = gBrowser.selectedTab; ctx.tab0Browser = gBrowser.getBrowserForTab(ctx.tab0); // Our current tab should be active ok(ctx.tab0Browser.docShellIsActive, "Tab 0 should be active at test start"); // Open a New Tab ctx.tab1 = gBrowser.addTab(testPath + "bug343515_pg1.html"); ctx.tab1Browser = gBrowser.getBrowserForTab(ctx.tab1); oneShotListener(ctx.tab1Browser, "load", step2); } function step2() { is(testPath + "bug343515_pg1.html", ctx.tab1Browser.currentURI.spec, "Got expected tab 1 url in step 2"); // Our current tab should still be active ok(ctx.tab0Browser.docShellIsActive, "Tab 0 should still be active"); ok(!ctx.tab1Browser.docShellIsActive, "Tab 1 should not be active"); // Switch to tab 1 BrowserTestUtils.switchTab(gBrowser, ctx.tab1).then(() => { // Tab 1 should now be active ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive"); ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active"); // Open another tab ctx.tab2 = gBrowser.addTab(testPath + "bug343515_pg2.html"); ctx.tab2Browser = gBrowser.getBrowserForTab(ctx.tab2); // bug343515_pg2.html consists of a page with two iframes, // which will therefore generate 3 load events. nShotsListener(ctx.tab2Browser, "load", step3, 3); }); } function step3() { is(testPath + "bug343515_pg2.html", ctx.tab2Browser.currentURI.spec, "Got expected tab 2 url in step 3"); // Tab 0 should be inactive, Tab 1 should be active ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive"); ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active"); // Tab 2's window _and_ its iframes should be inactive ok(!ctx.tab2Browser.docShellIsActive, "Tab 2 should be inactive"); ContentTask.spawn(ctx.tab2Browser, null, function* () { Assert.equal(content.frames.length, 2, "Tab 2 should have 2 iframes"); for (var i = 0; i < content.frames.length; i++) { info("step 3, frame " + i + " info: " + content.frames[i].location); let docshell = content.frames[i].QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell); Assert.ok(!docShell.isActive, `Tab2 iframe ${i} should be inactive`); } }).then(() => { // Navigate tab 2 to a different page ctx.tab2Browser.loadURI(testPath + "bug343515_pg3.html"); // bug343515_pg3.html consists of a page with two iframes, one of which // contains another iframe, so there'll be a total of 4 load events nShotsListener(ctx.tab2Browser, "load", step4, 4); }); } function step4() { function checkTab2Active(expected) { return ContentTask.spawn(ctx.tab2Browser, expected, function* (expected) { function isActive(aWindow) { var docshell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell); return docshell.isActive; } let active = expected ? "active" : "inactive"; Assert.equal(content.frames.length, 2, "Tab 2 should have 2 iframes"); for (var i = 0; i < content.frames.length; i++) info("step 4, frame " + i + " info: " + content.frames[i].location); Assert.equal(content.frames[0].frames.length, 1, "Tab 2 iframe 0 should have 1 iframes"); Assert.equal(isActive(content.frames[0]), expected, `Tab2 iframe 0 should be ${active}`); Assert.equal(isActive(content.frames[0].frames[0]), expected, `Tab2 iframe 0 subiframe 0 should be ${active}`); Assert.equal(isActive(content.frames[1]), expected, `Tab2 iframe 1 should be ${active}`); }); } is(testPath + "bug343515_pg3.html", ctx.tab2Browser.currentURI.spec, "Got expected tab 2 url in step 4"); // Tab 0 should be inactive, Tab 1 should be active ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive"); ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active"); // Tab2 and all descendants should be inactive checkTab2Active(false).then(() => { // Switch to Tab 2 return BrowserTestUtils.switchTab(gBrowser, ctx.tab2); }).then(() => { // Check everything ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive"); ok(!ctx.tab1Browser.docShellIsActive, "Tab 1 should be inactive"); ok(ctx.tab2Browser.docShellIsActive, "Tab 2 should be active"); return checkTab2Active(true); }).then(() => { // Go back waitForPageshow(ctx.tab2Browser, step5); ctx.tab2Browser.goBack(); }); } function step5() { // Check everything ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive"); ok(!ctx.tab1Browser.docShellIsActive, "Tab 1 should be inactive"); ok(ctx.tab2Browser.docShellIsActive, "Tab 2 should be active"); ContentTask.spawn(ctx.tab2Browser, null, function* () { for (var i = 0; i < content.frames.length; i++) { let docshell = content.frames[i].QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell); Assert.ok(docShell.isActive, `Tab2 iframe ${i} should be active`); } }).then(() => { // Switch to tab 1 return BrowserTestUtils.switchTab(gBrowser, ctx.tab1); }).then(() => { // Navigate to page 3 ctx.tab1Browser.loadURI(testPath + "bug343515_pg3.html"); // bug343515_pg3.html consists of a page with two iframes, one of which // contains another iframe, so there'll be a total of 4 load events nShotsListener(ctx.tab1Browser, "load", step6, 4); }); } function step6() { // Check everything ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive"); ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active"); ContentTask.spawn(ctx.tab1Browser, null, function* () { function isActive(aWindow) { var docshell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell); return docshell.isActive; } Assert.ok(isActive(content.frames[0]), "Tab1 iframe 0 should be active"); Assert.ok(isActive(content.frames[0].frames[0]), "Tab1 iframe 0 subiframe 0 should be active"); Assert.ok(isActive(content.frames[1]), "Tab1 iframe 1 should be active"); }).then(() => { ok(!ctx.tab2Browser.docShellIsActive, "Tab 2 should be inactive"); return ContentTask.spawn(ctx.tab2Browser, null, function* () { for (var i = 0; i < content.frames.length; i++) { let docshell = content.frames[i].QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell); Assert.ok(!docShell.isActive, `Tab2 iframe ${i} should be inactive`); } }); }).then(() => { // Go forward on tab 2 waitForPageshow(ctx.tab2Browser, step7); ctx.tab2Browser.goForward(); }); } function step7() { function checkBrowser(browser, tabNum, active) { return ContentTask.spawn(browser, { tabNum, active }, function* ({ tabNum, active }) { function isActive(aWindow) { var docshell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell); return docshell.isActive; } let activestr = active ? "active" : "inactive"; Assert.equal(isActive(content.frames[0]), active, `Tab${tabNum} iframe 0 should be ${activestr}`); Assert.equal(isActive(content.frames[0].frames[0]), active, `Tab${tabNum} iframe 0 subiframe 0 should be ${activestr}`); Assert.equal(isActive(content.frames[1]), active, `Tab${tabNum} iframe 1 should be ${activestr}`); }); } // Check everything ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive"); ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active"); checkBrowser(ctx.tab1Browser, 1, true).then(() => { ok(!ctx.tab2Browser.docShellIsActive, "Tab 2 should be inactive"); return checkBrowser(ctx.tab2Browser, 2, false); }).then(() => { // That's probably enough allDone(); }); } function allDone() { // Close the tabs we made gBrowser.removeTab(ctx.tab1); gBrowser.removeTab(ctx.tab2); // Tell the framework we're done finish(); }