summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/streams/transferable/reason.html
blob: 4251aa85b816bb24a00143b642cf8410a4132366 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<!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>