summaryrefslogtreecommitdiffstats
path: root/browser/components/sessionstore/test/browser_broadcast.js
blob: 02f3bc59e74430dcbab74774d280df89473a7d65 (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
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

const INITIAL_VALUE = "browser_broadcast.js-initial-value-" + Date.now();

/**
 * This test ensures we won't lose tab data queued in the content script when
 * closing a tab.
 */
add_task(async function flush_on_tabclose() {
  let tab = await createTabWithStorageData(["http://example.com/"]);
  let browser = tab.linkedBrowser;

  await modifySessionStorage(browser, { test: "on-tab-close" });
  await TabStateFlusher.flush(browser);
  await promiseRemoveTabAndSessionState(tab);

  let [
    {
      state: { storage },
    },
  ] = ss.getClosedTabDataForWindow(window);
  is(
    storage["http://example.com"].test,
    "on-tab-close",
    "sessionStorage data has been flushed on TabClose"
  );
});

/**
 * This test ensures we won't lose tab data queued in the content script when
 * duplicating a tab.
 */
add_task(async function flush_on_duplicate() {
  let tab = await createTabWithStorageData(["http://example.com/"]);
  let browser = tab.linkedBrowser;

  await modifySessionStorage(browser, { test: "on-duplicate" });
  let tab2 = ss.duplicateTab(window, tab);
  await promiseTabRestored(tab2);

  await promiseRemoveTabAndSessionState(tab2);
  let [
    {
      state: { storage },
    },
  ] = ss.getClosedTabDataForWindow(window);
  is(
    storage["http://example.com"].test,
    "on-duplicate",
    "sessionStorage data has been flushed when duplicating tabs"
  );

  gBrowser.removeTab(tab);
});

/**
 * This test ensures we won't lose tab data queued in the content script when
 * a window is closed.
 */
add_task(async function flush_on_windowclose() {
  let win = await promiseNewWindow();
  let tab = await createTabWithStorageData(["http://example.com/"], win);
  let browser = tab.linkedBrowser;

  await modifySessionStorage(browser, { test: "on-window-close" });
  await BrowserTestUtils.closeWindow(win);

  let [
    {
      tabs: [, { storage }],
    },
  ] = ss.getClosedWindowData();
  is(
    storage["http://example.com"].test,
    "on-window-close",
    "sessionStorage data has been flushed when closing a window"
  );
});

/**
 * This test ensures that stale tab data is ignored when reusing a tab
 * (via e.g. setTabState) and does not overwrite the new data.
 */
add_task(async function flush_on_settabstate() {
  let tab = await createTabWithStorageData(["http://example.com/"]);
  let browser = tab.linkedBrowser;

  // Flush to make sure our tab state is up-to-date.
  await TabStateFlusher.flush(browser);

  let state = ss.getTabState(tab);
  await modifySessionStorage(browser, { test: "on-set-tab-state" });

  // Flush all data contained in the content script but send it using
  // asynchronous messages.
  TabStateFlusher.flush(browser);

  await promiseTabState(tab, state);

  let { storage } = JSON.parse(ss.getTabState(tab));
  is(
    storage["http://example.com"].test,
    INITIAL_VALUE,
    "sessionStorage data has not been overwritten"
  );

  gBrowser.removeTab(tab);
});

/**
 * This test ensures that we won't lose tab data that has been sent
 * asynchronously just before closing a tab. Flushing must re-send all data
 * that hasn't been received by chrome, yet.
 */
add_task(async function flush_on_tabclose_racy() {
  let tab = await createTabWithStorageData(["http://example.com/"]);
  let browser = tab.linkedBrowser;

  // Flush to make sure we start with an empty queue.
  await TabStateFlusher.flush(browser);

  await modifySessionStorage(browser, { test: "on-tab-close-racy" });

  // Flush all data contained in the content script but send it using
  // asynchronous messages.
  TabStateFlusher.flush(browser);
  await promiseRemoveTabAndSessionState(tab);

  let [
    {
      state: { storage },
    },
  ] = ss.getClosedTabDataForWindow(window);
  is(
    storage["http://example.com"].test,
    "on-tab-close-racy",
    "sessionStorage data has been merged correctly to prevent data loss"
  );
});

function promiseNewWindow() {
  return new Promise(resolve => {
    whenNewWindowLoaded({ private: false }, resolve);
  });
}

async function createTabWithStorageData(urls, win = window) {
  let tab = BrowserTestUtils.addTab(win.gBrowser);
  let browser = tab.linkedBrowser;

  for (let url of urls) {
    BrowserTestUtils.loadURIString(browser, url);
    await promiseBrowserLoaded(browser, true, url);
    dump("Loaded url: " + url + "\n");
    await modifySessionStorage(browser, { test: INITIAL_VALUE });
  }

  return tab;
}