| <!doctype html> | |
| <meta charset=utf-8> | |
| <meta name="variant" content="?interop-2026"> | |
| <meta name="variant" content="?rest"> | |
| <title></title> | |
| <script src=/resources/testharness.js></script> | |
| <script src=/resources/testharnessreport.js></script> | |
| <script src="RTCPeerConnection-helper.js"></script> | |
| <script> | |
| "use strict"; | |
| const rest = !new URLSearchParams(location.search).has("interop-2026"); | |
| const interop2026 = !new URLSearchParams(location.search).has("rest"); | |
| const kSmallTimeoutMs = 100; | |
| if (rest) { | |
| promise_test(async t => { | |
| const offerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => offerer.close()); | |
| const signalingStateChangeEvent | |
| = new EventWatcher(t, offerer, 'signalingstatechange') | |
| .wait_for('signalingstatechange'); | |
| await offerer.setLocalDescription(); | |
| await signalingStateChangeEvent; | |
| assert_equals(offerer.signalingState, 'have-local-offer'); | |
| }, "Parameterless SLD() in 'stable' goes to 'have-local-offer'"); | |
| promise_test(async t => { | |
| const offerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => offerer.close()); | |
| await offerer.setLocalDescription(); | |
| assert_not_equals(offerer.pendingLocalDescription, null); | |
| assert_equals(offerer.pendingLocalDescription, offerer.pendingLocalDescription); | |
| }, "Parameterless SLD() in 'stable' sets pendingLocalDescription"); | |
| promise_test(async t => { | |
| const offerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => offerer.close()); | |
| const transceiver = offerer.addTransceiver('audio'); | |
| assert_equals(transceiver.mid, null); | |
| await offerer.setLocalDescription(); | |
| assert_not_equals(transceiver.mid, null); | |
| }, "Parameterless SLD() in 'stable' assigns transceiver.mid"); | |
| promise_test(async t => { | |
| const offerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => offerer.close()); | |
| const answerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => answerer.close()); | |
| await answerer.setRemoteDescription(await offerer.createOffer()); | |
| const signalingStateChangeEvent | |
| = new EventWatcher(t, answerer, 'signalingstatechange') | |
| .wait_for('signalingstatechange'); | |
| await answerer.setLocalDescription(); | |
| await signalingStateChangeEvent; | |
| assert_equals(answerer.signalingState, 'stable'); | |
| }, "Parameterless SLD() in 'have-remote-offer' goes to 'stable'"); | |
| promise_test(async t => { | |
| const offerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => offerer.close()); | |
| const answerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => answerer.close()); | |
| await answerer.setRemoteDescription(await offerer.createOffer()); | |
| await answerer.setLocalDescription(); | |
| assert_not_equals(answerer.currentLocalDescription, null); | |
| assert_equals(answerer.currentLocalDescription, answerer.currentLocalDescription); | |
| }, "Parameterless SLD() in 'have-remote-offer' sets currentLocalDescription"); | |
| promise_test(async t => { | |
| const offerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => offerer.close()); | |
| const answerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => answerer.close()); | |
| offerer.addTransceiver('audio'); | |
| const onTransceiverPromise = new Promise(resolve => | |
| answerer.ontrack = e => resolve(e.transceiver)); | |
| await answerer.setRemoteDescription(await offerer.createOffer()); | |
| const transceiver = await onTransceiverPromise; | |
| await answerer.setLocalDescription(); | |
| assert_equals(transceiver.currentDirection, 'recvonly'); | |
| }, "Parameterless SLD() in 'have-remote-offer' sets " + | |
| "transceiver.currentDirection"); | |
| promise_test(async t => { | |
| const offerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => offerer.close()); | |
| const offer = await offerer.createOffer(); | |
| await offerer.setLocalDescription(); | |
| // assert_true() is used rather than assert_equals() so that if the assertion | |
| // fails, the -expected.txt file is not different on each run. | |
| assert_true(offerer.pendingLocalDescription.sdp == offer.sdp, | |
| "offerer.pendingLocalDescription.sdp == offer.sdp"); | |
| }, "Parameterless SLD() uses [[LastCreatedOffer]] if it is still valid"); | |
| promise_test(async t => { | |
| const offerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => offerer.close()); | |
| const answerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => answerer.close()); | |
| await answerer.setRemoteDescription(await offerer.createOffer()); | |
| const answer = await answerer.createAnswer(); | |
| await answerer.setLocalDescription(); | |
| // assert_true() is used rather than assert_equals() so that if the assertion | |
| // fails, the -expected.txt file is not different on each run. | |
| assert_true(answerer.currentLocalDescription.sdp == answer.sdp, | |
| "answerer.currentLocalDescription.sdp == answer.sdp"); | |
| }, "Parameterless SLD() uses [[LastCreatedAnswer]] if it is still valid"); | |
| promise_test(async t => { | |
| const offerer = new RTCPeerConnection(); | |
| offerer.close(); | |
| try { | |
| await offerer.setLocalDescription(); | |
| assert_unreached(); | |
| } catch (e) { | |
| assert_equals(e.name, "InvalidStateError"); | |
| } | |
| }, "Parameterless SLD() rejects with InvalidStateError if already closed"); | |
| promise_test(async t => { | |
| const offerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => offerer.close()); | |
| const p = Promise.race([ | |
| offerer.setLocalDescription(), | |
| new Promise(r => t.step_timeout(() => r("timeout"), kSmallTimeoutMs)) | |
| ]); | |
| offerer.close(); | |
| assert_equals(await p, "timeout"); | |
| }, "Parameterless SLD() never settles if closed while pending"); | |
| promise_test(async t => { | |
| const offerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => offerer.close()); | |
| const answerer = new RTCPeerConnection(); | |
| t.add_cleanup(() => answerer.close()); | |
| // Implicitly create an offer. | |
| await offerer.setLocalDescription(); | |
| await answerer.setRemoteDescription(offerer.pendingLocalDescription); | |
| // Implicitly create an answer. | |
| await answerer.setLocalDescription(); | |
| await offerer.setRemoteDescription(answerer.currentLocalDescription); | |
| }, "Parameterless SLD() in a full O/A exchange succeeds"); | |
| promise_test(async t => { | |
| const answerer = new RTCPeerConnection(); | |
| try { | |
| await answerer.setRemoteDescription(); | |
| assert_unreached(); | |
| } catch (e) { | |
| assert_equals(e.name, "TypeError"); | |
| } | |
| }, "Parameterless SRD() rejects with TypeError."); | |
| } // rest | |
| if (interop2026) { | |
| promise_test(async t => { | |
| const offerer = new RTCPeerConnection(); | |
| const {sdp} = await offerer.createOffer(); | |
| new RTCSessionDescription({type: "offer", sdp}); | |
| try { | |
| new RTCSessionDescription({sdp}); | |
| assert_unreached(); | |
| } catch (e) { | |
| assert_equals(e.name, "TypeError"); | |
| } | |
| }, "RTCSessionDescription constructed without type throws TypeError"); | |
| } // interop2026 | |
| </script> |