| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 1 | <!doctype html> | 
|  | 2 | <meta charset=utf-8> | 
|  | 3 | <title>RTCPeerConnection.prototype.ondatachannel</title> | 
|  | 4 | <script src="/resources/testharness.js"></script> | 
|  | 5 | <script src="/resources/testharnessreport.js"></script> | 
|  | 6 | <script src="RTCPeerConnection-helper.js"></script> | 
|  | 7 | <script> | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 8 | 'use strict'; | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 9 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 10 | // Test is based on the following revision: | 
|  | 11 | // https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 12 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 13 | // The following helper functions are called from RTCPeerConnection-helper.js: | 
|  | 14 | // exchangeIceCandidates | 
|  | 15 | // doSignalingHandshake | 
|  | 16 | // createDataChannelPair | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 17 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 18 | /* | 
|  | 19 | 6.2. RTCDataChannel | 
|  | 20 | When an underlying data transport is to be announced (the other peer created a channel with | 
|  | 21 | negotiated unset or set to false), the user agent of the peer that did not initiate the | 
|  | 22 | creation process MUST queue a task to run the following steps: | 
|  | 23 | 2. Let channel be a newly created RTCDataChannel object. | 
|  | 24 | 7. Set channel's [[ReadyState]] to open (but do not fire the open event, yet). | 
|  | 25 | 8. Fire a datachannel event named datachannel with channel at the RTCPeerConnection object. | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 26 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 27 | 6.3. RTCDataChannelEvent | 
|  | 28 | Firing a datachannel event named e with an RTCDataChannel channel means that an event with the | 
|  | 29 | name e, which does not bubble (except where otherwise stated) and is not cancelable (except | 
|  | 30 | where otherwise stated), and which uses the RTCDataChannelEvent interface with the channel | 
|  | 31 | attribute set to channel, MUST be created and dispatched at the given target. | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 32 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 33 | interface RTCDataChannelEvent : Event { | 
|  | 34 | readonly attribute RTCDataChannel channel; | 
|  | 35 | }; | 
|  | 36 | */ | 
|  | 37 | promise_test(async (t) => { | 
|  | 38 | const resolver = new Resolver(); | 
|  | 39 | const pc1 = new RTCPeerConnection(); | 
|  | 40 | const pc2 = new RTCPeerConnection(); | 
|  | 41 | t.add_cleanup(() => pc1.close()); | 
|  | 42 | t.add_cleanup(() => pc2.close()); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 43 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 44 | let eventCount = 0; | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 45 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 46 | pc2.ondatachannel = t.step_func((event) => { | 
|  | 47 | eventCount++; | 
|  | 48 | assert_equals(eventCount, 1, | 
|  | 49 | 'Expect data channel event to fire exactly once'); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 50 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 51 | assert_true(event instanceof RTCDataChannelEvent, | 
|  | 52 | 'Expect event to be instance of RTCDataChannelEvent'); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 53 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 54 | assert_equals(event.bubbles, false); | 
|  | 55 | assert_equals(event.cancelable, false); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 56 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 57 | const dc = event.channel; | 
|  | 58 | assert_true(dc instanceof RTCDataChannel, | 
|  | 59 | 'Expect channel to be instance of RTCDataChannel'); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 60 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 61 | // The channel should be in the 'open' state already. | 
|  | 62 | // See: https://github.com/w3c/webrtc-pc/pull/1851 | 
|  | 63 | assert_equals(dc.readyState, 'open', | 
|  | 64 | 'Expect channel ready state to be open'); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 65 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 66 | resolver.resolve(); | 
|  | 67 | }); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 68 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 69 | pc1.createDataChannel('fire-me!'); | 
|  | 70 |  | 
|  | 71 | exchangeIceCandidates(pc1, pc2); | 
|  | 72 | await doSignalingHandshake(pc1, pc2); | 
|  | 73 |  | 
|  | 74 | await resolver; | 
|  | 75 | }, 'Data channel event should fire when new data channel is announced to the remote peer'); | 
|  | 76 |  | 
|  | 77 | /* | 
|  | 78 | Since the channel should be in the 'open' state when dispatching via the 'datachannel' event, | 
|  | 79 | we should be able to send data in the event handler. | 
|  | 80 | */ | 
|  | 81 | promise_test(async (t) => { | 
|  | 82 | const resolver = new Resolver(); | 
|  | 83 | const pc1 = new RTCPeerConnection(); | 
|  | 84 | const pc2 = new RTCPeerConnection(); | 
|  | 85 | t.add_cleanup(() => pc1.close()); | 
|  | 86 | t.add_cleanup(() => pc2.close()); | 
|  | 87 |  | 
|  | 88 | const message = 'meow meow!'; | 
|  | 89 |  | 
|  | 90 | pc2.ondatachannel = t.step_func((event) => { | 
|  | 91 | const dc2 = event.channel; | 
|  | 92 | dc2.send(message); | 
|  | 93 | }); | 
|  | 94 |  | 
|  | 95 | const dc1 = pc1.createDataChannel('fire-me!'); | 
|  | 96 | dc1.onmessage = t.step_func((event) => { | 
|  | 97 | assert_equals(event.data, message, | 
|  | 98 | 'Received data should be equal to sent data'); | 
|  | 99 |  | 
|  | 100 | resolver.resolve(); | 
|  | 101 | }); | 
|  | 102 |  | 
|  | 103 | exchangeIceCandidates(pc1, pc2); | 
|  | 104 | await doSignalingHandshake(pc1, pc2); | 
|  | 105 |  | 
|  | 106 | await resolver; | 
|  | 107 | }, 'Should be able to send data in a datachannel event handler'); | 
|  | 108 |  | 
|  | 109 | /* | 
|  | 110 | 6.2. RTCDataChannel | 
|  | 111 | When an underlying data transport is to be announced (the other peer created a channel with | 
|  | 112 | negotiated unset or set to false), the user agent of the peer that did not initiate the | 
|  | 113 | creation process MUST queue a task to run the following steps: | 
|  | 114 | 8. Fire a datachannel event named datachannel with channel at the RTCPeerConnection object. | 
|  | 115 | 9. If the channel's [[ReadyState]] is still open, announce the data channel as open. | 
|  | 116 | */ | 
|  | 117 | promise_test(async (t) => { | 
|  | 118 | const resolver = new Resolver(); | 
|  | 119 | const pc1 = new RTCPeerConnection(); | 
|  | 120 | const pc2 = new RTCPeerConnection(); | 
|  | 121 | t.add_cleanup(() => pc1.close()); | 
|  | 122 | t.add_cleanup(() => pc2.close()); | 
|  | 123 |  | 
|  | 124 | pc2.ondatachannel = t.step_func((event) => { | 
|  | 125 | const dc = event.channel; | 
|  | 126 | dc.onopen = t.step_func(() => { | 
|  | 127 | assert_unreached('Open event should not fire'); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 128 | }); | 
|  | 129 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 130 | // This should prevent triggering the 'open' event | 
|  | 131 | dc.close(); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 132 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 133 | // Wait a bit to ensure the 'open' event does NOT fire | 
|  | 134 | t.step_timeout(() => resolver.resolve(), 500); | 
|  | 135 | }); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 136 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 137 | pc1.createDataChannel('fire-me!'); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 138 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 139 | exchangeIceCandidates(pc1, pc2); | 
|  | 140 | await doSignalingHandshake(pc1, pc2); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 141 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 142 | await resolver; | 
|  | 143 | }, 'Open event should not be raised when closing the channel in the datachannel event'); | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 144 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 145 | // Added this test as a result of the discussion in | 
|  | 146 | // https://github.com/w3c/webrtc-pc/pull/1851#discussion_r185976747 | 
|  | 147 | promise_test(async (t) => { | 
|  | 148 | const resolver = new Resolver(); | 
|  | 149 | const pc1 = new RTCPeerConnection(); | 
|  | 150 | const pc2 = new RTCPeerConnection(); | 
|  | 151 | t.add_cleanup(() => pc1.close()); | 
|  | 152 | t.add_cleanup(() => pc2.close()); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 153 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 154 | pc2.ondatachannel = t.step_func((event) => { | 
|  | 155 | const dc = event.channel; | 
|  | 156 | dc.onopen = t.step_func((event) => { | 
|  | 157 | resolver.resolve(); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 158 | }); | 
|  | 159 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 160 | // This should NOT prevent triggering the 'open' event since it enqueues at least two tasks | 
|  | 161 | t.step_timeout(() => { | 
|  | 162 | t.step_timeout(() => { | 
|  | 163 | dc.close() | 
|  | 164 | }, 1); | 
|  | 165 | }, 1); | 
|  | 166 | }); | 
|  | 167 |  | 
|  | 168 | pc1.createDataChannel('fire-me!'); | 
|  | 169 |  | 
|  | 170 | exchangeIceCandidates(pc1, pc2); | 
|  | 171 | await doSignalingHandshake(pc1, pc2); | 
|  | 172 |  | 
|  | 173 | await resolver; | 
|  | 174 | }, 'Open event should be raised when closing the channel in the datachannel event after ' + | 
|  | 175 | 'enqueuing a task'); | 
|  | 176 |  | 
|  | 177 |  | 
|  | 178 | /* | 
|  | 179 | Combination of the two tests above (send and close). | 
|  | 180 | */ | 
|  | 181 | promise_test(async (t) => { | 
|  | 182 | const resolver = new Resolver(); | 
|  | 183 | const pc1 = new RTCPeerConnection(); | 
|  | 184 | const pc2 = new RTCPeerConnection(); | 
|  | 185 | t.add_cleanup(() => pc1.close()); | 
|  | 186 | t.add_cleanup(() => pc2.close()); | 
|  | 187 |  | 
|  | 188 | const message = 'meow meow!'; | 
|  | 189 |  | 
|  | 190 | pc2.ondatachannel = t.step_func((event) => { | 
|  | 191 | const dc2 = event.channel; | 
|  | 192 | dc2.onopen = t.step_func(() => { | 
|  | 193 | assert_unreached('Open event should not fire'); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 194 | }); | 
|  | 195 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 196 | // This should send but still prevent triggering the 'open' event | 
|  | 197 | dc2.send(message); | 
|  | 198 | dc2.close(); | 
|  | 199 | }); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 200 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 201 | const dc1 = pc1.createDataChannel('fire-me!'); | 
|  | 202 | dc1.onmessage = t.step_func((event) => { | 
|  | 203 | assert_equals(event.data, message, | 
|  | 204 | 'Received data should be equal to sent data'); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 205 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 206 | resolver.resolve(); | 
|  | 207 | }); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 208 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 209 | exchangeIceCandidates(pc1, pc2); | 
|  | 210 | await doSignalingHandshake(pc1, pc2); | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 211 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 212 | await resolver; | 
|  | 213 | }, 'Open event should not be raised when sending and immediately closing the channel in the ' + | 
|  | 214 | 'datachannel event'); | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 215 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 216 | /* | 
|  | 217 | 6.2. RTCDataChannel | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 218 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 219 | interface RTCDataChannel : EventTarget { | 
|  | 220 | readonly attribute USVString label; | 
|  | 221 | readonly attribute boolean ordered; | 
|  | 222 | readonly attribute unsigned short? maxPacketLifeTime; | 
|  | 223 | readonly attribute unsigned short? maxRetransmits; | 
|  | 224 | readonly attribute USVString protocol; | 
|  | 225 | readonly attribute boolean negotiated; | 
|  | 226 | readonly attribute unsigned short? id; | 
|  | 227 | readonly attribute RTCPriorityType priority; | 
|  | 228 | readonly attribute RTCDataChannelState readyState; | 
|  | 229 | ... | 
|  | 230 | }; | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 231 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 232 | When an underlying data transport is to be announced (the other peer created a channel with | 
|  | 233 | negotiated unset or set to false), the user agent of the peer that did not initiate the | 
|  | 234 | creation process MUST queue a task to run the following steps: | 
|  | 235 | 2. Let channel be a newly created RTCDataChannel object. | 
|  | 236 | 3. Let configuration be an information bundle received from the other peer as a part of the | 
|  | 237 | process to establish the underlying data transport described by the WebRTC DataChannel | 
|  | 238 | Protocol specification [RTCWEB-DATA-PROTOCOL]. | 
|  | 239 | 4. Initialize channel's [[DataChannelLabel]], [[Ordered]], [[MaxPacketLifeTime]], | 
|  | 240 | [[MaxRetransmits]], [[DataChannelProtocol]], and [[DataChannelId]] internal slots to the | 
|  | 241 | corresponding values in configuration. | 
|  | 242 | 5. Initialize channel's [[Negotiated]] internal slot to false. | 
|  | 243 | 6. Initialize channel's [[DataChannelPriority]] internal slot based on the integer priority | 
|  | 244 | value in configuration, [...] | 
|  | 245 | 7. Set channel's [[ReadyState]] slot to connecting. | 
|  | 246 | 8. Fire a datachannel event named datachannel with channel at the RTCPeerConnection object. | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 247 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 248 | Note: More exhaustive tests are defined in RTCDataChannel-dcep | 
|  | 249 | */ | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 250 |  | 
| youennf | 0e97d09 | 2019-03-23 18:02:56 | [diff] [blame^] | 251 | promise_test(async (t) => { | 
|  | 252 | const resolver = new Resolver(); | 
|  | 253 | const pc1 = new RTCPeerConnection(); | 
|  | 254 | const pc2 = new RTCPeerConnection(); | 
|  | 255 | t.add_cleanup(() => pc1.close()); | 
|  | 256 | t.add_cleanup(() => pc2.close()); | 
|  | 257 |  | 
|  | 258 | const dc1 = pc1.createDataChannel('test', { | 
|  | 259 | ordered: false, | 
|  | 260 | maxRetransmits: 1, | 
|  | 261 | protocol: 'custom', | 
|  | 262 | priority: 'high' | 
|  | 263 | }); | 
|  | 264 |  | 
|  | 265 | assert_equals(dc1.label, 'test'); | 
|  | 266 | assert_equals(dc1.ordered, false); | 
|  | 267 | assert_equals(dc1.maxPacketLifeTime, null); | 
|  | 268 | assert_equals(dc1.maxRetransmits, 1); | 
|  | 269 | assert_equals(dc1.protocol, 'custom'); | 
|  | 270 | assert_equals(dc1.negotiated, false); | 
|  | 271 | assert_equals(dc1.priority, 'high'); | 
|  | 272 |  | 
|  | 273 | pc2.ondatachannel = t.step_func((event) => { | 
|  | 274 | const dc2 = event.channel; | 
|  | 275 | assert_true(dc2 instanceof RTCDataChannel, | 
|  | 276 | 'Expect channel to be instance of RTCDataChannel'); | 
|  | 277 |  | 
|  | 278 | assert_equals(dc2.label, 'test'); | 
|  | 279 | assert_equals(dc2.ordered, false); | 
|  | 280 | assert_equals(dc2.maxPacketLifeTime, null); | 
|  | 281 | assert_equals(dc2.maxRetransmits, 1); | 
|  | 282 | assert_equals(dc2.protocol, 'custom'); | 
|  | 283 | assert_equals(dc2.negotiated, false); | 
|  | 284 | assert_equals(dc2.id, dc1.id); | 
|  | 285 | assert_equals(dc2.priority, 'high'); | 
|  | 286 |  | 
|  | 287 | resolver.resolve(); | 
|  | 288 | }); | 
|  | 289 |  | 
|  | 290 | exchangeIceCandidates(pc1, pc2); | 
|  | 291 | await doSignalingHandshake(pc1, pc2); | 
|  | 292 |  | 
|  | 293 | await resolver; | 
|  | 294 | }, 'In-band negotiated channel created on remote peer should match the same configuration as local ' + | 
|  | 295 | 'peer'); | 
|  | 296 |  | 
|  | 297 | promise_test(async (t) => { | 
|  | 298 | const resolver = new Resolver(); | 
|  | 299 | const pc1 = new RTCPeerConnection(); | 
|  | 300 | const pc2 = new RTCPeerConnection(); | 
|  | 301 | t.add_cleanup(() => pc1.close()); | 
|  | 302 | t.add_cleanup(() => pc2.close()); | 
|  | 303 |  | 
|  | 304 | const dc1 = pc1.createDataChannel(''); | 
|  | 305 |  | 
|  | 306 | assert_equals(dc1.label, ''); | 
|  | 307 | assert_equals(dc1.ordered, true); | 
|  | 308 | assert_equals(dc1.maxPacketLifeTime, null); | 
|  | 309 | assert_equals(dc1.maxRetransmits, null); | 
|  | 310 | assert_equals(dc1.protocol, ''); | 
|  | 311 | assert_equals(dc1.negotiated, false); | 
|  | 312 | assert_equals(dc1.priority, 'low'); | 
|  | 313 |  | 
|  | 314 | pc2.ondatachannel = t.step_func((event) => { | 
|  | 315 | const dc2 = event.channel; | 
|  | 316 | assert_true(dc2 instanceof RTCDataChannel, | 
|  | 317 | 'Expect channel to be instance of RTCDataChannel'); | 
|  | 318 |  | 
|  | 319 | assert_equals(dc2.label, ''); | 
|  | 320 | assert_equals(dc2.ordered, true); | 
|  | 321 | assert_equals(dc2.maxPacketLifeTime, null); | 
|  | 322 | assert_equals(dc2.maxRetransmits, null); | 
|  | 323 | assert_equals(dc2.protocol, ''); | 
|  | 324 | assert_equals(dc2.negotiated, false); | 
|  | 325 | assert_equals(dc2.id, dc1.id); | 
|  | 326 | assert_equals(dc2.priority, 'low'); | 
|  | 327 |  | 
|  | 328 | resolver.resolve(); | 
|  | 329 | }); | 
|  | 330 |  | 
|  | 331 | exchangeIceCandidates(pc1, pc2); | 
|  | 332 | await doSignalingHandshake(pc1, pc2); | 
|  | 333 |  | 
|  | 334 | await resolver; | 
|  | 335 | }, 'In-band negotiated channel created on remote peer should match the same (default) ' + | 
|  | 336 | 'configuration as local peer'); | 
|  | 337 |  | 
|  | 338 | /* | 
|  | 339 | 6.2. RTCDataChannel | 
|  | 340 | Dictionary RTCDataChannelInit Members | 
|  | 341 | negotiated | 
|  | 342 | The default value of false tells the user agent to announce the | 
|  | 343 | channel in-band and instruct the other peer to dispatch a corresponding | 
|  | 344 | RTCDataChannel object. If set to true, it is up to the application | 
|  | 345 | to negotiate the channel and create a RTCDataChannel object with the | 
|  | 346 | same id at the other peer. | 
|  | 347 | */ | 
|  | 348 | promise_test(async (t) => { | 
|  | 349 | const resolver = new Resolver(); | 
|  | 350 | const pc1 = new RTCPeerConnection(); | 
|  | 351 | const pc2 = new RTCPeerConnection(); | 
|  | 352 | t.add_cleanup(() => pc1.close()); | 
|  | 353 | t.add_cleanup(() => pc2.close()); | 
|  | 354 |  | 
|  | 355 | pc2.ondatachannel = t.unreached_func('datachannel event should not be fired'); | 
|  | 356 |  | 
|  | 357 | pc1.createDataChannel('test', { | 
|  | 358 | negotiated: true | 
|  | 359 | }); | 
|  | 360 |  | 
|  | 361 | exchangeIceCandidates(pc1, pc2); | 
|  | 362 | await doSignalingHandshake(pc1, pc2); | 
|  | 363 |  | 
|  | 364 | // Wait a bit to ensure the 'datachannel' event does NOT fire | 
|  | 365 | t.step_timeout(() => resolver.resolve(), 500); | 
|  | 366 | await resolver; | 
|  | 367 | }, 'Negotiated channel should not fire datachannel event on remote peer'); | 
|  | 368 |  | 
|  | 369 | /* | 
|  | 370 | Non-testable | 
|  | 371 | 6.2. RTCDataChannel | 
|  | 372 | When an underlying data transport is to be announced | 
|  | 373 | 1. If the associated RTCPeerConnection object's [[isClosed]] slot | 
|  | 374 | is true, abort these steps. | 
|  | 375 |  | 
|  | 376 | The above step is not testable because to reach it we would have to | 
|  | 377 | close the peer connection just between receiving the in-band negotiated data | 
|  | 378 | channel via DCEP and firing the datachannel event. | 
|  | 379 | */ | 
| Soares Chen | 6d8970d | 2017-06-12 16:02:23 | [diff] [blame] | 380 | </script> |