Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add WPT Test for Stream Object globals
This test is based on the general structure of js/src/tests/non262/ReadableStream/readable-stream-globals.js, however the expectations have been commented and updated to match what we believe is the correct WebIDL behaviour. Not all the features of that test case have been ported over, as there's some stuff around the handling of Symbol.species that we can test elsewhere, and it attempts to test BYOB streams, which we have yet to implement. Note: I tried to initially write this as an xpcshell test case using Cu.sandbox; but I found that I wasn't geting global behaviour that matched my expectations from testing on the web. Differential Revision: https://phabricator.services.mozilla.com/D137492 bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1750634 gecko-commit: 7b75650e5e0bcc300a409f54f664efc08ed0c7ba gecko-reviewers: smaug, saschanaz
- Loading branch information
1 parent
878da93
commit 60cda28
Showing
1 changed file
with
162 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
<!doctype html> | ||
<meta charset="utf-8"> | ||
<title>Ensure Stream objects are created in expected globals. </title> | ||
|
||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
|
||
<body></body> | ||
<script> | ||
// These tests are loosely derived from Gecko's readable-stream-globals.js, | ||
// which is a test case designed around the JS Streams implementation. | ||
// | ||
// Unlike in JS Streams, where function calls switch realms and change | ||
// the resulting global of the resulting objects, in WebIDL streams, | ||
// the global of an object is (currently underspecified, but) intended | ||
// to be the "Relevant Global" of the 'this' object. | ||
// | ||
// See: | ||
// https://html.spec.whatwg.org/multipage/webappapis.html#relevant | ||
// https://github.com/whatwg/streams/issues/1213 | ||
"use strict" | ||
|
||
const iframe = document.createElement("iframe") | ||
document.body.append(iframe) | ||
|
||
const otherGlobal = iframe.contentWindow; | ||
const OtherReadableStream = otherGlobal.ReadableStream | ||
const OtherReadableStreamDefaultReader = otherGlobal.ReadableStreamDefaultReader; | ||
const OtherReadableStreamDefaultController = otherGlobal.ReadableStreamDefaultController; | ||
|
||
promise_test(async () => { | ||
|
||
// Controllers | ||
let controller; | ||
let otherController; | ||
|
||
// Get Stream Prototypes and controllers. | ||
let streamController; | ||
let stream = new ReadableStream({start(c) { streamController = c; }}); | ||
|
||
const callReaderThisGlobal = OtherReadableStream.prototype.getReader.call(stream); | ||
const newReaderOtherGlobal = new OtherReadableStreamDefaultReader(new ReadableStream()); | ||
|
||
// Relevant Global Checking. | ||
assert_equals(callReaderThisGlobal instanceof ReadableStreamDefaultReader, true, "reader was created in this global (.call)"); | ||
assert_equals(newReaderOtherGlobal instanceof ReadableStreamDefaultReader, false, "reader was created in other global (new)"); | ||
|
||
assert_equals(callReaderThisGlobal instanceof OtherReadableStreamDefaultReader, false, "reader isn't coming from other global (.call)" ); | ||
assert_equals(newReaderOtherGlobal instanceof OtherReadableStreamDefaultReader, true, "reader isn't coming from other global (new)"); | ||
|
||
assert_equals(otherController instanceof ReadableStreamDefaultController, false, "otherController should come from other gloal") | ||
|
||
|
||
const request = callReaderThisGlobal.read(); | ||
assert_equals(request instanceof Promise, true, "Promise comes from this global"); | ||
|
||
streamController.close(); | ||
const requestResult = await request; | ||
assert_equals(requestResult instanceof Object, true, "returned object comes from this global"); | ||
}, "Stream objects created in expected globals") | ||
|
||
promise_test(async () => { | ||
const stream = new ReadableStream(); | ||
const otherReader = new OtherReadableStreamDefaultReader(stream); | ||
const cancelPromise = ReadableStreamDefaultReader.prototype.cancel.call(otherReader); | ||
assert_equals(cancelPromise instanceof Promise, true, "Cancel promise comes from the same global as the stream"); | ||
assert_equals(await cancelPromise, undefined, "Cancel promise resolves to undefined"); | ||
}, "Cancel promise is created in same global as stream") | ||
|
||
// Refresh the streams and controllers. | ||
function getFreshInstances() { | ||
let controller; | ||
let otherController; | ||
let stream = new ReadableStream({ | ||
start(c) { | ||
controller = c; | ||
} | ||
}); | ||
|
||
new OtherReadableStream({ | ||
start(c) { | ||
otherController = c; | ||
} | ||
}); | ||
|
||
return {stream, controller, otherController} | ||
} | ||
|
||
|
||
promise_test(async () => { | ||
// Test closed promise on reader from another global (connected to a this-global stream) | ||
const {stream, controller, otherController} = getFreshInstances(); | ||
|
||
const otherReader = new OtherReadableStreamDefaultReader(stream); | ||
const closedPromise = otherReader.closed; | ||
assert_equals(closedPromise instanceof otherGlobal.Promise, true, "Closed promise in other global."); | ||
}, "Closed Promise in correct global"); | ||
|
||
promise_test(async () => { | ||
const {stream, controller, otherController} = getFreshInstances(); | ||
|
||
const otherReader = OtherReadableStream.prototype.getReader.call(stream); | ||
assert_equals(otherReader instanceof ReadableStreamDefaultReader, true, "Reader comes from this global") | ||
const request = otherReader.read(); | ||
assert_equals(request instanceof Promise, true, "Promise still comes from stream's realm (this realm)"); | ||
otherController.close.call(controller); | ||
assert_equals((await request) instanceof otherGlobal.Object, true, "Object comes from other realm"); | ||
}, "Reader objects in correct global"); | ||
|
||
|
||
promise_test(async () => { | ||
const {stream, controller, otherController} = getFreshInstances(); | ||
assert_equals(controller.desiredSize, 1, "Desired size is expected"); | ||
Object.defineProperty(controller, "desiredSize", | ||
Object.getOwnPropertyDescriptor(OtherReadableStreamDefaultController.prototype, "desiredSize")); | ||
assert_equals(controller.desiredSize, 1, "Grafting getter from other prototype still returns desired size"); | ||
}, "Desired size can be grafted from one prototype to another"); | ||
|
||
promise_test(async () => { | ||
const {stream, controller, otherController} = getFreshInstances(); | ||
|
||
// Make sure the controller close method returns the correct TypeError | ||
const enqueuedError = { name: "enqueuedError" }; | ||
controller.error(enqueuedError); | ||
|
||
assert_throws_js(TypeError, () => controller.close(), "Current Global controller"); | ||
assert_throws_js(otherGlobal.TypeError, () => otherController.close.call(controller), "Other global controller"); | ||
}, "Closing errored stream throws object in appropriate global") | ||
|
||
promise_test(async () => { | ||
const {otherController} = getFreshInstances(); | ||
// We can enqueue chunks from multiple globals | ||
const chunk = { name: "chunk" }; | ||
|
||
let controller; | ||
const stream = new ReadableStream({ start(c) { controller = c; } }, { size() {return 1} }); | ||
otherController.enqueue.call(controller, chunk); | ||
otherController.enqueue.call(controller, new otherGlobal.Uint8Array(10)); | ||
controller.enqueue(new otherGlobal.Uint8Array(10)); | ||
}, "Can enqueue chunks from multiple globals") | ||
|
||
promise_test(async () => { | ||
const {stream, controller, otherController} = getFreshInstances(); | ||
const chunk = { name: "chunk" }; | ||
|
||
// We get the correct type errors out of a closed stream. | ||
controller.close(); | ||
assert_throws_js(TypeError, () => controller.enqueue(new otherGlobal.Uint8Array(10))); | ||
assert_throws_js(otherGlobal.TypeError, () => otherController.enqueue.call(controller, chunk)); | ||
assert_throws_js(otherGlobal.TypeError, () => otherController.enqueue.call(controller, new otherGlobal.Uint8Array(10))); | ||
}, "Correct errors and globals for closed streams"); | ||
|
||
|
||
promise_test(async () => { | ||
const {stream, controller, otherController} = getFreshInstances(); | ||
// Branches out of tee are in the correct global | ||
|
||
const [branch1, branch2] = otherGlobal.ReadableStream.prototype.tee.call(stream); | ||
assert_equals(branch1 instanceof ReadableStream, true, "Branch created in this global (as stream is in this global)"); | ||
assert_equals(branch2 instanceof ReadableStream, true, "Branch created in this global (as stream is in this global)"); | ||
}, "Tee Branches in correct global"); | ||
</script> |