summaryrefslogtreecommitdiffstats
path: root/browser/components/firefoxview/tests/browser/browser_setup_synced_tabs_loading.js
blob: e302b3dee90e0c3afdfaf38b9dc87458794d7dfb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/* 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",
});

async function tearDown(sandbox) {
  sandbox?.restore();
  Services.prefs.clearUserPref("services.sync.lastTabFetch");
}

function checkLoadingState(browser, isLoading = false) {
  const { document } = browser.contentWindow;
  const tabsContainer = document.querySelector("#tabpickup-tabs-container");
  const tabsList = document.querySelector(
    "#tabpickup-tabs-container tab-pickup-list"
  );
  const loadingElem = document.querySelector(
    "#tabpickup-tabs-container .loading-content"
  );
  const setupElem = document.querySelector("#tabpickup-steps");

  if (isLoading) {
    ok(
      tabsContainer.classList.contains("loading"),
      "Tabs container has loading class"
    );
    BrowserTestUtils.is_visible(
      loadingElem,
      "Loading content is visible when loading"
    );
    !tabsList ||
      BrowserTestUtils.is_hidden(
        tabsList,
        "Synced tabs list is not visible when loading"
      );
    !setupElem ||
      BrowserTestUtils.is_hidden(
        setupElem,
        "Setup content is not visible when loading"
      );
  } else {
    ok(
      !tabsContainer.classList.contains("loading"),
      "Tabs container has no loading class"
    );
    !loadingElem ||
      BrowserTestUtils.is_hidden(
        loadingElem,
        "Loading content is not visible when tabs are loaded"
      );
    BrowserTestUtils.is_visible(
      tabsList,
      "Synced tabs list is visible when loaded"
    );
    !setupElem ||
      BrowserTestUtils.is_hidden(
        setupElem,
        "Setup content is not visible when tabs are loaded"
      );
  }
}

function setupMocks(recentTabs, syncEnabled = true) {
  const sandbox = (gSandbox = setupRecentDeviceListMocks());
  sandbox.stub(SyncedTabs, "getRecentTabs").callsFake(() => {
    info(
      `SyncedTabs.getRecentTabs will return a promise resolving to ${recentTabs.length} tabs`
    );
    return Promise.resolve(recentTabs);
  });
  return sandbox;
}

add_setup(async function () {
  registerCleanupFunction(() => {
    // reset internal state so it doesn't affect the next tests
    TabsSetupFlowManager.resetInternalState();
  });

  // gSync.init() is called in a requestIdleCallback. Force its initialization.
  gSync.init();

  registerCleanupFunction(async function () {
    Services.prefs.clearUserPref("services.sync.engine.tabs");
    await tearDown(gSandbox);
  });
});

add_task(async function test_tab_sync_loading() {
  // empty synced tabs, so we're relying on tabs.changed or sync:finish notifications to clear the waiting state
  const recentTabsData = [];
  const sandbox = setupMocks(recentTabsData);
  // stub syncTabs so it resolves to true - meaning yes it will trigger a sync, which is the case
  // we want to cover in this test.
  sandbox.stub(SyncedTabs._internal, "syncTabs").resolves(true);

  await withFirefoxView({}, async browser => {
    Services.obs.notifyObservers(null, UIState.ON_UPDATE);

    const { document } = browser.contentWindow;
    const tabsContainer = document.querySelector("#tabpickup-tabs-container");

    await waitForElementVisible(browser, "#tabpickup-steps", false);
    await waitForElementVisible(browser, "#tabpickup-tabs-container", true);
    checkMobilePromo(browser, {
      mobilePromo: false,
      mobileConfirmation: false,
    });

    ok(TabsSetupFlowManager.waitingForTabs, "waitingForTabs is true");
    checkLoadingState(browser, true);

    Services.obs.notifyObservers(null, "services.sync.tabs.changed");

    await BrowserTestUtils.waitForMutationCondition(
      tabsContainer,
      { attributeFilter: ["class"], attributes: true },
      () => {
        return !tabsContainer.classList.contains("loading");
      }
    );
    checkLoadingState(browser, false);
    checkMobilePromo(browser, {
      mobilePromo: false,
      mobileConfirmation: false,
    });
  });
  await tearDown(sandbox);
});

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 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.
  sandbox.stub(SyncedTabs._internal, "syncTabs").resolves(false);

  await withFirefoxView({}, async browser => {
    Services.obs.notifyObservers(null, UIState.ON_UPDATE);

    await waitForElementVisible(browser, "#tabpickup-steps", false);
    await waitForElementVisible(browser, "#tabpickup-tabs-container", true);

    ok(!TabsSetupFlowManager.waitingForTabs, "waitingForTabs is false");
    checkLoadingState(browser, false);
  });
  await tearDown(sandbox);
});

add_task(async function test_recent_tabs_loading() {
  // Simulate stale data by setting lastTabFetch to 10mins ago
  const TEN_MINUTES_MS = 1000 * 60 * 10;
  const staleFetchSeconds = Math.floor((Date.now() - TEN_MINUTES_MS) / 1000);
  info("updating lastFetch:" + staleFetchSeconds);
  Services.prefs.setIntPref("services.sync.lastTabFetch", staleFetchSeconds);

  // cached tabs data is available, so we shouldn't wait on lastTabFetch pref value
  const recentTabsData = structuredClone(syncedTabsData1[0].tabs);
  const sandbox = setupMocks(recentTabsData);

  await withFirefoxView({}, async browser => {
    Services.obs.notifyObservers(null, UIState.ON_UPDATE);

    await waitForElementVisible(browser, "#tabpickup-steps", false);
    await waitForElementVisible(browser, "#tabpickup-tabs-container", true);
    checkMobilePromo(browser, {
      mobilePromo: false,
      mobileConfirmation: false,
    });
    checkLoadingState(browser, false);
  });
  await tearDown(sandbox);
});