close.any.js (7617B)
1 // META: script=../../constants.sub.js 2 // META: script=resources/url-constants.js 3 // META: global=window,worker 4 // META: variant=?default 5 // META: variant=?wss 6 // META: variant=?wpt_flags=h2 7 8 'use strict'; 9 10 promise_test(async () => { 11 const wss = new WebSocketStream(ECHOURL); 12 await wss.opened; 13 wss.close({ closeCode: 3456, reason: 'pizza' }); 14 const { closeCode, reason } = await wss.closed; 15 assert_equals(closeCode, 3456, 'code should match'); 16 assert_equals(reason, 'pizza', 'reason should match'); 17 }, 'close code should be sent to server and reflected back'); 18 19 promise_test(async () => { 20 const wss = new WebSocketStream(ECHOURL); 21 await wss.opened; 22 wss.close(); 23 const { closeCode, reason } = await wss.closed; 24 assert_equals(closeCode, 1005, 'code should be unset'); 25 assert_equals(reason, '', 'reason should be empty'); 26 }, 'no close argument should send empty Close frame'); 27 28 promise_test(async () => { 29 const wss = new WebSocketStream(ECHOURL); 30 await wss.opened; 31 wss.close({}); 32 const { closeCode, reason } = await wss.closed; 33 assert_equals(closeCode, 1005, 'code should be unset'); 34 assert_equals(reason, '', 'reason should be empty'); 35 }, 'unspecified close code should send empty Close frame'); 36 37 promise_test(async () => { 38 const wss = new WebSocketStream(ECHOURL); 39 await wss.opened; 40 wss.close({reason: ''}); 41 const { closeCode, reason } = await wss.closed; 42 assert_equals(closeCode, 1005, 'code should be unset'); 43 assert_equals(reason, '', 'reason should be empty'); 44 }, 'unspecified close code with empty reason should send empty Close frame'); 45 46 promise_test(async () => { 47 const wss = new WebSocketStream(ECHOURL); 48 await wss.opened; 49 wss.close({reason: 'non-empty'}); 50 const { closeCode, reason } = await wss.closed; 51 assert_equals(closeCode, 1000, 'code should be set'); 52 assert_equals(reason, 'non-empty', 'reason should match'); 53 }, 'unspecified close code with non-empty reason should set code to 1000'); 54 55 promise_test(async () => { 56 const wss = new WebSocketStream(ECHOURL); 57 await wss.opened; 58 assert_throws_js(TypeError, () => wss.close(true), 59 'close should throw a TypeError'); 60 }, 'close(true) should throw a TypeError'); 61 62 promise_test(async () => { 63 const wss = new WebSocketStream(ECHOURL); 64 await wss.opened; 65 const reason = '.'.repeat(124); 66 assert_throws_dom('SyntaxError', () => wss.close({ reason }), 67 'close should throw a SyntaxError'); 68 }, 'close() with an overlong reason should throw'); 69 70 function IsWebSocketError(e) { 71 return e.constructor == WebSocketError; 72 } 73 74 promise_test(t => { 75 const wss = new WebSocketStream(ECHOURL); 76 wss.close(); 77 return Promise.all([ 78 wss.opened.then(t.unreached_func('should have rejected')).catch(e => assert_true(IsWebSocketError(e))), 79 wss.closed.then(t.unreached_func('should have rejected')).catch(e => assert_true(IsWebSocketError(e))), 80 ]); 81 }, 'close during handshake should work'); 82 83 for (const invalidCode of [999, 1001, 2999, 5000]) { 84 promise_test(async () => { 85 const wss = new WebSocketStream(ECHOURL); 86 await wss.opened; 87 assert_throws_dom('InvalidAccessError', () => wss.close({ closeCode: invalidCode }), 88 'close should throw an InvalidAccessError'); 89 }, `close() with invalid code ${invalidCode} should throw`); 90 } 91 92 promise_test(async () => { 93 const wss = new WebSocketStream(ECHOURL); 94 const { writable } = await wss.opened; 95 writable.getWriter().close(); 96 const { closeCode, reason } = await wss.closed; 97 assert_equals(closeCode, 1005, 'code should be unset'); 98 assert_equals(reason, '', 'reason should be empty'); 99 }, 'closing the writable should result in a clean close'); 100 101 promise_test(async () => { 102 const wss = new WebSocketStream(`${BASEURL}/delayed-passive-close`); 103 const { writable } = await wss.opened; 104 const startTime = performance.now(); 105 await writable.getWriter().close(); 106 const elapsed = performance.now() - startTime; 107 const jitterAllowance = 100; 108 assert_greater_than_equal(elapsed, 1000 - jitterAllowance, 109 'one second should have elapsed'); 110 }, 'writer close() promise should not resolve until handshake completes'); 111 112 promise_test(async t => { 113 const wss = new WebSocketStream(`${BASEURL}/passive-close-abort`); 114 await wss.opened; 115 wss.close({closeCode: 4000, reason: 'because'}); 116 const error = await wss.closed.then(t.unreached_func('closed should reject'), e => e); 117 assert_equals(error.constructor, WebSocketError, 'error should be WebSocketError'); 118 assert_equals(error.closeCode, 1006, 'close code should be Abnormal Closure'); 119 }, 'incomplete closing handshake should be considered unclean close'); 120 121 const abortOrCancel = [ 122 { 123 method: 'abort', 124 voweling: 'aborting', 125 stream: 'writable', 126 }, 127 { 128 method: 'cancel', 129 voweling: 'canceling', 130 stream: 'readable', 131 }, 132 ]; 133 134 for (const { method, voweling, stream } of abortOrCancel) { 135 136 promise_test(async () => { 137 const wss = new WebSocketStream(ECHOURL); 138 const info = await wss.opened; 139 info[stream][method](); 140 const { closeCode, reason } = await wss.closed; 141 assert_equals(closeCode, 1005, 'code should be unset'); 142 assert_equals(reason, '', 'reason should be empty'); 143 }, `${voweling} the ${stream} should result in a clean close`); 144 145 promise_test(async () => { 146 const wss = new WebSocketStream(ECHOURL); 147 const info = await wss.opened; 148 info[stream][method]({ closeCode: 3333, reason: 'obsolete' }); 149 const { closeCode, reason } = await wss.closed; 150 assert_equals(closeCode, 1005, 'code should be unset'); 151 assert_equals(reason, '', 'reason should be empty'); 152 }, `${voweling} the ${stream} with attributes not wrapped in a WebSocketError should be ignored`); 153 154 promise_test(async () => { 155 const wss = new WebSocketStream(ECHOURL); 156 const info = await wss.opened; 157 info[stream][method](new WebSocketError('', { closeCode: 3333 })); 158 const { closeCode, reason } = await wss.closed; 159 assert_equals(closeCode, 3333, 'code should be used'); 160 assert_equals(reason, '', 'reason should be empty'); 161 }, `${voweling} the ${stream} with a code should send that code`); 162 163 promise_test(async () => { 164 const wss = new WebSocketStream(ECHOURL); 165 const info = await wss.opened; 166 info[stream][method](new WebSocketError('', { closeCode: 3456, reason: 'set' })); 167 const { closeCode, reason } = await wss.closed; 168 assert_equals(closeCode, 3456, 'code should be used'); 169 assert_equals(reason, 'set', 'reason should be used'); 170 }, `${voweling} the ${stream} with a code and reason should use them`); 171 172 promise_test(async () => { 173 const wss = new WebSocketStream(ECHOURL); 174 const info = await wss.opened; 175 info[stream][method](new WebSocketError('', { reason: 'specified' })); 176 const { closeCode, reason } = await wss.closed; 177 assert_equals(closeCode, 1000, 'code should be defaulted'); 178 assert_equals(reason, 'specified', 'reason should be used'); 179 }, `${voweling} the ${stream} with a reason but no code should default the close code`); 180 181 promise_test(async () => { 182 const wss = new WebSocketStream(ECHOURL); 183 const info = await wss.opened; 184 const domException = new DOMException('yes', 'DataCloneError'); 185 domException.closeCode = 1000; 186 domException.reason = 'should be ignored'; 187 info[stream][method](domException); 188 const { closeCode, reason } = await wss.closed; 189 assert_equals(closeCode, 1005, 'code should be unset'); 190 assert_equals(reason, '', 'reason should be empty'); 191 }, `${voweling} the ${stream} with a DOMException not set code or reason`); 192 193 }