Backed out changeset 649252a67839 (bug 1809661) for causing failures complaining about _createRecentTabsList . CLOSED TREE

This commit is contained in:
Butkovits Atila 2023-03-08 21:12:35 +02:00
parent 1956495c03
commit fdef81b168
11 changed files with 53 additions and 628 deletions

View File

@ -169,7 +169,7 @@ export const TabsSetupFlowManager = new (class {
this._currentSetupStateName = "not-signed-in";
this._shouldShowSuccessConfirmation = false;
this._didShowMobilePromo = false;
this.waitingForTabs = false;
this._waitingForTabs = false;
this.syncHasWorked = false;
@ -178,8 +178,6 @@ export const TabsSetupFlowManager = new (class {
mobileDeviceConnected: this.mobileDeviceConnected,
secondaryDeviceConnected: this.secondaryDeviceConnected,
};
// keep track of tab-pickup-container instance visibilities
this._viewVisibilityStates = new Map();
}
get isPrimaryPasswordLocked() {
@ -217,14 +215,6 @@ export const TabsSetupFlowManager = new (class {
Services.obs.removeObserver(this, FXA_DEVICE_CONNECTED);
Services.obs.removeObserver(this, FXA_DEVICE_DISCONNECTED);
}
get hasVisibleViews() {
return Array.from(this._viewVisibilityStates.values()).reduce(
(hasVisible, visibility) => {
return hasVisible || visibility == "visible";
},
false
);
}
get currentSetupState() {
return this.setupState.get(this._currentSetupStateName);
}
@ -306,15 +296,12 @@ export const TabsSetupFlowManager = new (class {
break;
case TOPIC_DEVICELIST_UPDATED:
this.logger.debug("Handling observer notification:", topic, data);
const { deviceStateChanged, deviceAdded } = await this.refreshDevices();
if (deviceStateChanged) {
if (await this.refreshDevices()) {
this.logger.debug(
"refreshDevices made changes, calling maybeUpdateUI"
);
this.maybeUpdateUI(true);
}
if (deviceAdded && this.secondaryDeviceConnected) {
this.logger.debug("device was added");
this._newlyAddedDeviceTabsPending = true;
this.startWaitingForNewDeviceTabs();
}
break;
case FXA_DEVICE_CONNECTED:
case FXA_DEVICE_DISCONNECTED:
@ -324,20 +311,18 @@ export const TabsSetupFlowManager = new (class {
case SYNC_SERVICE_ERROR:
this.logger.debug(`Handling ${SYNC_SERVICE_ERROR}`);
if (lazy.UIState.get().status == lazy.UIState.STATUS_SIGNED_IN) {
this.waitingForTabs = false;
this._waitingForTabs = false;
this.syncIsWorking = false;
this.maybeUpdateUI(true);
}
break;
case NETWORK_STATUS_CHANGED:
this.networkIsOnline = data == "online";
this.waitingForTabs = false;
this._waitingForTabs = false;
this.maybeUpdateUI(true);
break;
case SYNC_SERVICE_FINISHED:
this.logger.debug(`Handling ${SYNC_SERVICE_FINISHED}`);
// We intentionally leave any pending flag and empty-tabs timestamp here
// as we may be still waiting for a sync that delivers some tabs
this._waitingForTabs = false;
if (!this.syncIsWorking) {
this.syncIsWorking = true;
@ -355,50 +340,15 @@ export const TabsSetupFlowManager = new (class {
}
}
updateViewVisiblity(instanceId, visibility) {
this.logger.debug(
`updateViewVisiblity for instance: ${instanceId}, visibility: ${visibility}`
);
if (visibility == "unloaded") {
this._viewVisibilityStates.delete(instanceId);
} else {
this._viewVisibilityStates.set(instanceId, visibility);
}
// If we're currently waiting for tabs from a newly-added device
// we may want to start the empty-tabs visible timer
if (this._newlyAddedDeviceTabsPending && this.hasVisibleViews) {
this.startWaitingForNewDeviceTabs();
}
if (!this.hasVisibleViews) {
this.logger.debug(
"Resetting timestamp and tabs pending flags as there are no visible views"
);
// if there's no view visible, we're not really waiting anymore
this._noTabsVisibleFromAddedDeviceTimestamp = 0;
this._newlyAddedDeviceTabsPending = false;
}
}
get waitingForTabs() {
return !!(
return (
// signed in & at least 1 other device is sycning indicates there's something to wait for
(
this.secondaryDeviceConnected &&
// last recent tabs request came back empty and we've not had a sync finish (or error) yet
(this._waitingForTabs || this._noTabsVisibleFromAddedDeviceTimestamp)
)
this.secondaryDeviceConnected &&
// last recent tabs request came back empty and we've not had a sync finish (or error) yet
this._waitingForTabs
);
}
set waitingForTabs(isWaiting) {
this._waitingForTabs = isWaiting;
if (!isWaiting) {
// also clear out the device-added / tabs pending flags
this._noTabsVisibleFromAddedDeviceTimestamp = 0;
this._newlyAddedDeviceTabsPending = false;
}
}
startWaitingForTabs() {
if (!this._waitingForTabs) {
this._waitingForTabs = true;
@ -406,33 +356,9 @@ export const TabsSetupFlowManager = new (class {
}
}
async stopWaitingForTabs() {
const recentTabs = await lazy.SyncedTabs.getRecentTabs(1);
if (!recentTabs.length && this._newlyAddedDeviceTabsPending) {
// we are still waiting for some tabs to show...
this.logger.debug(
"stopWaitingForTabs: Still no recent tabs, we are still waiting"
);
return;
}
if (this._noTabsVisibleFromAddedDeviceTimestamp) {
// If we were waiting for tabs from a newly-added device, record
// the time elapsed
const elapsed = Date.now() - this._noTabsVisibleFromAddedDeviceTimestamp;
this.logger.debug(
"stopWaitingForTabs, resetting _noTabsVisibleFromAddedDeviceTimestamp and recording telemetry:",
Math.round(elapsed / 1000)
);
Services.telemetry.recordEvent(
"firefoxview",
"synced_tabs_empty",
"since_device_added",
Math.round(elapsed / 1000).toString()
);
}
const wasWaiting = this.waitingForTabs;
this.waitingForTabs = false;
if (wasWaiting) {
stopWaitingForTabs() {
if (this._waitingForTabs) {
this._waitingForTabs = false;
Services.obs.notifyObservers(null, TOPIC_SETUPSTATE_CHANGED);
}
}
@ -443,7 +369,7 @@ export const TabsSetupFlowManager = new (class {
this.maybeUpdateUI(true);
if (!this.fxaSignedIn) {
// As we just signed out, ensure the waiting flag is reset for next time around
this.waitingForTabs = false;
this._waitingForTabs = false;
return;
}
@ -462,8 +388,7 @@ export const TabsSetupFlowManager = new (class {
// When SyncedTabs has resolved the getRecentTabs promise,
// we also know we can update devices-related internal state
const { deviceStateChanged } = await this.refreshDevices();
if (deviceStateChanged) {
if (await this.refreshDevices()) {
this.logger.debug(
"onSignedInChange, after refreshDevices, calling maybeUpdateUI"
);
@ -499,28 +424,6 @@ export const TabsSetupFlowManager = new (class {
}
}
async startWaitingForNewDeviceTabs() {
// don't start a timer if all tab-pickup-container views are currently hidden
if (!this.hasVisibleViews) {
return;
}
// if we're already waiting for tabs, don't reset
if (this._noTabsVisibleFromAddedDeviceTimestamp) {
return;
}
// take a timestamp whenever the latest device is added and we have 0 tabs to show,
// allowing us to track how long we show an empty list after a new device is added
const hasRecentTabs = (await lazy.SyncedTabs.getRecentTabs(1)).length;
if (this.hasVisibleViews && !hasRecentTabs) {
this._noTabsVisibleFromAddedDeviceTimestamp = Date.now();
this.logger.debug(
"New device added, storing timestamp:",
this._noTabsVisibleFromAddedDeviceTimestamp
);
}
}
async refreshDevices() {
// If current device not found in recent device list, refresh device list
if (
@ -534,15 +437,13 @@ export const TabsSetupFlowManager = new (class {
// compare new values to the previous values
const mobileDeviceConnected = this.mobileDeviceConnected;
const secondaryDeviceConnected = this.secondaryDeviceConnected;
const oldDevicesCount = this._deviceStateSnapshot?.devicesCount ?? 0;
const devicesCount = lazy.fxAccounts.device?.recentDeviceList?.length ?? 0;
this.logger.debug(
`refreshDevices, mobileDeviceConnected: ${mobileDeviceConnected}, `,
`secondaryDeviceConnected: ${secondaryDeviceConnected}`
);
let deviceStateChanged =
let didDeviceStateChange =
this._deviceStateSnapshot.mobileDeviceConnected !=
mobileDeviceConnected ||
this._deviceStateSnapshot.secondaryDeviceConnected !=
@ -564,9 +465,8 @@ export const TabsSetupFlowManager = new (class {
this._deviceStateSnapshot = {
mobileDeviceConnected,
secondaryDeviceConnected,
devicesCount,
};
if (deviceStateChanged) {
if (didDeviceStateChange) {
this.logger.debug("refreshDevices: device state did change");
if (!secondaryDeviceConnected) {
this.logger.debug(
@ -577,10 +477,7 @@ export const TabsSetupFlowManager = new (class {
} else {
this.logger.debug("refreshDevices: no device state change");
}
return {
deviceStateChanged,
deviceAdded: oldDevicesCount < devicesCount,
};
return didDeviceStateChange;
}
maybeUpdateUI(forceUpdate = false) {

View File

@ -20,7 +20,6 @@ class TabPickupContainer extends HTMLDetailsElement {
this._currentSetupStateIndex = -1;
this.errorState = null;
this.tabListAdded = null;
this._id = Math.floor(Math.random() * 10e6);
}
get setupContainerElem() {
return this.querySelector(".sync-setup-container");
@ -42,7 +41,7 @@ class TabPickupContainer extends HTMLDetailsElement {
connectedCallback() {
this.addEventListener("click", this);
this.addEventListener("toggle", this);
this.ownerDocument.addEventListener("visibilitychange", this);
this.addEventListener("visibilitychange", this);
Services.obs.addObserver(this.boundObserve, TOPIC_SETUPSTATE_CHANGED);
for (let elem of this.querySelectorAll("a[data-support-url]")) {
@ -55,7 +54,6 @@ class TabPickupContainer extends HTMLDetailsElement {
// when its safe to assume the custom-element's methods will be available
this.tabListAdded = this.promiseChildAdded();
this.update();
this.onVisibilityChange();
}
promiseChildAdded() {
@ -75,8 +73,6 @@ class TabPickupContainer extends HTMLDetailsElement {
}
cleanup() {
TabsSetupFlowManager.updateViewVisiblity(this._id, "unloaded");
this.ownerDocument?.removeEventListener("visibilitychange", this);
Services.obs.removeObserver(this.boundObserve, TOPIC_SETUPSTATE_CHANGED);
}
@ -87,7 +83,6 @@ class TabPickupContainer extends HTMLDetailsElement {
handleEvent(event) {
if (event.type == "toggle") {
onToggleContainer(this);
this.onVisibilityChange();
return;
}
if (event.type == "click" && event.target.dataset.action) {
@ -135,21 +130,11 @@ class TabPickupContainer extends HTMLDetailsElement {
}
}
// Returning to fxview seems like a likely time for a device check
if (event.type == "visibilitychange") {
this.onVisibilityChange();
}
}
onVisibilityChange() {
const isVisible = document.visibilityState == "visible";
const isOpen = this.open;
if (isVisible && isOpen) {
if (
event.type == "visibilitychange" &&
document.visibilityState === "visible"
) {
this.update();
TabsSetupFlowManager.updateViewVisiblity(this._id, "visible");
} else {
TabsSetupFlowManager.updateViewVisiblity(
this._id,
isVisible ? "closed" : "hidden"
);
}
}

View File

@ -98,15 +98,10 @@ async function withFirefoxView(
return result;
}
function isFirefoxViewTabSelectedInWindow(win) {
return win.gBrowser.selectedBrowser.currentURI.spec == "about:firefoxview";
}
export {
withFirefoxView,
assertFirefoxViewTab,
assertFirefoxViewTabSelected,
openFirefoxViewTab,
closeFirefoxViewTab,
isFirefoxViewTabSelectedInWindow,
};

View File

@ -27,7 +27,5 @@ skip-if = true # Bug 1783684
[browser_sync_admin_disabled.js]
[browser_tab_close_last_tab.js]
[browser_tab_on_close_warning.js]
[browser_tab_pickup_device_added_telemetry.js]
[browser_tab_pickup_list.js]
[browser_tab_pickup_visibility.js]
[browser_ui_state.js]

View File

@ -35,8 +35,6 @@ add_task(async function test_primary_password_locked() {
sandbox
.stub(TabsSetupFlowManager, "syncTabs")
.returns(Promise.resolve(null));
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
syncedTabsMock.returns(Promise.resolve(getMockTabData(syncedTabsData1)));
const { document } = browser.contentWindow;
Services.obs.notifyObservers(null, UIState.ON_UPDATE);

View File

@ -132,7 +132,7 @@ add_task(async function test_tab_sync_loading() {
add_task(async function test_tab_no_sync() {
// Ensure we take down the waiting message if SyncedTabs determines it doesnt need to sync
const recentTabsData = structuredClone(syncedTabsData1[0].tabs);
const recentTabsData = [];
const sandbox = setupMocks(recentTabsData);
// stub syncTabs so it resolves to false - meaning it will not trigger a sync, which is the case
// we want to cover in this test.

View File

@ -1,271 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
ChromeUtils.defineESModuleGetters(globalThis, {
SyncedTabs: "resource://services-sync/SyncedTabs.sys.mjs",
});
SimpleTest.requestCompleteLog();
registerCleanupFunction(async function() {
await clearAllParentTelemetryEvents();
cleanup_tab_pickup();
});
function setupWithFxaDevices() {
const sandbox = setupSyncFxAMocks({
state: UIState.STATUS_SIGNED_IN,
fxaDevices: [
{
id: 1,
name: "My desktop",
isCurrentDevice: true,
type: "desktop",
},
{
id: 2,
name: "Other device",
isCurrentDevice: false,
type: "mobile",
},
],
});
return sandbox;
}
const mockDesktopTab1 = {
client: "6c12bonqXZh8",
device: "My desktop",
deviceType: "desktop",
type: "tab",
title: "Example2",
url: "https://example.com",
icon: "https://example/favicon.png",
lastUsed: Math.floor((Date.now() - 1000 * 60) / 1000), // This is one minute from now, which is below the threshold for 'Just now'
};
const mockDesktopTab2 = {
client: "6c12bonqXZh8",
device: "My desktop",
deviceType: "desktop",
type: "tab",
title: "Sandboxes - Sinon.JS",
url: "https://sinonjs.org/releases/latest/sandbox/",
icon: "https://sinonjs.org/assets/images/favicon.png",
lastUsed: 1655391592, // Thu Jun 16 2022 14:59:52 GMT+0000
};
const mockMobileTab1 = {
client: "9d0y686hBXel",
device: "My phone",
deviceType: "mobile",
type: "tab",
title: "Element",
url: "https://chat.mozilla.org/#room:mozilla.org",
icon: "https://chat.mozilla.org/vector-icons/favicon.ico",
lastUsed: 1664571288,
};
const NO_TABS_EVENTS = [
["firefoxview", "entered", "firefoxview", undefined],
["firefoxview", "synced_tabs", "tabs", undefined, { count: "0" }],
];
const SINGLE_TAB_EVENTS = [
["firefoxview", "entered", "firefoxview", undefined],
["firefoxview", "synced_tabs", "tabs", undefined, { count: "1" }],
];
const DEVICE_ADDED_NO_TABS_EVENTS = [
["firefoxview", "synced_tabs", "tabs", undefined, undefined],
["firefoxview", "synced_tabs_empty", "since_device_added", undefined],
];
const DEVICE_ADDED_TABS_EVENTS = [
["firefoxview", "synced_tabs", "tabs", undefined, undefined],
];
async function test_device_added({
initialRecentTabsResult,
expectedInitialTelementryEvents,
expectedDeviceAddedTelementryEvents,
}) {
const recentTabsResult = initialRecentTabsResult;
await clearAllParentTelemetryEvents();
const sandbox = setupWithFxaDevices();
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
syncedTabsMock.callsFake(() => {
info(
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${recentTabsResult.length} tabs\n`
);
return Promise.resolve(recentTabsResult);
});
ok(
!TabsSetupFlowManager.hasVisibleViews,
"Initially hasVisibleViews is false"
);
is(
TabsSetupFlowManager._viewVisibilityStates.size,
0,
"Initially, there are no visible views"
);
ok(
!isFirefoxViewTabSelected(),
"Before we call withFirefoxView, about:firefoxview tab is not selected"
);
await withFirefoxView({}, async browser => {
info("inside withFirefoxView taskFn, waiting for setupListState");
const { document } = browser.contentWindow;
await setupListState(browser);
info("setupListState finished");
const isTablistVisible = !!initialRecentTabsResult.length;
testVisibility(browser, {
expectedVisible: {
"ol.synced-tabs-list": isTablistVisible,
"#synced-tabs-placeholder": !isTablistVisible,
},
});
const syncedTabsItems = document.querySelectorAll(
"ol.synced-tabs-list > li:not(.synced-tab-li-placeholder)"
);
info(
"list items: " +
Array.from(syncedTabsItems)
.map(li => `li.${li.className}`)
.join(", ")
);
is(
syncedTabsItems.length,
initialRecentTabsResult.length,
`synced-tabs-list should have initial count of ${initialRecentTabsResult.length} non-placeholder list items`
);
// confirm telemetry is in expected state?
info(
"Checking telemetry against expectedInitialTelementryEvents: " +
JSON.stringify(expectedInitialTelementryEvents, null, 2)
);
TelemetryTestUtils.assertEvents(
expectedInitialTelementryEvents,
{ category: "firefoxview" },
{ clear: true, process: "parent" }
);
// add a new mock device
info("Adding a new mock fxa dedvice");
gMockFxaDevices.push({
id: 1,
name: "My primary phone",
isCurrentDevice: false,
type: "mobile",
});
// Notify of the newly added device
const startWaitingSpy = sandbox.spy(
TabsSetupFlowManager,
"startWaitingForNewDeviceTabs"
);
info("Notifying devicelist_updated with the new mobile device");
Services.obs.notifyObservers(null, "fxaccounts:devicelist_updated");
info("Waiting for the startWaitingForNewDeviceTabs spy to be called");
await TestUtils.waitForCondition(() => startWaitingSpy.called);
is(
startWaitingSpy.getCall(0).returnValue.constructor.name,
"Promise",
"startWaitingForNewDeviceTabs returned a promise"
);
// Some time passes here waiting for sync to get data from that device
// we expect new-device handling to kick in. If there are 0 tabs we'll signal we're waiting,
// create a timestamp and only clear it when there are > 0 tabs.
// If there are already > 0 tabs, we'll basically do nothing, showing any new tabs when the arrive
info("Waiting for the startWaitingForNewDeviceTabs promise to resolve");
await startWaitingSpy.getCall(0).returnValue;
info(
"Initial tabs count: " +
recentTabsResult.length +
", assert on waitingForTabs, TabsSetupFlowManager.waitingForTabs: " +
TabsSetupFlowManager.waitingForTabs
);
is(
TabsSetupFlowManager.waitingForTabs,
!recentTabsResult.length,
"Should be waiting if there were 0 tabs initially"
);
// Add tab data from this new device and notify of the changed data
recentTabsResult.push(mockMobileTab1);
const stopWaitingSpy = sandbox.spy(
TabsSetupFlowManager,
"stopWaitingForTabs"
);
info("Notifying tabs.changed with the new mobile device's tabs");
Services.obs.notifyObservers(null, "services.sync.tabs.changed");
// handling the tab.change and clearing the timestamp is necessarily async
// as counting synced tabs via getRecentTabs() is async.
// There may not be any outcome depending on the tab state, so we just wait
// for stopWaitingForTabs to get called and its promise to resolve
if (TabsSetupFlowManager.waitingForTabs) {
// the setup manager will notify when we stop loading/waiting
info("Waiting for setupstate.changed to be notified");
await TestUtils.topicObserved("firefox-view.setupstate.changed");
}
info("Waiting for the stopWaitingSpy to be called");
await TestUtils.waitForCondition(() => stopWaitingSpy.called);
is(
stopWaitingSpy.getCall(0).returnValue.constructor.name,
"Promise",
"stopWaitingTabs returned a promise"
);
info("Waiting for the stopWaiting promise to resolve");
await stopWaitingSpy.getCall(0).returnValue;
let snapshots = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
false
);
info(
"Weve added a synced tab and updated the tab list, got snapshotEvents:" +
JSON.stringify(snapshots, null, 2)
);
// confirm no telemetry was recorded for tabs from the newly-added device
// as the tab list was never empty
info(
"Checking telemetry against expectedDeviceAddedTelementryEvents: " +
JSON.stringify(expectedDeviceAddedTelementryEvents, null, 2)
);
TelemetryTestUtils.assertEvents(
expectedDeviceAddedTelementryEvents,
{ category: "firefoxview" },
{ clear: true, process: "parent" }
);
});
sandbox.restore();
cleanup_tab_pickup();
}
add_task(async function test_device_added_with_existing_tabs() {
/* Confirm that no telemetry is recorded when a new device is added while the synced tabs list has tabs */
await test_device_added({
initialRecentTabsResult: [mockDesktopTab1],
expectedInitialTelementryEvents: SINGLE_TAB_EVENTS,
expectedDeviceAddedTelementryEvents: DEVICE_ADDED_TABS_EVENTS,
});
});
add_task(async function test_device_added_with_empty_list() {
/* Confirm that telemetry is recorded when a device is added and the synced tabs list
is empty until its tabs get synced
*/
await test_device_added({
initialRecentTabsResult: [],
expectedInitialTelementryEvents: NO_TABS_EVENTS,
expectedDeviceAddedTelementryEvents: DEVICE_ADDED_NO_TABS_EVENTS,
});
});

View File

@ -145,12 +145,11 @@ add_task(async function test_tab_list_ordering() {
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
let mockTabs1 = getMockTabData(syncedTabsData1);
let mockTabs2 = getMockTabData(syncedTabsData2);
let getRecentTabsResult = mockTabs1;
syncedTabsMock.callsFake(() => {
info(
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${getRecentTabsResult.length} tabs\n`
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${mockTabs1.length} tabs\n`
);
return Promise.resolve(getRecentTabsResult);
return Promise.resolve(mockTabs1);
});
await withFirefoxView({}, async browser => {
@ -183,7 +182,7 @@ add_task(async function test_tab_list_ordering() {
"Last list item in synced-tabs-list is in the correct order"
);
getRecentTabsResult = mockTabs2;
syncedTabsMock.returns(mockTabs2);
// Initiate a synced tabs update
Services.obs.notifyObservers(null, "services.sync.tabs.changed");
@ -224,12 +223,11 @@ add_task(async function test_empty_list_items() {
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
let mockTabs1 = getMockTabData(syncedTabsData3);
let mockTabs2 = getMockTabData(syncedTabsData4);
let getRecentTabsResult = mockTabs1;
syncedTabsMock.callsFake(() => {
info(
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${getRecentTabsResult.length} tabs\n`
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${mockTabs1.length} tabs\n`
);
return Promise.resolve(getRecentTabsResult);
return Promise.resolve(mockTabs1);
});
await withFirefoxView({}, async browser => {
@ -269,7 +267,7 @@ add_task(async function test_empty_list_items() {
"Last list item in synced-tabs-list should be a placeholder"
);
getRecentTabsResult = mockTabs2;
syncedTabsMock.returns(mockTabs2);
// Initiate a synced tabs update
Services.obs.notifyObservers(null, "services.sync.tabs.changed");
@ -307,12 +305,11 @@ add_task(async function test_empty_list() {
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
let mockTabs1 = getMockTabData([]);
let mockTabs2 = getMockTabData(syncedTabsData4);
let getRecentTabsResult = mockTabs1;
syncedTabsMock.callsFake(() => {
info(
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${getRecentTabsResult.length} tabs\n`
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${mockTabs1.length} tabs\n`
);
return Promise.resolve(getRecentTabsResult);
return Promise.resolve(mockTabs1);
});
await withFirefoxView({}, async browser => {
@ -353,7 +350,12 @@ add_task(async function test_empty_list() {
{ clear: true, process: "parent" }
);
getRecentTabsResult = mockTabs2;
syncedTabsMock.callsFake(() => {
info(
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${mockTabs2.length} tabs\n`
);
return Promise.resolve(mockTabs2);
});
// Initiate a synced tabs update
Services.obs.notifyObservers(null, "services.sync.tabs.changed");
@ -385,12 +387,11 @@ add_task(async function test_time_updates_correctly() {
const sandbox = setupRecentDeviceListMocks();
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
let mockTabs1 = getMockTabData(syncedTabsData5);
let getRecentTabsResult = mockTabs1;
syncedTabsMock.callsFake(() => {
info(
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${getRecentTabsResult.length} tabs\n`
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${mockTabs1.length} tabs\n`
);
return Promise.resolve(getRecentTabsResult);
return Promise.resolve(mockTabs1);
});
await withFirefoxView({}, async browser => {
@ -496,12 +497,11 @@ add_task(async function test_tabs_sync_on_user_page_reload() {
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
let mockTabs1 = getMockTabData(syncedTabsData1);
let expectedTabsAfterReload = getMockTabData(syncedTabsData3);
let getRecentTabsResult = mockTabs1;
syncedTabsMock.callsFake(() => {
info(
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${getRecentTabsResult.length} tabs\n`
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${mockTabs1.length} tabs\n`
);
return Promise.resolve(getRecentTabsResult);
return Promise.resolve(mockTabs1);
});
await withFirefoxView({}, async browser => {
@ -518,12 +518,9 @@ add_task(async function test_tabs_sync_on_user_page_reload() {
ok(true, "Firefox View has been reloaded");
ok(TabsSetupFlowManager.waitingForTabs, "waitingForTabs is true");
let waitedForTabs = TestUtils.waitForCondition(() => {
return !TabsSetupFlowManager.waitingForTabs;
});
getRecentTabsResult = expectedTabsAfterReload;
syncedTabsMock.returns(expectedTabsAfterReload);
Services.obs.notifyObservers(null, "services.sync.tabs.changed");
ok(!TabsSetupFlowManager.waitingForTabs, "waitingForTabs is false");
const syncedTabsList = document.querySelector("ol.synced-tabs-list");
// The tab pickup list has been updated
@ -533,7 +530,6 @@ add_task(async function test_tabs_sync_on_user_page_reload() {
() =>
syncedTabsList.firstChild.textContent.includes("Sandboxes - Sinon.JS")
);
await waitedForTabs;
sandbox.restore();
cleanup_tab_pickup();
@ -546,12 +542,11 @@ add_task(async function test_keyboard_navigation() {
const sandbox = setupRecentDeviceListMocks();
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
let mockTabs1 = getMockTabData(syncedTabsData1);
let getRecentTabsResult = mockTabs1;
syncedTabsMock.callsFake(() => {
info(
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${getRecentTabsResult.length} tabs\n`
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${mockTabs1.length} tabs\n`
);
return Promise.resolve(getRecentTabsResult);
return Promise.resolve(mockTabs1);
});
await withFirefoxView({}, async browser => {
@ -658,12 +653,11 @@ add_task(async function test_duplicate_tab_filter() {
const sandbox = setupRecentDeviceListMocks();
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
let mockTabs6 = getMockTabData(syncedTabsData6);
let getRecentTabsResult = mockTabs6;
syncedTabsMock.callsFake(() => {
info(
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${getRecentTabsResult.length} tabs\n`
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${mockTabs6.length} tabs\n`
);
return Promise.resolve(getRecentTabsResult);
return Promise.resolve(mockTabs6);
});
await withFirefoxView({}, async browser => {
@ -714,12 +708,11 @@ add_task(async function test_tabs_dont_update_unnecessarily() {
const sandbox = setupRecentDeviceListMocks();
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
let mockTabs1 = getMockTabData(syncedTabsData1);
let getRecentTabsResult = mockTabs1;
syncedTabsMock.callsFake(() => {
info(
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${getRecentTabsResult.length} tabs\n`
`Stubbed SyncedTabs.getRecentTabs returning a promise that resolves to ${mockTabs1.length} tabs\n`
);
return Promise.resolve(getRecentTabsResult);
return Promise.resolve(mockTabs1);
});
await withFirefoxView({}, async browser => {
@ -760,15 +753,13 @@ add_task(async function test_tabs_dont_update_unnecessarily() {
observer.observe(syncedTabsList, { childList: true, subtree: true });
getRecentTabsResult = mockTabs1;
syncedTabsMock.returns(mockTabs1);
const tabPickupList = document.querySelector("tab-pickup-list");
const updateTabsListSpy = sandbox.spy(tabPickupList, "updateTabsList");
// Initiate a synced tabs update
Services.obs.notifyObservers(null, "services.sync.tabs.changed");
await TestUtils.waitForCondition(() => {
return !TabsSetupFlowManager.waitingForTabs;
});
await TestUtils.waitForCondition(() => updateTabsListSpy.called);
Assert.ok(!wasMutated, "The synced tabs list was not mutated");

View File

@ -1,149 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
registerCleanupFunction(async function() {
Services.prefs.clearUserPref(TAB_PICKUP_STATE_PREF);
});
async function setup({ open } = {}) {
TabsSetupFlowManager.resetInternalState();
// sanity check initial values
ok(
!TabsSetupFlowManager.hasVisibleViews,
"Initially hasVisibleViews is false"
);
is(
TabsSetupFlowManager._viewVisibilityStates.size,
0,
"Initially, there are no visible views"
);
ok(
!isFirefoxViewTabSelected(),
"During setup, the about:firefoxview tab is not selected"
);
if (typeof open == "undefined") {
Services.prefs.clearUserPref(TAB_PICKUP_STATE_PREF);
} else {
await SpecialPowers.pushPrefEnv({
set: [[TAB_PICKUP_STATE_PREF, open]],
});
}
const sandbox = sinon.createSandbox();
sandbox.stub(TabsSetupFlowManager, "isTabSyncSetupComplete").get(() => true);
return sandbox;
}
add_task(async function test_tab_pickup_visibility() {
/* Confirm the correct number of tab-pickup views are registered as visible */
const sandbox = await setup();
await withFirefoxView({ win: window }, async function(browser) {
const { document } = browser.contentWindow;
let tabPickupContainer = document.querySelector("#tab-pickup-container");
ok(tabPickupContainer.open, "Tab Pickup container should be open");
ok(isFirefoxViewTabSelected(), "The firefox view tab is selected");
ok(TabsSetupFlowManager.hasVisibleViews, "hasVisibleViews");
is(TabsSetupFlowManager._viewVisibilityStates.size, 1, "One view");
info("Opening and switching to different tab to background fx-view");
let newTab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
"about:mozilla"
);
ok(!isFirefoxViewTabSelected(), "The firefox view tab is not selected");
ok(
!TabsSetupFlowManager.hasVisibleViews,
"no view visible when fx-view is not active"
);
let newWin = await BrowserTestUtils.openNewBrowserWindow();
await openFirefoxViewTab(newWin);
ok(
isFirefoxViewTabSelected(newWin),
"The firefox view tab in the new window is selected"
);
ok(
TabsSetupFlowManager.hasVisibleViews,
"view registered as visible when fx-view is opened in a new window"
);
is(TabsSetupFlowManager._viewVisibilityStates.size, 2, "2 tracked views");
await BrowserTestUtils.closeWindow(newWin);
ok(
!isFirefoxViewTabSelected(),
"The firefox view tab in the original window is not selected"
);
ok(
!TabsSetupFlowManager.hasVisibleViews,
"no visible views when fx-view is not the active tab in the remaining window"
);
is(
TabsSetupFlowManager._viewVisibilityStates.size,
1,
"Back to one tracked view"
);
// Switch back to FxView:
await BrowserTestUtils.switchTab(
gBrowser,
gBrowser.getTabForBrowser(browser)
);
ok(
isFirefoxViewTabSelected(),
"The firefox view tab in the original window is now selected"
);
ok(
TabsSetupFlowManager.hasVisibleViews,
"View visibility updated when we switch tab"
);
BrowserTestUtils.removeTab(newTab);
});
sandbox.restore();
await SpecialPowers.popPrefEnv();
ok(
!TabsSetupFlowManager.hasVisibleViews,
"View visibility updated after withFirefoxView"
);
});
add_task(async function test_instance_closed() {
/* Confirm tab-pickup views are correctly accounted for when toggled closed */
const sandbox = await setup({ open: false });
await withFirefoxView({ win: window }, async function(browser) {
const { document } = browser.contentWindow;
info(
"tab-pickup.open pref: " +
Services.prefs.getBoolPref(
"browser.tabs.firefox-view.ui-state.tab-pickup.open"
)
);
info(
"isTabSyncSetupComplete: " + TabsSetupFlowManager.isTabSyncSetupComplete
);
let tabPickupContainer = document.querySelector("#tab-pickup-container");
ok(!tabPickupContainer.open, "Tab Pickup container should be closed");
info(
"_viewVisibilityStates" +
JSON.stringify(
Array.from(TabsSetupFlowManager._viewVisibilityStates.values()),
null,
2
)
);
ok(!TabsSetupFlowManager.hasVisibleViews, "no visible views");
is(
TabsSetupFlowManager._viewVisibilityStates.size,
1,
"One registered view"
);
tabPickupContainer.open = true;
await TestUtils.waitForTick();
ok(TabsSetupFlowManager.hasVisibleViews, "view visible");
});
sandbox.restore();
});

View File

@ -7,7 +7,6 @@ const {
assertFirefoxViewTabSelected,
openFirefoxViewTab,
closeFirefoxViewTab,
isFirefoxViewTabSelectedInWindow,
} = ChromeUtils.importESModule(
"resource://testing-common/FirefoxViewTestUtils.sys.mjs"
);
@ -528,7 +527,3 @@ function cleanup_tab_pickup() {
Services.prefs.clearUserPref("services.sync.lastTabFetch");
Services.prefs.clearUserPref(TAB_PICKUP_STATE_PREF);
}
function isFirefoxViewTabSelected(win = window) {
return isFirefoxViewTabSelectedInWindow(win);
}

View File

@ -3650,20 +3650,6 @@ firefoxview:
- 1789641
expiry_version: "never"
release_channel_collection: opt-out
synced_tabs_empty:
objects: ["since_device_added"]
description: >
Records the time elapsed in seconds that the Tab Pickup empty message is displayed after a new device was added
notification_emails:
- firefox-view-engineers@mozilla.com
products:
- "firefox"
record_in_processes:
- main
bug_numbers:
- 1809661
expiry_version: "120"
release_channel_collection: opt-out
closed_tabs_open:
objects: ["tabs"]
description: >