summaryrefslogtreecommitdiffstats
path: root/dom/bindings/test/test_dom_xrays.html
blob: 15d7013adebb06d112694530ec838be0fc271e9e (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
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=787070
-->
<head>
  <meta charset="utf-8">
  <title>Test for Bug 787070</title>
  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=787070">Mozilla Bug 787070</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe id="t" src="http://example.org/tests/dom/bindings/test/file_dom_xrays.html"></iframe>
</div>
<pre id="test">
<script type="application/javascript">

/** Test for Bug 1021066 **/

var Cu = Components.utils;

// values should contain the values that the property should have on each of
// the objects on the prototype chain of obj. A value of undefined signals
// that the value should not be present on that prototype.
function checkXrayProperty(obj, name, values)
{
  var instance = obj;
  do {
    var value = values.shift();
    if (typeof value == "undefined") {
      ok(!obj.hasOwnProperty(name), "hasOwnProperty shouldn't see \"" + name + "\" through Xrays");
      is(Object.getOwnPropertyDescriptor(obj, name), undefined, "getOwnPropertyDescriptor shouldn't see \"" + name + "\" through Xrays");
      ok(Object.keys(obj).indexOf(name) == -1, "Enumerating the Xray should not return \"" + name + "\"");
    } else {
      ok(obj.hasOwnProperty(name), "hasOwnProperty should see \"" + name + "\" through Xrays");
      var pd = Object.getOwnPropertyDescriptor(obj, name);
      ok(pd, "getOwnPropertyDescriptor should see \"" + name + "\" through Xrays");
      if (pd && pd.get) {
        is(pd.get.call(instance), value, "Should get the right value for \"" + name + "\" through Xrays");
      } else {
        is(obj[name], value, "Should get the right value for \"" + name + "\" through Xrays");
      }
      if (pd && pd.enumerable) {
        ok(Object.keys(obj).indexOf("" + name) > -1, "Enumerating the Xray should return \"" + name + "\"");
      }
    }
  } while ((obj = Object.getPrototypeOf(obj)));
}

function checkWindowXrayProperty(obj, name, windowValue, windowPrototypeValue, namedPropertiesValue, eventTargetValue)
{
  checkXrayProperty(obj, name, [ windowValue, windowPrototypeValue, namedPropertiesValue, eventTargetValue ]);
}

function test()
{
  // Window
  var win = document.getElementById("t").contentWindow;
  var doc = document.getElementById("t").contentDocument;

  var winProto = Object.getPrototypeOf(win);
  is(winProto, win.Window.prototype, "The proto chain of the Xray should mirror the prototype chain of the Xrayed object");

  var namedPropertiesObject = Object.getPrototypeOf(winProto);
  is(Cu.getClassName(namedPropertiesObject, /* unwrap = */ true), "WindowProperties", "The proto chain of the Xray should mirror the prototype chain of the Xrayed object");

  var eventTargetProto = Object.getPrototypeOf(namedPropertiesObject);
  is(eventTargetProto, win.EventTarget.prototype, "The proto chain of the Xray should mirror the prototype chain of the Xrayed object");

  // Xrays need to filter expandos.
  checkWindowXrayProperty(win, "expando", undefined);
  ok(!("expando" in win), "Xrays should filter expandos");

  checkWindowXrayProperty(win, "shadowedIframe", undefined, undefined, doc.getElementById("shadowedIframe").contentWindow);
  ok("shadowedIframe" in win, "Named properties should be exposed through Xrays");

  // Named properties live on the named properties object for global objects.
  checkWindowXrayProperty(win, "iframe", undefined, undefined, doc.getElementById("iframe").contentWindow);
  ok("iframe" in win, "Named properties should be exposed through Xrays");

  // Window properties live on the instance, shadowing the properties of the named property object.
  checkWindowXrayProperty(win, "document", doc, undefined, doc.getElementById("document").contentWindow);
  ok("document" in win, "WebIDL properties should be exposed through Xrays");

  // Unforgeable properties live on the instance, shadowing the properties of the named property object.
  checkWindowXrayProperty(win, "self", win, undefined, doc.getElementById("self").contentWindow);
  ok("self" in win, "WebIDL properties should be exposed through Xrays");

  // Object.prototype is at the end of the prototype chain.
  var obj = win;
  while ((proto = Object.getPrototypeOf(obj))) {
    obj = proto;
  }
  is(obj, win.Object.prototype, "Object.prototype should be at the end of the prototype chain");

  // Named properties shouldn't shadow WebIDL- or ECMAScript-defined properties.
  checkWindowXrayProperty(win, "addEventListener", undefined, undefined, undefined, eventTargetProto.addEventListener);
  is(win.addEventListener, eventTargetProto.addEventListener, "Named properties shouldn't shadow WebIDL-defined properties");

  is(win.toString, win.Object.prototype.toString, "Named properties shouldn't shadow ECMAScript-defined properties");

  // HTMLDocument
  // Unforgeable properties live on the instance.
  checkXrayProperty(doc, "location", [ win.location ]);
  is(String(win.location), document.getElementById("t").src,
     "Should have the right stringification");

  // HTMLHtmlElement
  var elem = doc.documentElement;

  var elemProto = Object.getPrototypeOf(elem);
  is(elemProto, win.HTMLHtmlElement.prototype, "The proto chain of the Xray should mirror the prototype chain of the Xrayed object");

  elemProto = Object.getPrototypeOf(elemProto);
  is(elemProto, win.HTMLElement.prototype, "The proto chain of the Xray should mirror the prototype chain of the Xrayed object");

  elemProto = Object.getPrototypeOf(elemProto);
  is(elemProto, win.Element.prototype, "The proto chain of the Xray should mirror the prototype chain of the Xrayed object");

  elemProto = Object.getPrototypeOf(elemProto);
  is(elemProto, win.Node.prototype, "The proto chain of the Xray should mirror the prototype chain of the Xrayed object");

  elemProto = Object.getPrototypeOf(elemProto);
  is(elemProto, win.EventTarget.prototype, "The proto chain of the Xray should mirror the prototype chain of the Xrayed object");

  // Xrays need to filter expandos.
  ok(!("expando" in elem), "Xrays should filter expandos");

  // WebIDL-defined properties live on the prototype.
  checkXrayProperty(elem, "version", [ undefined, "" ]);
  is(elem.version, "", "WebIDL properties should be exposed through Xrays");

  // HTMLCollection
  var coll = doc.getElementsByTagName("iframe");

  // Named properties live on the instance for non-global objects.
  checkXrayProperty(coll, "iframe", [ doc.getElementById("iframe") ]);

  // Indexed properties live on the instance.
  checkXrayProperty(coll, 0, [ doc.getElementById("shadowedIframe") ]);

  // WebIDL-defined properties live on the prototype, overriding any named properties.
  checkXrayProperty(coll, "item", [ undefined, win.HTMLCollection.prototype.item ]);

  // ECMAScript-defined properties live on the prototype, overriding any named properties.
  checkXrayProperty(coll, "toString", [ undefined, undefined, win.Object.prototype.toString ]);

  // Frozen arrays should come from our compartment, not the target one.
  var languages1 = win.navigator.languages;
  isnot(languages1, undefined, "Must have .languages");
  ok(Array.isArray(languages1), ".languages should be an array");
  ok(Object.isFrozen(languages1), ".languages should be a frozen array");
  ok(!Cu.isXrayWrapper(languages1), "Should have our own version of array");
  is(Cu.getGlobalForObject(languages1), window,
     "languages1 should come from our window");
  // We want to get .languages in the content compartment, but without waiving
  // Xrays altogether.
  var languages2 = win.eval("navigator.languages");
  isnot(languages2, undefined, "Must still have .languages");
  ok(Array.isArray(languages2), ".languages should still be an array");
  ok(Cu.isXrayWrapper(languages2), "Should have xray for content version of array");
  is(Cu.getGlobalForObject(languages2), win,
     "languages2 come from the underlying window");
  ok(Object.isFrozen(languages2.wrappedJSObject),
     ".languages should still be a frozen array underneath");
  isnot(languages1, languages2, "Must have distinct arrays");
  isnot(languages1, languages2.wrappedJSObject,
        "Must have distinct arrays no matter how we slice it");

  // Check that DataTransfer's .types has the hack to alias contains()
  // to includes().
  var dataTransfer = new win.DataTransfer();
  is(dataTransfer.types.contains, dataTransfer.types.includes,
     "Should have contains() set up as an alias to includes()");
  // Waive Xrays on the dataTransfer itself, since the .types we get is
  // different over Xrays vs not.
  is(dataTransfer.wrappedJSObject.types.contains, undefined,
     "Underlying object should not have contains() set up as an alias to " +
     "includes()");

  // Check that deleters work correctly in the [OverrideBuiltins] case.
  var elem = win.document.documentElement;
  var dataset = elem.dataset;
  is(dataset.foo, undefined, "Should not have a 'foo' property");
  ok(!('foo' in dataset), "Really should not have a 'foo' property");
  is(elem.getAttribute("data-foo"), null,
     "Should not have a 'data-foo' attribute");
  ok(!elem.hasAttribute("data-foo"),
     "Really should not have a 'data-foo' attribute");
  dataset.foo = "bar";
  is(dataset.foo, "bar", "Should now have a 'foo' property");
  ok('foo' in dataset, "Really should have a 'foo' property");
  is(elem.getAttribute("data-foo"), "bar",
     "Should have a 'data-foo' attribute");
  ok(elem.hasAttribute("data-foo"),
     "Really should have a 'data-foo' attribute");
  delete dataset.foo;
  is(dataset.foo, undefined, "Should not have a 'foo' property again");
  ok(!('foo' in dataset), "Really should not have a 'foo' property again");
  is(elem.getAttribute("data-foo"), null,
     "Should not have a 'data-foo' attribute again");
  ok(!elem.hasAttribute("data-foo"),
     "Really should not have a 'data-foo' attribute again");

  // Check that deleters work correctly in the non-[OverrideBuiltins] case.
  var storage = win.sessionStorage;
  is(storage.foo, undefined, "Should not have a 'foo' property");
  ok(!('foo' in storage), "Really should not have a 'foo' property");
  is(storage.getItem("foo"), null, "Should not have an item named 'foo'");
  storage.foo = "bar";
  is(storage.foo, "bar", "Should have a 'foo' property");
  ok('foo' in storage, "Really should have a 'foo' property");
  is(storage.getItem("foo"), "bar", "Should have an item named 'foo'");
  delete storage.foo
  is(storage.foo, undefined, "Should not have a 'foo' property again");
  ok(!('foo' in storage), "Really should not have a 'foo' property again");
  is(storage.getItem("foo"), null, "Should not have an item named 'foo' again");

  SimpleTest.finish();
}

SimpleTest.waitForExplicitFinish();
addLoadEvent(test);

</script>
</pre>
</body>
</html>