| structuredCloneBatteryOfTests.push({ |
| description: 'ArrayBuffer', |
| async f(runner) { |
| const buffer = new Uint8Array([1]).buffer; |
| const copy = await runner.structuredClone(buffer, [buffer]); |
| assert_equals(buffer.byteLength, 0); |
| assert_equals(copy.byteLength, 1); |
| } |
| }); |
| |
| structuredCloneBatteryOfTests.push({ |
| description: 'MessagePort', |
| async f(runner) { |
| const {port1, port2} = new MessageChannel(); |
| const copy = await runner.structuredClone(port2, [port2]); |
| const msg = new Promise(resolve => port1.onmessage = resolve); |
| copy.postMessage('ohai'); |
| assert_equals((await msg).data, 'ohai'); |
| } |
| }); |
| |
| // TODO: ImageBitmap |
| |
| structuredCloneBatteryOfTests.push({ |
| description: 'A detached ArrayBuffer cannot be transferred', |
| async f(runner, t) { |
| const buffer = new ArrayBuffer(); |
| await runner.structuredClone(buffer, [buffer]); |
| await promise_rejects_dom( |
| t, |
| "DataCloneError", |
| runner.structuredClone(buffer, [buffer]) |
| ); |
| } |
| }); |
| |
| structuredCloneBatteryOfTests.push({ |
| description: 'A detached platform object cannot be transferred', |
| async f(runner, t) { |
| const {port1} = new MessageChannel(); |
| await runner.structuredClone(port1, [port1]); |
| await promise_rejects_dom( |
| t, |
| "DataCloneError", |
| runner.structuredClone(port1, [port1]) |
| ); |
| } |
| }); |
| |
| structuredCloneBatteryOfTests.push({ |
| description: 'Transferring a non-transferable platform object fails', |
| async f(runner, t) { |
| const blob = new Blob(); |
| await promise_rejects_dom( |
| t, |
| "DataCloneError", |
| runner.structuredClone(blob, [blob]) |
| ); |
| } |
| }); |
| |
| structuredCloneBatteryOfTests.push({ |
| description: 'An object whose interface is deleted from the global object must still be received', |
| async f(runner) { |
| const {port1} = new MessageChannel(); |
| const messagePortInterface = globalThis.MessagePort; |
| delete globalThis.MessagePort; |
| try { |
| const transfer = await runner.structuredClone(port1, [port1]); |
| assert_true(transfer instanceof messagePortInterface); |
| } finally { |
| globalThis.MessagePort = messagePortInterface; |
| } |
| } |
| }); |
| |
| structuredCloneBatteryOfTests.push({ |
| description: 'A subclass instance will be received as its closest transferable superclass', |
| async f(runner) { |
| // MessagePort doesn't have a constructor, so we must use something else. |
| |
| // Make sure that ReadableStream is transferable before we test its subclasses. |
| try { |
| const stream = new ReadableStream(); |
| await runner.structuredClone(stream, [stream]); |
| } catch(err) { |
| if (err instanceof DOMException && err.code === DOMException.DATA_CLONE_ERR) { |
| throw new OptionalFeatureUnsupportedError("ReadableStream isn't transferable"); |
| } else { |
| throw err; |
| } |
| } |
| |
| class ReadableStreamSubclass extends ReadableStream {} |
| const original = new ReadableStreamSubclass(); |
| const transfer = await runner.structuredClone(original, [original]); |
| assert_equals(Object.getPrototypeOf(transfer), ReadableStream.prototype); |
| } |
| }); |
| |
| structuredCloneBatteryOfTests.push({ |
| description: 'Resizable ArrayBuffer is transferable', |
| async f(runner) { |
| const buffer = new ArrayBuffer(16, { maxByteLength: 1024 }); |
| const copy = await runner.structuredClone(buffer, [buffer]); |
| assert_equals(buffer.byteLength, 0); |
| assert_equals(copy.byteLength, 16); |
| assert_equals(copy.maxByteLength, 1024); |
| assert_true(copy.resizable); |
| } |
| }); |
| |
| structuredCloneBatteryOfTests.push({ |
| description: 'Length-tracking TypedArray is transferable', |
| async f(runner) { |
| const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); |
| const ta = new Uint8Array(ab); |
| const copy = await runner.structuredClone(ta, [ab]); |
| assert_equals(ab.byteLength, 0); |
| assert_equals(copy.buffer.byteLength, 16); |
| assert_equals(copy.buffer.maxByteLength, 1024); |
| assert_true(copy.buffer.resizable); |
| copy.buffer.resize(32); |
| assert_equals(copy.byteLength, 32); |
| } |
| }); |
| |
| structuredCloneBatteryOfTests.push({ |
| description: 'Length-tracking DataView is transferable', |
| async f(runner) { |
| const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); |
| const dv = new DataView(ab); |
| const copy = await runner.structuredClone(dv, [ab]); |
| assert_equals(ab.byteLength, 0); |
| assert_equals(copy.buffer.byteLength, 16); |
| assert_equals(copy.buffer.maxByteLength, 1024); |
| assert_true(copy.buffer.resizable); |
| copy.buffer.resize(32); |
| assert_equals(copy.byteLength, 32); |
| } |
| }); |
| |
| structuredCloneBatteryOfTests.push({ |
| description: 'Transferring OOB TypedArray throws', |
| async f(runner, t) { |
| const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); |
| const ta = new Uint8Array(ab, 8); |
| ab.resize(0); |
| await promise_rejects_dom( |
| t, |
| "DataCloneError", |
| runner.structuredClone(ta, [ab]) |
| ); |
| } |
| }); |
| |
| structuredCloneBatteryOfTests.push({ |
| description: 'Transferring OOB DataView throws', |
| async f(runner, t) { |
| const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); |
| const dv = new DataView(ab, 8); |
| ab.resize(0); |
| await promise_rejects_dom( |
| t, |
| "DataCloneError", |
| runner.structuredClone(dv, [ab]) |
| ); |
| } |
| }); |