mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			324 lines
		
	
	
	
		
			9.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			324 lines
		
	
	
	
		
			9.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* Any copyright is dedicated to the Public Domain.
 | 
						|
   http://creativecommons.org/publicdomain/zero/1.0/ */
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
const REMOTE_URL = "https://www.example.com/";
 | 
						|
const ABOUT_ROBOTS_URL = "about:robots";
 | 
						|
const NO_TITLE_URL = "data:text/plain,foo";
 | 
						|
 | 
						|
const BACKUP_STATE = SessionStore.getBrowserState();
 | 
						|
registerCleanupFunction(() => promiseBrowserState(BACKUP_STATE));
 | 
						|
 | 
						|
add_setup(async function() {
 | 
						|
  await SpecialPowers.pushPrefEnv({
 | 
						|
    set: [
 | 
						|
      ["browser.sessionstore.restore_on_demand", true],
 | 
						|
      ["browser.sessionstore.restore_tabs_lazily", true],
 | 
						|
    ],
 | 
						|
  });
 | 
						|
});
 | 
						|
 | 
						|
/**
 | 
						|
 * When implementing batch insertion of tabs as part of session restore,
 | 
						|
 * we started reversing the insertion order of pinned tabs (bug 1607441).
 | 
						|
 * This test checks we don't regress that again.
 | 
						|
 */
 | 
						|
add_task(async function test_pinned_tabs_order() {
 | 
						|
  // we expect 3 pinned tabs plus the selected tab get content restored.
 | 
						|
  let allTabsRestored = promiseSessionStoreLoads(4);
 | 
						|
  await promiseBrowserState({
 | 
						|
    windows: [
 | 
						|
      {
 | 
						|
        selected: 4, // SessionStore uses 1-based indexing.
 | 
						|
        tabs: [
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: ABOUT_ROBOTS_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: NO_TITLE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          { entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }] },
 | 
						|
          { entries: [{ url: "about:blank", triggeringPrincipal_base64 }] },
 | 
						|
        ],
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  });
 | 
						|
  await allTabsRestored;
 | 
						|
  let [tab1, tab2, tab3, tab4, tab5] = gBrowser.tabs;
 | 
						|
  ok(tab1.pinned, "First tab is pinned");
 | 
						|
  ok(tab2.pinned, "Second tab is pinned");
 | 
						|
  ok(tab3.pinned, "Third tab is pinned");
 | 
						|
  ok(!tab4.pinned, "Fourth tab is not pinned");
 | 
						|
  ok(!tab5.pinned, "Fifth tab is not pinned");
 | 
						|
 | 
						|
  ok(tab4.selected, "Fourth tab is selected");
 | 
						|
  is(
 | 
						|
    tab1.linkedBrowser.currentURI.spec,
 | 
						|
    REMOTE_URL,
 | 
						|
    "First tab has matching URL"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    tab2.linkedBrowser.currentURI.spec,
 | 
						|
    ABOUT_ROBOTS_URL,
 | 
						|
    "Second tab has matching URL"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    tab3.linkedBrowser.currentURI.spec,
 | 
						|
    NO_TITLE_URL,
 | 
						|
    "Third tab has matching URL"
 | 
						|
  );
 | 
						|
  // Clean up for the next task.
 | 
						|
  await promiseBrowserState(BACKUP_STATE);
 | 
						|
});
 | 
						|
 | 
						|
/**
 | 
						|
 * When fixing the previous regression, pinned tabs started disappearing out
 | 
						|
 * of sessions with selected pinned tabs. This test checks that case.
 | 
						|
 */
 | 
						|
add_task(async function test_selected_pinned_tab_dataloss() {
 | 
						|
  // we expect 3 pinned tabs (one of which is selected) get content restored.
 | 
						|
  let allTabsRestored = promiseSessionStoreLoads(3);
 | 
						|
  await promiseBrowserState({
 | 
						|
    windows: [
 | 
						|
      {
 | 
						|
        selected: 1, // SessionStore uses 1-based indexing.
 | 
						|
        tabs: [
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: ABOUT_ROBOTS_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: NO_TITLE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          { entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }] },
 | 
						|
          { entries: [{ url: "about:blank", triggeringPrincipal_base64 }] },
 | 
						|
        ],
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  });
 | 
						|
  await allTabsRestored;
 | 
						|
  let [tab1, tab2, tab3, tab4, tab5] = gBrowser.tabs;
 | 
						|
  ok(tab5, "Should have 5 tabs");
 | 
						|
  ok(tab1.pinned, "First tab is pinned");
 | 
						|
  ok(tab2.pinned, "Second tab is pinned");
 | 
						|
  ok(tab3.pinned, "Third tab is pinned");
 | 
						|
  ok(tab4 && !tab4.pinned, "Fourth tab is not pinned");
 | 
						|
  ok(tab5 && !tab5.pinned, "Fifth tab is not pinned");
 | 
						|
 | 
						|
  ok(tab1 && tab1.selected, "First (pinned) tab is selected");
 | 
						|
  is(
 | 
						|
    tab1.linkedBrowser.currentURI.spec,
 | 
						|
    REMOTE_URL,
 | 
						|
    "First tab has matching URL"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    tab2.linkedBrowser.currentURI.spec,
 | 
						|
    ABOUT_ROBOTS_URL,
 | 
						|
    "Second tab has matching URL"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    tab3.linkedBrowser.currentURI.spec,
 | 
						|
    NO_TITLE_URL,
 | 
						|
    "Third tab has matching URL"
 | 
						|
  );
 | 
						|
  // Clean up for the next task.
 | 
						|
  await promiseBrowserState(BACKUP_STATE);
 | 
						|
});
 | 
						|
 | 
						|
/**
 | 
						|
 * While we're here, it seems useful to have a test for mixed pinned and
 | 
						|
 * unpinned tabs in session store state, as well as userContextId.
 | 
						|
 */
 | 
						|
add_task(async function test_mixed_pinned_unpinned() {
 | 
						|
  // we expect 3 pinned tabs plus the selected tab get content restored.
 | 
						|
  let allTabsRestored = promiseSessionStoreLoads(4);
 | 
						|
  await promiseBrowserState({
 | 
						|
    windows: [
 | 
						|
      {
 | 
						|
        selected: 4, // SessionStore uses 1-based indexing.
 | 
						|
        tabs: [
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          { entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }] },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: ABOUT_ROBOTS_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          { entries: [{ url: "about:blank", triggeringPrincipal_base64 }] },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: NO_TITLE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  });
 | 
						|
  await allTabsRestored;
 | 
						|
  let [tab1, tab2, tab3, tab4, tab5] = gBrowser.tabs;
 | 
						|
  ok(tab1.pinned, "First tab is pinned");
 | 
						|
  ok(tab2.pinned, "Second tab is pinned");
 | 
						|
  ok(tab3.pinned, "Third tab is pinned");
 | 
						|
  ok(!tab4.pinned, "Fourth tab is not pinned");
 | 
						|
  ok(!tab5.pinned, "Fifth tab is not pinned");
 | 
						|
 | 
						|
  // This is confusing to read - the 4th entry in the session data is
 | 
						|
  // selected. But the 5th entry is pinned, so it moves to the start of the
 | 
						|
  // tabstrip, so when we fetch `gBrowser.tabs`, the 4th entry in the list
 | 
						|
  // is actually the 5th tab.
 | 
						|
  ok(tab5.selected, "Fifth tab is selected");
 | 
						|
  is(
 | 
						|
    tab1.linkedBrowser.currentURI.spec,
 | 
						|
    REMOTE_URL,
 | 
						|
    "First tab has matching URL"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    tab2.linkedBrowser.currentURI.spec,
 | 
						|
    ABOUT_ROBOTS_URL,
 | 
						|
    "Second tab has matching URL"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    tab3.linkedBrowser.currentURI.spec,
 | 
						|
    NO_TITLE_URL,
 | 
						|
    "Third tab has matching URL"
 | 
						|
  );
 | 
						|
  // Clean up for the next task.
 | 
						|
  await promiseBrowserState(BACKUP_STATE);
 | 
						|
});
 | 
						|
 | 
						|
/**
 | 
						|
 * After session restore, if we crash an unpinned tab, we noticed pinned tabs
 | 
						|
 * created in the same process would lose all data (Bug 1624511). This test
 | 
						|
 * checks that case.
 | 
						|
 */
 | 
						|
add_task(async function test_pinned_tab_dataloss() {
 | 
						|
  // We do not run if there are no crash reporters to avoid
 | 
						|
  // problems with the intentional crash.
 | 
						|
  if (!AppConstants.MOZ_CRASHREPORTER) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  // If we end up increasing the process count limit in future,
 | 
						|
  // we want to ensure that we don't stop testing this case
 | 
						|
  // of pinned tab data loss.
 | 
						|
  if (SpecialPowers.getIntPref("dom.ipc.processCount") > 8) {
 | 
						|
    ok(
 | 
						|
      false,
 | 
						|
      "Process count is greater than 8, update the number of pinned tabs in test."
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  // We expect 17 pinned tabs plus the selected tab get content restored.
 | 
						|
  // Given that the default process count is currently 8, we need this
 | 
						|
  // number of pinned tabs to reproduce the data loss. If this changes,
 | 
						|
  // please add more pinned tabs.
 | 
						|
  let allTabsRestored = promiseSessionStoreLoads(18);
 | 
						|
  await promiseBrowserState({
 | 
						|
    windows: [
 | 
						|
      {
 | 
						|
        selected: 18, // SessionStore uses 1-based indexing.
 | 
						|
        tabs: [
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          {
 | 
						|
            pinned: true,
 | 
						|
            entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }],
 | 
						|
          },
 | 
						|
          { entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }] },
 | 
						|
        ],
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  });
 | 
						|
  await allTabsRestored;
 | 
						|
 | 
						|
  let tabs = gBrowser.tabs;
 | 
						|
  await BrowserTestUtils.crashFrame(tabs[17].linkedBrowser);
 | 
						|
 | 
						|
  await TestUtils.topicObserved("sessionstore-state-write-complete");
 | 
						|
 | 
						|
  for (let i = 0; i < tabs.length; i++) {
 | 
						|
    let tab = tabs[i];
 | 
						|
    is(
 | 
						|
      tab.linkedBrowser.currentURI.spec,
 | 
						|
      REMOTE_URL,
 | 
						|
      `Tab ${i + 1} should have matching URL`
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  // Clean up for the next task.
 | 
						|
  await promiseBrowserState(BACKUP_STATE);
 | 
						|
});
 |