| <!DOCTYPE html> | |
| <title>Geometry Interfaces: Serialize and deserialize</title> | |
| <link rel="help" href="https://drafts.fxtf.org/geometry/#structured-serialization"> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <div id=log></div> | |
| <script> | |
| function clone(obj) { | |
| return new Promise((resolve, reject) => { | |
| const channel = new MessageChannel(); | |
| channel.port2.onmessage = e => resolve(e.data); | |
| channel.port1.postMessage(obj); | |
| }); | |
| } | |
| function defineThrowingGetters(object, attrs) { | |
| for (let attr of attrs) { | |
| Object.defineProperty(object, attr, { | |
| get: () => assert_unreached(`getter for ${attr}`) | |
| }); | |
| } | |
| } | |
| [ | |
| ["DOMPointReadOnly", "x", "y", "z", "w"], | |
| ["DOMPoint", "x", "y", "z", "w"], | |
| ["DOMRectReadOnly", "x", "y", "width", "height"], | |
| ["DOMRect", "x", "y", "width", "height"], | |
| ["DOMQuad", "p1", "p2", "p3", "p4"], | |
| ["DOMMatrixReadOnly", "a", "b", "c", "d", "e", "f", "m11", "m12", "m13", "m14", "m21", "m22", "m23", "m24", "m31", "m32", "m33", "m34", "m41", "m42", "m43", "m44", "is2D"], | |
| ["DOMMatrix", "a", "b", "c", "d", "e", "f", "m11", "m12", "m13", "m14", "m21", "m22", "m23", "m24", "m31", "m32", "m33", "m34", "m41", "m42", "m43", "m44", "is2D"], | |
| ].forEach(([constr, ...attrs]) => { | |
| const prefix = `${constr} clone:`; | |
| promise_test(t => { | |
| const object = new self[constr](); | |
| return clone(object).then(other => { | |
| assert_not_equals(object, other); | |
| assert_class_string(other, constr); | |
| for (let attr of attrs) { | |
| if (constr === "DOMQuad") { | |
| assert_not_equals(other[attr], object[attr], attr); | |
| assert_class_string(other[attr], "DOMPoint", attr); | |
| assert_equals(other[attr].x, object.p1.x, `${attr}.x`); | |
| assert_equals(other[attr].y, object.p1.y, `${attr}.y`); | |
| assert_equals(other[attr].z, object.p1.z, `${attr}.z`); | |
| assert_equals(other[attr].w, object.p1.w, `${attr}.w`); | |
| } else { | |
| assert_equals(other[attr], object[attr], attr); | |
| } | |
| } | |
| t.done(); | |
| }); | |
| }, `${prefix} basic`); | |
| promise_test(t => { | |
| const object = new self[constr](); | |
| object.foo = "bar"; | |
| return clone(object).then(other => { | |
| assert_false("foo" in other, 'foo should not exist in other'); | |
| t.done(); | |
| }); | |
| }, `${prefix} custom property`); | |
| promise_test(t => { | |
| const object = new self[constr](); | |
| // The custom throwing getter on object should not be copied to other. | |
| defineThrowingGetters(object, attrs); | |
| return clone(object).then(other => { | |
| for (let attr of attrs) { | |
| // This should call the standard getter, and therefore not throw. | |
| // If this were to call the throwing getter defined on object, the test would fail. | |
| other[attr]; | |
| } | |
| t.done(); | |
| }); | |
| }, `${prefix} throwing getters`); | |
| // More specific tests for each type | |
| switch(constr) { | |
| case "DOMPointReadOnly": | |
| case "DOMPoint": | |
| case "DOMRectReadOnly": | |
| case "DOMRect": | |
| promise_test(t => { | |
| const object = new self[constr](1, -0, Infinity, NaN); | |
| return clone(object).then(other => { | |
| for (let attr of attrs) { | |
| assert_equals(other[attr], object[attr], attr); | |
| } | |
| t.done(); | |
| }); | |
| }, `${prefix} non-initial values`); | |
| break; | |
| case "DOMQuad": | |
| promise_test(t => { | |
| const object = new self[constr]({x:1, y:2, z:3, w:4}, | |
| {x:-0, y:-0, z:-0, w:-0}, | |
| {x:Infinity, y:Infinity, z:Infinity, w:Infinity}, | |
| {x:NaN, y:NaN, z:NaN, w:NaN}); | |
| return clone(object).then(other => { | |
| for (let attr of attrs) { | |
| assert_equals(other[attr].x, object[attr].x, `${attr}.x`); | |
| assert_equals(other[attr].y, object[attr].y, `${attr}.y`); | |
| assert_equals(other[attr].z, object[attr].z, `${attr}.z`); | |
| assert_equals(other[attr].w, object[attr].w, `${attr}.w`); | |
| } | |
| t.done(); | |
| }); | |
| }, `${prefix} non-initial values`); | |
| break; | |
| case "DOMMatrixReadOnly": | |
| case "DOMMatrix": | |
| promise_test(t => { | |
| const object = new self[constr]([1, -0, Infinity, NaN, 5, 6]); | |
| object.m13 = -0; | |
| object.m14 = -0; | |
| object.m23 = -0; | |
| object.m24 = -0; | |
| object.m31 = -0; | |
| object.m32 = -0; | |
| object.m34 = -0; | |
| object.m43 = -0; | |
| assert_true(object.is2D, 'is2D after setting m13 etc to -0'); | |
| return clone(object).then(other => { | |
| for (let attr of attrs) { | |
| if (attr === 'm13' || | |
| attr === 'm14' || | |
| attr === 'm23' || | |
| attr === 'm24' || | |
| attr === 'm31' || | |
| attr === 'm32' || | |
| attr === 'm34' || | |
| attr === 'm43') { | |
| assert_equals(other[attr], 0, attr); | |
| } else { | |
| assert_equals(other[attr], object[attr], attr); | |
| } | |
| } | |
| t.done(); | |
| }); | |
| }, `${prefix} non-initial values (2d)`); | |
| promise_test(t => { | |
| const object = new self[constr]([11, -0, Infinity, NaN, | |
| 21, 22, 23, 24, | |
| 31, 32, 33, 34, | |
| 41, 42, 43, 44]); | |
| return clone(object).then(other => { | |
| for (let attr of attrs) { | |
| assert_equals(other[attr], object[attr], attr); | |
| } | |
| t.done(); | |
| }); | |
| }, `${prefix} non-initial values (3d)`); | |
| break; | |
| default: | |
| throw new Error(`Test bug: ${constr} has no test for non-initial values`); | |
| } | |
| }); | |
| promise_test((t) => { | |
| const object = document.getElementById('log').getClientRects(); | |
| return promise_rejects_dom(t, "DataCloneError", clone(object)); | |
| }, 'DOMRectList clone');0 | |
| </script> |