Commit 9b43f474 authored by criss's avatar criss
Browse files

Merge autoland to mozilla-central. a=merge

parents 85a87e3f 14e158cc
Loading
Loading
Loading
Loading
+170 −164

File changed.

Preview size limit exceeded, changes collapsed.

+3 −0
Original line number Diff line number Diff line
@@ -90,6 +90,9 @@ vcpkg = { path = "build/rust/vcpkg" }
# Helper crate for integration in the gecko build system.
mozbuild = { path = "build/rust/mozbuild" }

# Patch itoa 0.4 to 1.0.
itoa = { path = "build/rust/itoa" }

# Patch autocfg to hide rustc output. Workaround for https://github.com/cuviper/autocfg/issues/30
autocfg = { path = "third_party/rust/autocfg" }

+18 −9
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ const { switchToTabHavingURI } = window.docShell.chromeEventHandler.ownerGlobal;
const { XPCOMUtils } = ChromeUtils.import(
  "resource://gre/modules/XPCOMUtils.jsm"
);
const SYNC_TABS_PREF = "services.sync.engine.tabs";

const tabsSetupFlowManager = new (class {
  constructor() {
@@ -28,6 +29,17 @@ const tabsSetupFlowManager = new (class {
      "resource://services-sync/UIState.jsm"
    );

    // this.syncTabsPrefEnabled will track the value of the tabs pref
    XPCOMUtils.defineLazyPreferenceGetter(
      this,
      "syncTabsPrefEnabled",
      SYNC_TABS_PREF,
      false,
      () => {
        this.maybeUpdateUI();
      }
    );

    this.registerSetupState({
      uiStateIndex: 0,
      name: "not-signed-in",
@@ -47,9 +59,7 @@ const tabsSetupFlowManager = new (class {
      uiStateIndex: 2,
      name: "disabled-tab-sync",
      exitConditions: () => {
        // Bug 1763139 - Implement the actual logic to advance to next step
        // This will basically be a check for the pref to enable tab-syncing
        return false;
        return this.syncTabsPrefEnabled;
      },
    });
    this.registerSetupState({
@@ -62,7 +72,7 @@ const tabsSetupFlowManager = new (class {
    });
    this.registerSetupState({
      uiStateIndex: 4,
      name: "show-synced-tabs-agreement",
      name: "show-synced-tabs-loading",
      exitConditions: () => {
        // Bug 1763139 - Implement the actual logic to advance to next step
        return false;
@@ -165,15 +175,14 @@ const tabsSetupFlowManager = new (class {
    switchToTabHavingURI(url, true);
  }
  syncOpenTabs(containerElem) {
    // Bug 1763139 - Implement the actual logic to advance to next step
    this.elem.updateSetupState(
      this.setupState.get("synced-tabs-not-ready").uiStateIndex
    );
    // Flip the pref on.
    // The observer should trigger re-evaluating state and advance to next step
    this.Services.prefs.setBoolPref(SYNC_TABS_PREF, true);
  }
  confirmSetupComplete(containerElem) {
    // Bug 1763139 - Implement the actual logic to advance to next step
    this.elem.updateSetupState(
      this.setupState.get("show-synced-tabs-agreement").uiStateIndex
      this.setupState.get("show-synced-tabs-loading").uiStateIndex
    );
  }
})();
+99 −37
Original line number Diff line number Diff line
@@ -30,19 +30,34 @@ function setupMocks({ fxaDevices = null, state = UIState.STATUS_SIGNED_IN }) {
  return sandbox;
}

function testSetupState(browser, expected) {
async function waitForVisibleStep(browser, expected) {
  const { document } = browser.contentWindow;
  for (let [selector, shouldBeVisible] of Object.entries(
    expected.expectedVisible
  )) {
    const elem = document.querySelector(selector);
    if (shouldBeVisible) {

  const deck = document.querySelector(".sync-setup-container");
  const nextStepElem = deck.querySelector(expected.expectedVisible);
  const stepElems = deck.querySelectorAll(".setup-step");

  await BrowserTestUtils.waitForMutationCondition(
    deck,
    {
      attributeFilter: ["selected-view"],
    },
    () => {
      return BrowserTestUtils.is_visible(nextStepElem);
    }
  );

  for (let elem of stepElems) {
    if (elem == nextStepElem) {
      ok(
        BrowserTestUtils.is_visible(elem),
        `Expected ${selector} to be visible`
        `Expected ${elem.id || elem.className} to be visible`
      );
    } else {
      ok(BrowserTestUtils.is_hidden(elem), `Expected ${selector} to be hidden`);
      ok(
        BrowserTestUtils.is_hidden(elem),
        `Expected ${elem.id || elem.className} to be hidden`
      );
    }
  }
}
@@ -58,6 +73,11 @@ add_setup(async function() {
  );
  registerCleanupFunction(async function() {
    BrowserTestUtils.removeTab(tab);
    Services.prefs.clearUserPref("services.sync.engine.tabs");
  });
  // set tab sync false so we don't skip setup states
  await SpecialPowers.pushPrefEnv({
    set: [["services.sync.engine.tabs", false]],
  });
});

@@ -66,13 +86,8 @@ add_task(async function test_unconfigured_initial_state() {
  const sandbox = setupMocks({ state: UIState.STATUS_NOT_CONFIGURED });

  Services.obs.notifyObservers(null, UIState.ON_UPDATE);
  testSetupState(browser, {
    expectedVisible: {
      "#tabpickup-steps-view0": true,
      "#tabpickup-steps-view1": false,
      "#tabpickup-steps-view2": false,
      "#tabpickup-steps-view3": false,
    },
  await waitForVisibleStep(browser, {
    expectedVisible: "#tabpickup-steps-view0",
  });

  sandbox.restore();
@@ -91,16 +106,11 @@ add_task(async function test_signed_in() {
      },
    ],
  });

  Services.obs.notifyObservers(null, UIState.ON_UPDATE);
  testSetupState(browser, {
    expectedVisible: {
      "#tabpickup-steps-view0": false,
      "#tabpickup-steps-view1": true,
      "#tabpickup-steps-view2": false,
      "#tabpickup-steps-view3": false,
    },
  await waitForVisibleStep(browser, {
    expectedVisible: "#tabpickup-steps-view1",
  });

  is(fxAccounts.device.recentDeviceList?.length, 1, "Just 1 device connected");

  sandbox.restore();
@@ -126,14 +136,10 @@ add_task(async function test_2nd_desktop_connected() {
  });

  Services.obs.notifyObservers(null, UIState.ON_UPDATE);
  testSetupState(browser, {
    expectedVisible: {
      "#tabpickup-steps-view0": false,
      "#tabpickup-steps-view1": true,
      "#tabpickup-steps-view2": false,
      "#tabpickup-steps-view3": false,
    },
  await waitForVisibleStep(browser, {
    expectedVisible: "#tabpickup-steps-view1",
  });

  is(fxAccounts.device.recentDeviceList?.length, 2, "2 devices connected");
  ok(
    fxAccounts.device.recentDeviceList?.every(
@@ -163,16 +169,17 @@ add_task(async function test_mobile_connected() {
      },
    ],
  });
  // ensure tab sync is false so we don't skip onto next step
  ok(
    !Services.prefs.getBoolPref("services.sync.engine.tabs", false),
    "services.sync.engine.tabs is initially false"
  );

  Services.obs.notifyObservers(null, UIState.ON_UPDATE);
  testSetupState(browser, {
    expectedVisible: {
      "#tabpickup-steps-view0": false,
      "#tabpickup-steps-view1": false,
      "#tabpickup-steps-view2": true,
      "#tabpickup-steps-view3": false,
    },
  await waitForVisibleStep(browser, {
    expectedVisible: "#tabpickup-steps-view2",
  });

  is(fxAccounts.device.recentDeviceList?.length, 2, "2 devices connected");
  ok(
    fxAccounts.device.recentDeviceList?.some(
@@ -183,3 +190,58 @@ add_task(async function test_mobile_connected() {

  sandbox.restore();
});

add_task(async function test_tab_sync_enabled() {
  const browser = gBrowser.selectedBrowser;
  const sandbox = setupMocks({
    state: UIState.STATUS_SIGNED_IN,
    fxaDevices: [
      {
        id: 1,
        name: "This Device",
        isCurrentDevice: true,
        type: "desktop",
      },
      {
        id: 2,
        name: "Other Device",
        type: "mobile",
      },
    ],
  });
  Services.obs.notifyObservers(null, UIState.ON_UPDATE);

  // test initial state, with the pref not enabled
  await waitForVisibleStep(browser, {
    expectedVisible: "#tabpickup-steps-view2",
  });

  // test with the pref toggled on
  await SpecialPowers.pushPrefEnv({
    set: [["services.sync.engine.tabs", true]],
  });
  await waitForVisibleStep(browser, {
    expectedVisible: "#tabpickup-steps-view3",
  });

  // reset and test clicking the action button
  await SpecialPowers.popPrefEnv();
  await waitForVisibleStep(browser, {
    expectedVisible: "#tabpickup-steps-view2",
  });

  const actionButton = browser.contentWindow.document.querySelector(
    "#tabpickup-steps-view2 button.primary"
  );
  actionButton.click();
  await waitForVisibleStep(browser, {
    expectedVisible: "#tabpickup-steps-view3",
  });
  ok(
    Services.prefs.getBoolPref("services.sync.engine.tabs", false),
    "tab sync pref should be enabled after button click"
  );

  sandbox.restore();
  Services.prefs.clearUserPref("services.sync.engine.tabs");
});
+28 −11
Original line number Diff line number Diff line
@@ -377,22 +377,39 @@ class UrlbarInput {
    const previousSelectionStart = this.selectionStart;
    const previousSelectionEnd = this.selectionEnd;

    let isDifferentValidValue = valid && value != this.untrimmedValue;
    this.value = value;
    this.valueIsTyped = !valid;
    this.removeAttribute("usertyping");
    if (isDifferentValidValue) {
      // If the caret is at the end of the input or its position is beyond the
      // end of the new value, keep it at the end. Otherwise keep its current
      // position.
      const isCaretPositionEnd =
        previousUntrimmedValue.length === previousSelectionEnd ||
        value.length <= previousSelectionEnd;
      if (isCaretPositionEnd) {
        this.selectionStart = this.selectionEnd = value.length;
      } else {

    if (!this.focused) {
      // When setURI is called while the input is not focused, reset the caret.
      this.selectionStart = this.selectionEnd = 0;
    } else if (value != previousUntrimmedValue) {
      if (
        previousSelectionStart != previousSelectionEnd &&
        value.substring(previousSelectionStart, previousSelectionEnd) ===
          previousUntrimmedValue.substring(
            previousSelectionStart,
            previousSelectionEnd
          )
      ) {
        // If the same text is in the same place as the previously selected text,
        // the selection is kept.
        this.selectionStart = previousSelectionStart;
        this.selectionEnd = previousSelectionEnd;
      } else if (
        previousSelectionEnd &&
        (previousUntrimmedValue.length === previousSelectionEnd ||
          value.length <= previousSelectionEnd)
      ) {
        // If the previous end caret is not 0 and the caret is at the end of the
        // input or its position is beyond the end of the new value, keep the
        // position at the end.
        this.selectionStart = this.selectionEnd = value.length;
      } else {
        // Otherwise clear selection and set the caret position to the previous
        // caret end position.
        this.selectionStart = this.selectionEnd = previousSelectionEnd;
      }
    }

Loading