Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
- /webrtc/RTCPeerConnection-addIceCandidate-timing.https.html - WPT Dashboard Interop Dashboard
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
'use strict';
// In this test, the promises should resolve in the execution order
// (setLocalDescription, setLocalDescription, addIceCandidate) as is ensured by
// the Operations Chain; if an operation is pending, executing another operation
// will queue it. This test will fail if an Operations Chain is not implemented,
// but it gives the implementation some slack: it only ensures that
// addIceCandidate() is not resolved first, allowing timing issues in resolving
// promises where the test still passes even if addIceCandidate() is resolved
// *before* the second setLocalDescription().
//
// require setLocalDescription-promises to resolve immediately which is another
// test.
// in Chrome.
promise_test(async t => {
const caller = new RTCPeerConnection();
t.add_cleanup(() => caller.close());
const callee = new RTCPeerConnection();
t.add_cleanup(() => callee.close());
caller.addTransceiver('audio');
const candidatePromise = new Promise(resolve => {
caller.onicecandidate = e => resolve(e.candidate);
});
await caller.setLocalDescription(await caller.createOffer());
await callee.setRemoteDescription(caller.localDescription);
const candidate = await candidatePromise;
// Chain setLocalDescription(), setLocalDescription() and addIceCandidate()
// without performing await between the calls.
const pendingPromises = [];
const resolveOrder = [];
pendingPromises.push(callee.setLocalDescription().then(() => {
resolveOrder.push('setLocalDescription 1');
}));
pendingPromises.push(callee.setLocalDescription().then(() => {
resolveOrder.push('setLocalDescription 2');
}));
pendingPromises.push(callee.addIceCandidate(candidate).then(() => {
resolveOrder.push('addIceCandidate');
}));
await Promise.all(pendingPromises);
assert_equals(resolveOrder[0], 'setLocalDescription 1');
}, 'addIceCandidate is not resolved first if 2x setLocalDescription ' +
'operations are pending');
promise_test(async t => {
const caller = new RTCPeerConnection();
t.add_cleanup(() => caller.close());
const callee = new RTCPeerConnection();
t.add_cleanup(() => callee.close());
caller.addTransceiver('audio');
const candidatePromise = new Promise(resolve => {
caller.onicecandidate = e => resolve(e.candidate);
});
await caller.setLocalDescription(await caller.createOffer());
await callee.setRemoteDescription(caller.localDescription);
const candidate = await candidatePromise;
// Chain setLocalDescription(), setLocalDescription() and addIceCandidate()
// without performing await between the calls.
const pendingPromises = [];
const resolveOrder = [];
pendingPromises.push(callee.setLocalDescription().then(() => {
resolveOrder.push('setLocalDescription 1');
}));
pendingPromises.push(callee.setLocalDescription().then(() => {
resolveOrder.push('setLocalDescription 2');
}));
pendingPromises.push(callee.addIceCandidate(candidate).then(() => {
resolveOrder.push('addIceCandidate');
}));
await Promise.all(pendingPromises);
// ICE candidate exchange issues described in
assert_array_equals(
resolveOrder,
['setLocalDescription 1', 'setLocalDescription 2', 'addIceCandidate']);
}, 'addIceCandidate and setLocalDescription are resolved in the correct ' +
'order, as defined by the operations chain specification');
promise_test(async t => {
const caller = new RTCPeerConnection();
t.add_cleanup(() => caller.close());
const callee = new RTCPeerConnection();
t.add_cleanup(() => callee.close());
caller.addTransceiver('audio');
let events = [];
let pendingPromises = [];
const onCandidatePromise = new Promise(resolve => {
caller.onicecandidate = () => {
events.push('candidate generated');
resolve();
}
});
pendingPromises.push(onCandidatePromise);
pendingPromises.push(caller.setLocalDescription().then(() => {
events.push('setLocalDescription');
}));
await Promise.all(pendingPromises);
assert_array_equals(events, ['setLocalDescription', 'candidate generated']);
}, 'onicecandidate fires after resolving setLocalDescription in offerer');
promise_test(async t => {
const caller = new RTCPeerConnection();
t.add_cleanup(() => caller.close());
const callee = new RTCPeerConnection();
t.add_cleanup(() => callee.close());
caller.addTransceiver('audio');
let events = [];
let pendingPromises = [];
caller.onicecandidate = (ev) => {
if (ev.candidate) {
callee.addIceCandidate(ev.candidate);
}
}
const offer = await caller.createOffer();
const onCandidatePromise = new Promise(resolve => {
callee.onicecandidate = () => {
events.push('candidate generated');
resolve();
}
});
await callee.setRemoteDescription(offer);
const answer = await callee.createAnswer();
pendingPromises.push(onCandidatePromise);
pendingPromises.push(callee.setLocalDescription(answer).then(() => {
events.push('setLocalDescription');
}));
await Promise.all(pendingPromises);
assert_array_equals(events, ['setLocalDescription', 'candidate generated']);
}, 'onicecandidate fires after resolving setLocalDescription in answerer');
</script>