summaryrefslogtreecommitdiffstats
path: root/browser/components/extensions/test/browser/browser_ext_webNavigation_getFrames.js
blob: f72713d8fccb4ff17aa59fede23a0fd64a3beae9 (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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";

add_task(async function testWebNavigationGetNonExistentTab() {
  let extension = ExtensionTestUtils.loadExtension({
    background: async function () {
      // There is no "tabId = 0" because the id assigned by tabTracker (defined in ext-browser.js)
      // starts from 1.
      await browser.test.assertRejects(
        browser.webNavigation.getAllFrames({ tabId: 0 }),
        "Invalid tab ID: 0",
        "getAllFrames rejected Promise should pass the expected error"
      );

      // There is no "tabId = 0" because the id assigned by tabTracker (defined in ext-browser.js)
      // starts from 1, processId is currently marked as optional and it is ignored.
      await browser.test.assertRejects(
        browser.webNavigation.getFrame({
          tabId: 0,
          frameId: 15,
          processId: 20,
        }),
        "Invalid tab ID: 0",
        "getFrame rejected Promise should pass the expected error"
      );

      browser.test.sendMessage("getNonExistentTab.done");
    },
    manifest: {
      permissions: ["webNavigation"],
    },
  });

  await extension.startup();

  await extension.awaitMessage("getNonExistentTab.done");

  await extension.unload();
});

add_task(async function testWebNavigationFrames() {
  let extension = ExtensionTestUtils.loadExtension({
    background: async function () {
      let tabId;
      let collectedDetails = [];

      browser.webNavigation.onCompleted.addListener(async details => {
        collectedDetails.push(details);

        if (details.frameId !== 0) {
          // wait for the top level iframe to be complete
          return;
        }

        let getAllFramesDetails = await browser.webNavigation.getAllFrames({
          tabId,
        });

        let getFramePromises = getAllFramesDetails.map(({ frameId }) => {
          // processId is currently marked as optional and it is ignored.
          return browser.webNavigation.getFrame({
            tabId,
            frameId,
            processId: 0,
          });
        });

        let getFrameResults = await Promise.all(getFramePromises);
        browser.test.sendMessage("webNavigationFrames.done", {
          collectedDetails,
          getAllFramesDetails,
          getFrameResults,
        });

        // Pick a random frameId.
        let nonExistentFrameId = Math.floor(Math.random() * 10000);

        // Increment the picked random nonExistentFrameId until it doesn't exists.
        while (
          getAllFramesDetails.filter(
            details => details.frameId == nonExistentFrameId
          ).length
        ) {
          nonExistentFrameId += 1;
        }

        // Check that getFrame Promise is rejected with the expected error message on nonexistent frameId.
        await browser.test.assertRejects(
          browser.webNavigation.getFrame({
            tabId,
            frameId: nonExistentFrameId,
            processId: 20,
          }),
          `No frame found with frameId: ${nonExistentFrameId}`,
          "getFrame promise should be rejected with the expected error message on unexistent frameId"
        );

        await browser.tabs.remove(tabId);
        browser.test.sendMessage("webNavigationFrames.done");
      });

      let tab = await browser.tabs.create({ url: "tab.html" });
      tabId = tab.id;
    },
    manifest: {
      permissions: ["webNavigation", "tabs"],
    },
    files: {
      "tab.html": `
        <!DOCTYPE html>
        <html>
          <head>
            <meta charset="utf-8">
          </head>
          <body>
            <iframe src="subframe.html"></iframe>
            <iframe src="subframe.html"></iframe>
          </body>
        </html>
      `,
      "subframe.html": `
        <!DOCTYPE html>
        <html>
          <head>
            <meta charset="utf-8">
          </head>
        </html>
      `,
    },
  });

  await extension.startup();

  let { collectedDetails, getAllFramesDetails, getFrameResults } =
    await extension.awaitMessage("webNavigationFrames.done");

  is(getAllFramesDetails.length, 3, "expected number of frames found");
  is(
    getAllFramesDetails.length,
    collectedDetails.length,
    "number of frames found should equal the number onCompleted events collected"
  );

  is(
    getAllFramesDetails[0].frameId,
    0,
    "the root frame has the expected frameId"
  );
  is(
    getAllFramesDetails[0].parentFrameId,
    -1,
    "the root frame has the expected parentFrameId"
  );

  // ordered by frameId
  let sortByFrameId = (el1, el2) => {
    let val1 = el1 ? el1.frameId : -1;
    let val2 = el2 ? el2.frameId : -1;
    return val1 - val2;
  };

  collectedDetails = collectedDetails.sort(sortByFrameId);
  getAllFramesDetails = getAllFramesDetails.sort(sortByFrameId);
  getFrameResults = getFrameResults.sort(sortByFrameId);

  info("check frame details content");

  is(
    getFrameResults.length,
    getAllFramesDetails.length,
    "getFrame and getAllFrames should return the same number of results"
  );

  Assert.deepEqual(
    getFrameResults,
    getAllFramesDetails,
    "getFrame and getAllFrames should return the same results"
  );

  info(`check frame details collected and retrieved with getAllFrames`);

  for (let [i, collected] of collectedDetails.entries()) {
    let getAllFramesDetail = getAllFramesDetails[i];

    is(getAllFramesDetail.frameId, collected.frameId, "frameId");
    is(
      getAllFramesDetail.parentFrameId,
      collected.parentFrameId,
      "parentFrameId"
    );
    is(getAllFramesDetail.tabId, collected.tabId, "tabId");

    // This can be uncommented once Bug 1246125 has been fixed
    // is(getAllFramesDetail.url, collected.url, "url");
  }

  info("frame details content checked");

  await extension.awaitMessage("webNavigationFrames.done");

  await extension.unload();
});

add_task(async function testWebNavigationGetFrameOnDiscardedTab() {
  const extension = ExtensionTestUtils.loadExtension({
    manifest: {
      permissions: ["tabs", "webNavigation"],
    },
    async background() {
      let tabs = await browser.tabs.query({ currentWindow: true });
      browser.test.assertEq(2, tabs.length, "Expect 2 tabs open");

      const tabId = tabs[1].id;

      await browser.tabs.discard(tabId);
      let tab = await browser.tabs.get(tabId);
      browser.test.assertEq(true, tab.discarded, "Expect a discarded tab");

      const allFrames = await browser.webNavigation.getAllFrames({ tabId });
      browser.test.assertEq(
        null,
        allFrames,
        "Expect null from calling getAllFrames on discarded tab"
      );

      tab = await browser.tabs.get(tabId);
      browser.test.assertEq(
        true,
        tab.discarded,
        "Expect tab to stay discarded"
      );

      const topFrame = await browser.webNavigation.getFrame({
        tabId,
        frameId: 0,
      });
      browser.test.assertEq(
        null,
        topFrame,
        "Expect null from calling getFrame on discarded tab"
      );

      tab = await browser.tabs.get(tabId);
      browser.test.assertEq(
        true,
        tab.discarded,
        "Expect tab to stay discarded"
      );

      browser.test.sendMessage("get-frames-done");
    },
  });

  const initialTab = gBrowser.selectedTab;
  const tab = await BrowserTestUtils.openNewForegroundTab(
    gBrowser,
    "http://mochi.test:8888/?toBeDiscarded=true"
  );
  // Switch back to the initial tab to allow the new tab
  // to be discarded.
  await BrowserTestUtils.switchTab(gBrowser, initialTab);

  ok(!!tab.linkedPanel, "Tab not initially discarded");

  await extension.startup();
  await extension.awaitMessage("get-frames-done");

  ok(!tab.linkedPanel, "Tab should be discarded");

  BrowserTestUtils.removeTab(tab);

  await extension.unload();
});

add_task(async function testWebNavigationCrossOriginFrames() {
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      permissions: ["webNavigation"],
    },
    async background() {
      let url =
        "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest/file_contains_iframe.html";
      let tab = await browser.tabs.create({ url });

      await new Promise(resolve => {
        browser.webNavigation.onCompleted.addListener(details => {
          if (details.tabId === tab.id && details.frameId === 0) {
            resolve();
          }
        });
      });

      let frames = await browser.webNavigation.getAllFrames({ tabId: tab.id });
      browser.test.assertEq(frames[0].url, url, "Top is from mochi.test");

      await browser.tabs.remove(tab.id);
      browser.test.sendMessage("webNavigation.CrossOriginFrames", frames);
    },
  });

  await extension.startup();

  let frames = await extension.awaitMessage("webNavigation.CrossOriginFrames");
  is(frames.length, 2, "getAllFrames() returns both frames.");

  is(frames[0].frameId, 0, "Top frame has correct frameId.");
  is(frames[0].parentFrameId, -1, "Top parentFrameId is correct.");

  ok(frames[1].frameId > 0, "Cross-origin iframe has non-zero frameId.");
  is(frames[1].parentFrameId, 0, "Iframe parentFrameId is correct.");
  is(
    frames[1].url,
    "http://example.org/tests/toolkit/components/extensions/test/mochitest/file_contains_img.html",
    "Irame is from example.org"
  );

  await extension.unload();
});