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

"use strict";

const URL = HTTPROOT + "browser_frametree_sample.html";
const URL_FRAMESET = HTTPROOT + "browser_frametree_sample_frameset.html";

/**
 * This ensures that loading a page normally, aborting a page load, reloading
 * a page, navigating using the bfcache, and ignoring frames that were
 * created dynamically work as expect. We expect the frame tree to be reset
 * when a page starts loading and we also expect a valid frame tree to exist
 * when it has stopped loading.
 */
add_task(function test_frametree() {
  const FRAME_TREE_SINGLE = { href: URL };
  const FRAME_TREE_FRAMESET = {
    href: URL_FRAMESET,
    children: [{href: URL}, {href: URL}, {href: URL}]
  };

  // Create a tab with a single frame.
  let tab = gBrowser.addTab(URL);
  let browser = tab.linkedBrowser;
  yield promiseNewFrameTree(browser);
  yield checkFrameTree(browser, FRAME_TREE_SINGLE,
    "loading a page resets and creates the frame tree correctly");

  // Load the frameset and create two frames dynamically, the first on
  // DOMContentLoaded and the second on load.
  yield sendMessage(browser, "ss-test:createDynamicFrames", {id: "frames", url: URL});
  browser.loadURI(URL_FRAMESET);
  yield promiseNewFrameTree(browser);
  yield checkFrameTree(browser, FRAME_TREE_FRAMESET,
    "dynamic frames created on or after the load event are ignored");

  // Go back to the previous single-frame page. There will be no load event as
  // the page is still in the bfcache. We thus make sure this type of navigation
  // resets the frame tree.
  browser.goBack();
  yield promiseNewFrameTree(browser);
  yield checkFrameTree(browser, FRAME_TREE_SINGLE,
    "loading from bfache resets and creates the frame tree correctly");

  // Load the frameset again but abort the load early.
  // The frame tree should still be reset and created.
  browser.loadURI(URL_FRAMESET);
  executeSoon(() => browser.stop());
  yield promiseNewFrameTree(browser);

  // Load the frameset and check the tree again.
  yield sendMessage(browser, "ss-test:createDynamicFrames", {id: "frames", url: URL});
  browser.loadURI(URL_FRAMESET);
  yield promiseNewFrameTree(browser);
  yield checkFrameTree(browser, FRAME_TREE_FRAMESET,
    "reloading a page resets and creates the frame tree correctly");

  // Cleanup.
  gBrowser.removeTab(tab);
});

/**
 * This test ensures that we ignore frames that were created dynamically at or
 * after the load event. SessionStore can't handle these and will not restore
 * or collect any data for them.
 */
add_task(function test_frametree_dynamic() {
  // The frame tree as expected. The first two frames are static
  // and the third one was created on DOMContentLoaded.
  const FRAME_TREE = {
    href: URL_FRAMESET,
    children: [{href: URL}, {href: URL}, {href: URL}]
  };
  const FRAME_TREE_REMOVED = {
    href: URL_FRAMESET,
    children: [{href: URL}, {href: URL}]
  };

  // Add an empty tab for a start.
  let tab = gBrowser.addTab("about:blank");
  let browser = tab.linkedBrowser;
  yield promiseBrowserLoaded(browser);

  // Create dynamic frames on "DOMContentLoaded" and on "load".
  yield sendMessage(browser, "ss-test:createDynamicFrames", {id: "frames", url: URL});
  browser.loadURI(URL_FRAMESET);
  yield promiseNewFrameTree(browser);

  // Check that the frame tree does not contain the frame created on "load".
  // The two static frames and the one created on DOMContentLoaded must be in
  // the tree.
  yield checkFrameTree(browser, FRAME_TREE,
    "frame tree contains first four frames");

  // Remove the last frame in the frameset.
  yield sendMessage(browser, "ss-test:removeLastFrame", {id: "frames"});
  // Check that the frame tree didn't change.
  yield checkFrameTree(browser, FRAME_TREE,
    "frame tree contains first four frames");

  // Remove the last frame in the frameset.
  yield sendMessage(browser, "ss-test:removeLastFrame", {id: "frames"});
  // Check that the frame tree excludes the removed frame.
  yield checkFrameTree(browser, FRAME_TREE_REMOVED,
    "frame tree contains first three frames");

  // Cleanup.
  gBrowser.removeTab(tab);
});

/**
 * Checks whether the current frame hierarchy of a given |browser| matches the
 * |expected| frame hierarchy.
 */
function checkFrameTree(browser, expected, msg) {
  return sendMessage(browser, "ss-test:mapFrameTree").then(tree => {
    is(JSON.stringify(tree), JSON.stringify(expected), msg);
  });
}

/**
 * Returns a promise that will be resolved when the given |browser| has loaded
 * and we received messages saying that its frame tree has been reset and
 * recollected.
 */
function promiseNewFrameTree(browser) {
  let reset = promiseContentMessage(browser, "ss-test:onFrameTreeCollected");
  let collect = promiseContentMessage(browser, "ss-test:onFrameTreeCollected");
  return Promise.all([reset, collect]);
}