Skip to content

Commit 90c5aa6

Browse files
author
Andreu Botella
authored
Add additional structured clone tests
The following behaviors mandated by the spec weren't tested: - Serializing a non-serializable platform object, or transferring a non-transferable platform object, should fail. - Platform objects must deserialize even if their interface has been deleted from the realm's global. - Objects which have serializable or transferable interfaces in their inheritance hierarchy must deserialize as instances of the closest such interface. - Transferring again a detached object will fail. This change also passes the test object as an additional parameter to the `f` function of structured clone tests, to make it possible to test that a promise rejects.
1 parent ababf6c commit 90c5aa6

File tree

3 files changed

+117
-2
lines changed

3 files changed

+117
-2
lines changed

html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ function runStructuredCloneBatteryOfTests(runner) {
3030
}
3131

3232
return new Promise(resolve => {
33-
promise_test(async _ => {
33+
promise_test(async t => {
3434
test = await test;
3535
await setupPromise;
3636
await runner.preTest(test);
37-
await test.f(runner)
37+
await test.f(runner, t)
3838
await runner.postTest(test);
3939
resolve();
4040
}, test.description);

html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,80 @@ structuredCloneBatteryOfTests.push({
2020
});
2121

2222
// TODO: ImageBitmap
23+
24+
structuredCloneBatteryOfTests.push({
25+
description: 'A detached ArrayBuffer cannot be transferred',
26+
async f(runner, t) {
27+
const buffer = new ArrayBuffer();
28+
await runner.structuredClone(buffer, [buffer]);
29+
await promise_rejects_dom(
30+
t,
31+
"DataCloneError",
32+
runner.structuredClone(buffer, [buffer])
33+
);
34+
}
35+
});
36+
37+
structuredCloneBatteryOfTests.push({
38+
description: 'A detached platform object cannot be transferred',
39+
async f(runner, t) {
40+
const {port1} = new MessageChannel();
41+
await runner.structuredClone(port1, [port1]);
42+
await promise_rejects_dom(
43+
t,
44+
"DataCloneError",
45+
runner.structuredClone(port1, [port1])
46+
);
47+
}
48+
});
49+
50+
structuredCloneBatteryOfTests.push({
51+
description: 'Transferring a non-transferable platform object fails',
52+
async f(runner, t) {
53+
const blob = new Blob();
54+
await promise_rejects_dom(
55+
t,
56+
"DataCloneError",
57+
runner.structuredClone(blob, [blob])
58+
);
59+
}
60+
});
61+
62+
structuredCloneBatteryOfTests.push({
63+
description: 'An object whose interface is deleted from the global object must still be received',
64+
async f(runner) {
65+
const {port1} = new MessageChannel();
66+
const messagePortInterface = globalThis.MessagePort;
67+
delete globalThis.MessagePort;
68+
try {
69+
const transfer = await runner.structuredClone(port1, [port1]);
70+
assert_true(transfer instanceof messagePortInterface);
71+
} finally {
72+
globalThis.MessagePort = messagePortInterface;
73+
}
74+
}
75+
});
76+
77+
structuredCloneBatteryOfTests.push({
78+
description: 'A subclass instance will be received as its closest transferable superclass',
79+
async f(runner) {
80+
// MessagePort doesn't have a constructor, so we must use something else.
81+
82+
// Make sure that ReadableStream is transferable before we test its subclasses.
83+
try {
84+
const stream = new ReadableStream();
85+
await runner.structuredClone(stream, [stream]);
86+
} catch(err) {
87+
if (err instanceof DOMException && err.code === DOMException.DATA_CLONE_ERR) {
88+
throw new OptionalFeatureUnsupportedError("ReadableStream isn't transferable");
89+
} else {
90+
throw err;
91+
}
92+
}
93+
94+
class ReadableStreamSubclass extends ReadableStream {}
95+
const original = new ReadableStreamSubclass();
96+
const transfer = await runner.structuredClone(original, [original]);
97+
assert_equals(Object.getPrototypeOf(transfer), ReadableStream.prototype);
98+
}
99+
});

html/webappapis/structured-clone/structured-clone-battery-of-tests.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,3 +616,41 @@ check('ObjectPrototype must lose its exotic-ness when cloned',
616616
assert_equals(Object.getPrototypeOf(copy), newProto);
617617
}
618618
);
619+
620+
structuredCloneBatteryOfTests.push({
621+
description: 'Serializing a non-serializable platform object fails',
622+
async f(runner, t) {
623+
const request = new Response();
624+
await promise_rejects_dom(
625+
t,
626+
"DataCloneError",
627+
runner.structuredClone(request)
628+
);
629+
}
630+
});
631+
632+
structuredCloneBatteryOfTests.push({
633+
description: 'An object whose interface is deleted from the global must still deserialize',
634+
async f(runner) {
635+
const blob = new Blob();
636+
const blobInterface = globalThis.Blob;
637+
delete globalThis.Blob;
638+
try {
639+
const copy = await runner.structuredClone(blob);
640+
assert_true(copy instanceof blobInterface);
641+
} finally {
642+
globalThis.Blob = blobInterface;
643+
}
644+
}
645+
});
646+
647+
check(
648+
'A subclass instance will deserialize as its closest serializable superclass',
649+
() => {
650+
class FileSubclass extends File {}
651+
return new FileSubclass([], "");
652+
},
653+
(copy) => {
654+
assert_equals(Object.getPrototypeOf(copy), File.prototype);
655+
}
656+
);

0 commit comments

Comments
 (0)