blob: 1070ee701d2336cfb14c7370f9db25daf5922d7b [file] [log] [blame]
Soares Chen6d8970d2017-06-12 16:02:231<!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>
8 'use strict';
9
10 // Test is based on the following editor draft:
11 // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
12
13 // The following helper functions are called from RTCPeerConnection-helper.js:
14 // exchangeIceCandidates
15 // doSignalingHandshake
16
17 /*
18 6.2. RTCDataChannel
19 When an underlying data transport is to be announced
20 2. Let channel be a newly created RTCDataChannel object.
21 5. Set channel's readyState attribute to connecting.
22 6. Fire a datachannel event named datachannel with channel at the
23 RTCPeerConnection object.
24
25 6.3. RTCDataChannelEvent
26 Firing a datachannel event named e with a RTCDataChannel channel means
27 that an event with the name e, which does not bubble (except where
28 otherwise stated) and is not cancelable (except where otherwise stated),
29 and which uses the RTCDataChannelEvent interface with the channel
30 attribute set to channel, must be created and dispatched at the given
31 target.
32
33 interface RTCDataChannelEvent : Event {
34 readonly attribute RTCDataChannel channel;
35 };
36 */
37 async_test(t => {
38 const localPc = new RTCPeerConnection();
Philipp Hancke1622a022018-06-11 10:00:5339 t.add_cleanup(() => localPc.close());
Soares Chen6d8970d2017-06-12 16:02:2340 const remotePc = new RTCPeerConnection();
41
Philipp Hancke1622a022018-06-11 10:00:5342 t.add_cleanup(() => remotePc.close());
43
Soares Chen6d8970d2017-06-12 16:02:2344 let eventCount = 0;
45
46 const onDataChannel = t.step_func_done(event => {
47 eventCount++;
48 assert_equals(eventCount, 1,
49 'Expect data channel event to fire exactly once');
50
51 assert_true(event instanceof RTCDataChannelEvent,
52 'Expect event to be instance of RTCDataChannelEvent');
53
54 assert_equals(event.bubbles, false);
55 assert_equals(event.cancelable, false);
56
57 const { channel } = event;
58 assert_true(channel instanceof RTCDataChannel,
59 'Expect channel to be instance of RTCDataChannel');
60
61 const { readyState } = channel;
62
63 // The spec requires readyState to be connecting at first,
64 // but it may quickly change to open before the callback
65 // is invoked, especially with local connections.
66 assert_true(readyState === 'connecting' || readyState === 'open',
67 'Expect channel ready state to be either connecting or open');
68 });
69
70 localPc.createDataChannel('test');
71
72 remotePc.addEventListener('datachannel', onDataChannel);
73 exchangeIceCandidates(localPc, remotePc);
74 doSignalingHandshake(localPc, remotePc);
Soares Chen6d8970d2017-06-12 16:02:2375 }, 'datachannel event should fire when new data channel is announced to the remote peer');
76
77 /*
78 6.2. RTCDataChannel
79 interface RTCDataChannel : EventTarget {
80 readonly attribute USVString label;
81 readonly attribute boolean ordered;
82 readonly attribute unsigned short? maxPacketLifeTime;
83 readonly attribute unsigned short? maxRetransmits;
84 readonly attribute USVString protocol;
85 readonly attribute boolean negotiated;
86 readonly attribute unsigned short? id;
87 readonly attribute RTCPriorityType priority;
88 readonly attribute RTCDataChannelState readyState;
89 ...
90 };
91
92 When an underlying data transport is to be announced
93 3. Let configuration be an information bundle received from the
94 other peer as a part of the process to establish the underlying
95 data transport described by the WebRTC DataChannel Protocol
96 specification [RTCWEB-DATA-PROTOCOL].
97 4. Initialize channel's label, ordered, maxPacketLifeTime,
98 maxRetransmits, protocol, negotiated and id attributes to their
99 corresponding values in configuration.
100 */
101 async_test(t => {
102 const localPc = new RTCPeerConnection();
Philipp Hancke1622a022018-06-11 10:00:53103 t.add_cleanup(() => localPc.close());
Soares Chen6d8970d2017-06-12 16:02:23104 const remotePc = new RTCPeerConnection();
105
Philipp Hancke1622a022018-06-11 10:00:53106 t.add_cleanup(() => remotePc.close());
107
Soares Chen6d8970d2017-06-12 16:02:23108 const onDataChannel = t.step_func_done(event => {
109 const remoteChannel = event.channel;
110 assert_true(remoteChannel instanceof RTCDataChannel,
111 'Expect channel to be instance of RTCDataChannel');
112
113 assert_equals(remoteChannel.label, 'test');
114 assert_equals(remoteChannel.id, 8);
115 assert_equals(remoteChannel.ordered, false);
116 assert_equals(remoteChannel.maxRetransmits, 1);
117 assert_equals(remoteChannel.protocol, 'custom');
118 assert_equals(remoteChannel.priority, 'high');
119 });
120
121 const localChannel = localPc.createDataChannel('test', {
122 id: 8,
123 ordered: false,
124 maxRetransmits: 1,
125 protocol: 'custom',
126 priority: 'high'
127 });
128
129 assert_equals(localChannel.label, 'test');
130 assert_equals(localChannel.id, 8);
131 assert_equals(localChannel.ordered, false);
132 assert_equals(localChannel.maxRetransmits, 1);
133 assert_equals(localChannel.protocol, 'custom');
134 assert_equals(localChannel.priority, 'high');
135
136 remotePc.addEventListener('datachannel', onDataChannel);
137 exchangeIceCandidates(localPc, remotePc);
138 doSignalingHandshake(localPc, remotePc);
139 }, 'Data channel created on remote peer should match the same configuration as local peer');
140
141 /*
142 6.2. RTCDataChannel
143 Dictionary RTCDataChannelInit Members
144 negotiated
145 The default value of false tells the user agent to announce the
146 channel in-band and instruct the other peer to dispatch a corresponding
147 RTCDataChannel object. If set to true, it is up to the application
148 to negotiate the channel and create a RTCDataChannel object with the
149 same id at the other peer.
150 */
151 async_test(t => {
152 const localPc = new RTCPeerConnection();
Philipp Hancke1622a022018-06-11 10:00:53153 t.add_cleanup(() => localPc.close());
Soares Chen6d8970d2017-06-12 16:02:23154 const remotePc = new RTCPeerConnection();
155
Philipp Hancke1622a022018-06-11 10:00:53156 t.add_cleanup(() => remotePc.close());
157
Soares Chen6d8970d2017-06-12 16:02:23158 const onDataChannel = t.unreached_func('datachannel event should not be fired');
159
160 localPc.createDataChannel('test', {
161 negotiated: true
162 });
163
164 remotePc.addEventListener('datachannel', onDataChannel);
165 exchangeIceCandidates(localPc, remotePc);
166 doSignalingHandshake(localPc, remotePc);
167
168 t.step_timeout(t.step_func_done(), 200);
Soares Chen6d8970d2017-06-12 16:02:23169 }, 'Data channel created with negotiated set to true should not fire datachannel event on remote peer');
170
171 /*
172 Non-testable
173 6.2. RTCDataChannel
174 When an underlying data transport is to be announced
175 1. If the associated RTCPeerConnection object's [[isClosed]] slot
176 is true, abort these steps.
177
178 The above step is not testable because to reach it we would have to
179 close the peer connection after the remote peer call
180 setLocalDescription(answer) but before the underlying data transport
181 is connected. This require the promise callback for setLocalDescription()
182 to be called at the right moment, which is not always possible.
183 */
184</script>