Bug 1556663 [wpt PR 17159] - Add optional test for cloning of error stacks, a=testonly
[gecko.git] / testing / web-platform / tests / html / infrastructure / safe-passing-of-structured-data / structuredclone_0.html
blob098283106ef87da88629a8f5b1f14b6d235171ed
1 <!doctype html>
2 <html>
3 <head>
4 <meta content="text/html; charset=utf-8" http-equiv="content-type" />
5 <title>2.8 Common DOM interfaces - Structured Clone Algorithm </title>
6 <link rel="help" href="http://www.w3.org/TR/html5/common-dom-interfaces.html#safe-passing-of-structured-data" />
7 <script src="/resources/testharness.js"></script>
8 <script src="/resources/testharnessreport.js"></script>
9 </head>
10 <body>
11 <div id="log"></div>
13 <script type="text/javascript">
14 var worker;
15 var testCollection;
16 setup(function()
18 //the worker is used for each test in sequence
19 //worker's callback will be set for each test
20 //worker's internal onmessage echoes the data back to this thread through postMessage
21 worker = new Worker("./resources/echo-worker.js");
22 testCollection = [
23 function() {
24 var t = async_test("Primitive string is cloned");
25 t.id = 0;
26 worker.onmessage = t.step_func(function(e) {assert_equals("primitive string", e.data, "\"primitive string\" === event.data"); t.done(); });
27 t.step(function() { worker.postMessage("primitive string");});
29 function() {
30 var t = async_test("Primitive integer is cloned");
31 t.id = 1;
32 worker.onmessage = t.step_func(function(e) {assert_equals(2000, e.data, "2000 === event.data"); t.done(); });
33 t.step(function() { worker.postMessage(2000);});
35 function() {
36 var t = async_test("Primitive floating point is cloned");
37 t.id = 2;
38 worker.onmessage = t.step_func(function(e) {assert_equals(111.456, e.data, "111.456 === event.data"); t.done(); });
39 t.step(function() { worker.postMessage(111.456);});
41 function() {
42 var t = async_test("Primitive floating point (negative) is cloned");
43 t.id = 3;
44 worker.onmessage = t.step_func(function(e) {assert_equals(-111.456, e.data, "-111.456 === event.data"); t.done(); });
45 t.step(function() { worker.postMessage(-111.456);});
47 function() {
48 var t = async_test("Primitive number (hex) is cloned");
49 t.id = 4;
50 worker.onmessage = t.step_func(function(e) {assert_equals(0xAB25, e.data, "0xAB25 === event.data"); t.done(); });
51 t.step(function() { worker.postMessage(0xAB25);});
53 function() {
54 var t = async_test("Primitive number (scientific) is cloned");
55 t.id = 5;
56 worker.onmessage = t.step_func(function(e) {assert_equals(15e2, e.data, "15e2 === event.data"); t.done(); });
57 t.step(function() { worker.postMessage(15e2);});
59 function() {
60 var t = async_test("Primitive boolean is cloned");
61 t.id = 6;
62 worker.onmessage = t.step_func(function(e) {assert_equals(false, e.data, "false === event.data"); t.done(); });
63 t.step(function() { worker.postMessage(false);});
65 function() {
66 var t = async_test("Instance of Boolean is cloned");
67 t.id = 7;
68 var obj;
69 t.step(function() {obj = new Boolean(false);});
70 worker.onmessage = t.step_func(function(e) {
71 assert_equals(obj.constructor, e.data.constructor, "Boolean === event.data.constructor");
72 assert_equals(obj.valueOf(), e.data.valueOf(), "(new Boolean(false)).valueof() === event.data.valueOf()");
73 t.done();
74 });
75 t.step(function() { worker.postMessage(obj);});
76 },function() {
77 var t = async_test("Instance of Number is cloned");
78 t.id = 8;
79 var obj;
80 t.step(function() {obj = new Number(2000);});
81 worker.onmessage = t.step_func(function(e) {
82 assert_equals(obj.constructor, e.data.constructor, "Number === event.data.constructor");
83 assert_equals(obj.valueOf(), e.data.valueOf(), "(new Number(2000)).valueof() === event.data.valueOf()");
84 t.done();
85 });
86 t.step(function() { worker.postMessage(obj);});
88 function() {
89 var t = async_test("Instance of String is cloned");
90 t.id = 9;
91 var obj;
92 t.step(function() { obj = new String("String Object");});
93 worker.onmessage = t.step_func(function(e) {
94 assert_equals(obj.constructor, e.data.constructor, "String === event.data.constructor");
95 assert_equals(obj.valueOf(), e.data.valueOf(), "(new String(\"String Object\")).valueof() === event.data.valueOf()");
96 t.done();
97 });
98 t.step(function() { worker.postMessage(obj);});
100 function() {
101 var t = async_test("Instance of Date is cloned");
102 t.id = 10;
103 var obj;
104 t.step(function() { obj= new Date(2011,1,1);});
105 worker.onmessage = t.step_func(function(e) {
106 assert_equals(obj.constructor, e.data.constructor, "Date === event.data.constructor");
107 assert_equals(obj.valueOf(), e.data.valueOf(), "(new Date(2011,1,1)).valueof() === event.data.valueOf()");
108 t.done();
110 t.step(function() { worker.postMessage(obj);});
112 function() {
113 var t = async_test("Instance of RegExp is cloned");
114 t.id = 11;
115 var obj;
116 t.step(function() {obj = new RegExp("w3+c","g","i");});
117 worker.onmessage = t.step_func(function(e) {
118 assert_equals(obj.constructor, e.data.constructor, "RegExp === event.data.constructor");
119 assert_equals(obj.source, e.data.source, "canon.source === event.data.source");
120 assert_equals(obj.multiline, e.data.multiline, "canon.multiline === event.data.multiline");
121 assert_equals(obj.global, e.data.global, "canon.global === event.data.global");
122 assert_equals(obj.ignoreCase, e.data.ignoreCase, "canon.ignoreCase === event.data.ignoreCase");
123 t.done();
125 t.step(function() { worker.postMessage(obj);});
127 function() {
128 var t = async_test("Value 'null' is cloned");
129 t.id = 12;
130 worker.onmessage = t.step_func(function(e) {assert_equals(null, e.data, "null === event.data"); t.done(); });
131 t.step(function() { worker.postMessage(null);});
133 function() {
134 var t = async_test("Value 'undefined' is cloned");
135 t.id = 13;
136 worker.onmessage = t.step_func(function(e) {assert_equals(undefined, e.data, "undefined === event.data"); t.done(); });
137 t.step(function() { worker.postMessage(undefined);});
139 function() {
140 var t = async_test("Object properties are cloned");
141 t.id = 14;
142 var obj;
143 t.step(function() {
144 obj= {};
145 obj.a = "test";
146 obj.b = 2;
147 obj["child"] = 3;
149 worker.onmessage = t.step_func(function(e) {
150 assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
151 assert_equals(obj.a, e.data.a, "canon.a === event.data.a");
152 assert_equals(obj.b, e.data.b, "canon.b === event.data.b");
153 assert_equals(obj.child, e.data.child, "canon.child === e.data.child");
154 t.done();
156 t.step(function() { worker.postMessage(obj);});
158 function() {
159 var t = async_test("Prototype chains are not walked.");
160 t.id = 15;
161 function Custom() {
162 this.a = "hello";
165 var obj;
166 t.step(function() {
167 Object.defineProperty(Custom.prototype, "b", { enumerable: true, value: 100 });
168 obj = new Custom();
170 worker.onmessage = t.step_func(function(e) {
171 assert_not_equals(obj.constructor, e.data.constructor, "canon.constructor !== event.data.constructor");
172 assert_equals(Object, e.data.constructor, "Object === e.data.constructor");
173 assert_equals(obj.a, e.data.a, "canon.a === e.data.a");
174 assert_equals(undefined, e.data.b, "undefined === e.data.b");
175 t.done();
177 t.step(function() { worker.postMessage(obj);});
179 function() {
180 var t = async_test("Property descriptors of Objects are not cloned");
181 t.id = 16;
182 var obj;
183 t.step(function() {
184 obj = {};
185 Object.defineProperty(obj, "a", { enumerable: true, writable: false, value: 100 });
187 worker.onmessage = t.step_func(function(e) {
188 var des = Object.getOwnPropertyDescriptor(e.data, "a");
189 assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
190 assert_true(des.writable, "Descriptor is writable");
191 t.done();
193 t.step(function() { worker.postMessage(obj);});
195 function() {
196 var t = async_test("Cycles are preserved in Objects");
197 t.id = 17;
198 var obj;
199 t.step(function() {
200 obj = {};
201 obj.a = obj;
203 worker.onmessage = t.step_func(function(e) {
204 assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
205 assert_equals(e.data, e.data.a, "cycle is preserved");
206 t.done();
208 t.step(function() { worker.postMessage(obj);});
210 function() {
211 var t = async_test("Identity of duplicates is preserved");
212 t.id = 18;
213 var ref;
214 var obj;
215 t.step(function() {
216 ref = {};
217 ref.called = 0;
218 Object.defineProperty(ref, "child", {get: function(){this.called++;}, enumerable: true});
220 obj = {a:ref, b:ref};
222 worker.onmessage = t.step_func(function(e) {
223 assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
224 assert_equals(e.data.b.called, 0, "e.data.b.called === 0");
225 t.done();
227 t.step(function() { worker.postMessage(obj);});
229 function() {
230 var t = async_test("Property order is preserved");
231 t.id = 19;
232 var obj;
233 t.step(function() {
234 obj = { "a": "hello", "b": "w3c", "c": "and world" };
235 obj["a"] = "named1";
237 worker.onmessage = t.step_func(function(e) {
238 assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
239 var canonNames = Object.getOwnPropertyNames(obj);
240 var testNames = Object.getOwnPropertyNames(e.data);
241 for (var i in canonNames) {
242 assert_equals(canonNames[i], testNames[i], "canonProperty["+i+"] === dataProperty["+i+"]");
244 t.done();
246 t.step(function() { worker.postMessage(obj);});
248 function() {
249 var t = async_test("Enumerable properties of Arrays are cloned");
250 t.id = 20;
251 var obj;
252 t.step(function() {
253 obj = [0,1];
254 obj["a"] = "named1";
256 worker.onmessage = t.step_func(function(e) {
257 assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
258 assert_equals(e.data["a"], "named1", "e.data[\"a\"] === \"named1\"");
259 assert_equals(e.data[0], 0, "e.data[0] === 0");
260 assert_equals(e.data[1], 1, "e.data[1] === 1");
261 t.done();
263 t.step(function() { worker.postMessage(obj);});
265 function() {
266 var t = async_test("Property descriptors of Arrays are not cloned");
267 t.id = 21;
268 var obj;
269 t.step(function() {
270 obj = [0, 1];
271 Object.defineProperty(obj, "2", { enumerable: true, writable: false, value: 100 });
273 worker.onmessage = t.step_func(function(e) {
274 assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
275 assert_equals(e.data[0], 0, "e.data[0] === 0");
276 assert_equals(e.data[1], 1, "e.data[1] === 1");
277 var des = Object.getOwnPropertyDescriptor(e.data, "2");
278 assert_true(des.writable, "Descriptor is writable");
279 t.done();
281 t.step(function() { worker.postMessage(obj);});
283 function() {
284 var t = async_test("Cycles are preserved in Arrays");
285 t.id = 22;
286 var obj;
287 t.step(function() {
288 obj = [0,1];
289 obj[2] = obj;
291 worker.onmessage = t.step_func(function(e) {
292 assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
293 assert_equals(e.data[0], 0, "e.data[0] === 0");
294 assert_equals(e.data[1], 1, "e.data[1] === 1");
295 assert_equals(e.data[2], e.data, "e.data[2] === e.data");
296 t.done();
298 t.step(function() { worker.postMessage(obj);});
301 function() {
302 var t = async_test("ImageData object can be cloned");
303 t.id = 23;
304 var obj;
305 t.step(function() {
306 var canvas = document.createElement("canvas");
307 canvas.width = 40;
308 canvas.height = 40;
309 var context = canvas.getContext('2d');
310 obj = context.createImageData(40, 40);
311 assert_true(window.hasOwnProperty("ImageData"), "ImageData constructor must be present");
312 assert_true(obj instanceof ImageData, "ImageData must be returned by .createImageData");
314 worker.onmessage = t.step_func(function(e) {
315 assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
316 assert_not_equals(obj, e.data, "cloned object should be a new instance of ImageData");
317 assert_equals(obj.width, e.data.width, "canon.width === e.data.width");
318 assert_equals(obj.height, e.data.height, "canon.height === e.data.height");
319 assert_array_equals(obj.data, e.data.data, "data arrays are the same");
320 t.done();
322 t.step(function() { worker.postMessage(obj);});
324 function() {
325 var t = async_test("ImageData expandos are not cloned");
326 t.id = 24;
327 var obj;
328 t.step(function() {
329 var canvas = document.createElement("canvas");
330 canvas.width = 40;
331 canvas.height = 40;
332 var context = canvas.getContext('2d');
333 obj = context.createImageData(40, 40);
334 assert_true(window.hasOwnProperty("ImageData"), "ImageData constructor must be present");
335 assert_true(obj instanceof ImageData, "ImageData must be returned by .createImageData");
336 obj.foo = "bar";
338 worker.onmessage = t.step_func(function(e) {
339 assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
340 assert_not_equals(obj, e.data, "cloned object should be a new instance of ImageData");
341 assert_equals(obj.width, e.data.width, "canon.width === e.data.width");
342 assert_equals(obj.height, e.data.height, "canon.height === e.data.height");
343 assert_array_equals(obj.data, e.data.data, "data arrays are the same");
344 assert_equals(undefined, e.data.foo, "Expando is lost (undefined === e.data.foo)");
345 t.done();
347 t.step(function() { worker.postMessage(obj);});
349 function() {
350 var t = async_test("Window objects cannot be cloned");
351 t.id = 25;
352 worker.onmessage = function() {}; //no op because exception should be thrown.
353 t.step(function() {
354 assert_true(DOMException.hasOwnProperty('DATA_CLONE_ERR'), "DOMException.DATA_CLONE_ERR is present");
355 assert_equals(DOMException.DATA_CLONE_ERR, 25, "DOMException.DATA_CLONE_ERR === 25");
356 assert_throws('DATA_CLONE_ERR', function() {worker.postMessage(window)});
358 t.done();
360 function() {
361 var t = async_test("Document objects cannot be cloned");
362 t.id = 26;
363 worker.onmessage = function() {}; //no op because exception should be thrown.
364 t.step(function() {
365 assert_true(DOMException.hasOwnProperty('DATA_CLONE_ERR'), "DOMException.DATA_CLONE_ERR is present");
366 assert_equals(DOMException.DATA_CLONE_ERR, 25, "DOMException.DATA_CLONE_ERR === 25");
367 assert_throws('DATA_CLONE_ERR', function() {worker.postMessage(document)});
369 t.done();
372 }, {explicit_done:true});
374 //Callback for result_callback
375 //queues the next test in the array testCollection
376 //serves to make test execution sequential from the async worker callbacks
377 //alternatively, we would have to create a worker for each test
378 function testFinished(test) {
379 if(test.id < testCollection.length - 1) {
380 //queue the function so that stack remains shallow
381 queue(testCollection[test.id+1]);
382 } else {
383 //when the last test has run, explicitly end test suite
384 done();
387 function queue(func) {
388 step_timeout(func, 10);
391 add_result_callback(testFinished);
392 //start the first test manually
393 queue(testCollection[0]);
398 </script>
399 </body>
400 </html>