| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <script src="resources/helpers.js"></script> | |
| <script> | |
| 'use strict'; | |
| // Chrome used to special-case the reason for cancel() and abort() in order to | |
| // handle exceptions correctly. This is no longer necessary. These tests are | |
| // retained to avoid regressions. | |
| async function getTransferredReason(originalReason) { | |
| let resolvePromise; | |
| const rv = new Promise(resolve => { | |
| resolvePromise = resolve; | |
| }); | |
| const rs = await createTransferredReadableStream({ | |
| cancel(reason) { | |
| resolvePromise(reason); | |
| } | |
| }); | |
| await rs.cancel(originalReason); | |
| return rv; | |
| } | |
| for (const value of ['hi', '\t\r\n', 7, 3.0, undefined, null, true, false, | |
| NaN, Infinity]) { | |
| promise_test(async () => { | |
| const reason = await getTransferredReason(value); | |
| assert_equals(reason, value, 'reason should match'); | |
| }, `reason with a simple value of '${value}' should be preserved`); | |
| } | |
| for (const badType of [Symbol('hi'), _ => 'hi']) { | |
| promise_test(async t => { | |
| return promise_rejects_dom(t, 'DataCloneError', | |
| getTransferredReason(badType), | |
| 'cancel() should reject'); | |
| }, `reason with a type of '${typeof badType}' should be rejected and ` + | |
| `error the stream`); | |
| } | |
| promise_test(async () => { | |
| const reasonAsJson = | |
| `{"foo":[1,"col"],"bar":{"hoge":0.2,"baz":{},"shan":null}}`; | |
| const reason = await getTransferredReason(JSON.parse(reasonAsJson)); | |
| assert_equals(JSON.stringify(reason), reasonAsJson, | |
| 'object should be preserved'); | |
| }, 'objects that can be completely expressed in JSON should be preserved'); | |
| promise_test(async () => { | |
| const circularObject = {}; | |
| circularObject.self = circularObject; | |
| const reason = await getTransferredReason(circularObject); | |
| assert_true(reason instanceof Object, 'an Object should be output'); | |
| assert_equals(reason.self, reason, | |
| 'the object should have a circular reference'); | |
| }, 'objects that cannot be expressed in JSON should also be preserved'); | |
| promise_test(async () => { | |
| const originalReason = new TypeError('hi'); | |
| const reason = await getTransferredReason(originalReason); | |
| assert_true(reason instanceof TypeError, | |
| 'type should be preserved'); | |
| assert_equals(reason.message, originalReason.message, | |
| 'message should be preserved'); | |
| }, 'the type and message of a TypeError should be preserved'); | |
| promise_test(async () => { | |
| const originalReason = new TypeError('hi'); | |
| originalReason.foo = 'bar'; | |
| const reason = await getTransferredReason(originalReason); | |
| assert_false('foo' in reason, | |
| 'foo should not be preserved'); | |
| }, 'other attributes of a TypeError should not be preserved'); | |
| promise_test(async () => { | |
| const originalReason = new TypeError(); | |
| originalReason.message = [1, 2, 3]; | |
| const reason = await getTransferredReason(originalReason); | |
| assert_equals(reason.message, '1,2,3', 'message should be stringified'); | |
| }, 'a TypeError message should be converted to a string'); | |
| promise_test(async () => { | |
| const originalReason = new TypeError(); | |
| Object.defineProperty(originalReason, 'message', { | |
| get() { return 'words'; } | |
| }); | |
| const reason = await getTransferredReason(originalReason); | |
| assert_equals(reason.message, '', 'message should not be preserved'); | |
| }, 'a TypeError message should not be preserved if it is a getter'); | |
| promise_test(async () => { | |
| const originalReason = new TypeError(); | |
| delete originalReason.message; | |
| TypeError.prototype.message = 'inherited message'; | |
| const reason = await getTransferredReason(originalReason); | |
| delete TypeError.prototype.message; | |
| assert_equals(reason.message, '', 'message should not be preserved'); | |
| }, 'a TypeError message should not be preserved if it is inherited'); | |
| promise_test(async () => { | |
| const originalReason = new DOMException('yes', 'AbortError'); | |
| const reason = await getTransferredReason(originalReason); | |
| assert_true(reason instanceof DOMException, | |
| 'reason should be a DOMException'); | |
| assert_equals(reason.message, originalReason.message, | |
| 'the messages should match'); | |
| assert_equals(reason.name, originalReason.name, | |
| 'the names should match'); | |
| }, 'DOMException errors should be preserved'); | |
| for (const errorConstructor of [EvalError, RangeError, | |
| ReferenceError, SyntaxError, TypeError, | |
| URIError]) { | |
| promise_test(async () => { | |
| const originalReason = new errorConstructor('nope'); | |
| const reason = await getTransferredReason(originalReason); | |
| assert_equals(typeof reason, 'object', 'reason should have type object'); | |
| assert_true(reason instanceof errorConstructor, | |
| `reason should inherit ${errorConstructor.name}`); | |
| assert_true(reason instanceof Error, 'reason should inherit Error'); | |
| assert_equals(reason.constructor, errorConstructor, | |
| 'reason should have the right constructor'); | |
| assert_equals(reason.name, errorConstructor.name, | |
| `name should match constructor name`); | |
| assert_equals(reason.message, 'nope', 'message should match'); | |
| }, `${errorConstructor.name} should be preserved`); | |
| } | |
| </script> |