| <!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> |