diff --git a/src/polyfill/RTCDataChannel.ts b/src/polyfill/RTCDataChannel.ts index 2c7e8a7..517b8e7 100644 --- a/src/polyfill/RTCDataChannel.ts +++ b/src/polyfill/RTCDataChannel.ts @@ -11,6 +11,9 @@ export default class RTCDataChannel extends EventTarget implements globalThis.RT #maxRetransmits: number | null; #negotiated: boolean; #ordered: boolean; + #id: number + #label: string + #protocol: string #closeRequested = false; @@ -33,6 +36,9 @@ export default class RTCDataChannel extends EventTarget implements globalThis.RT this.#maxRetransmits = opts.maxRetransmits || null; this.#negotiated = opts.negotiated || false; this.#ordered = opts.ordered || true; + this.#id = this.#dataChannel.getId(); + this.#label = this.#dataChannel.getLabel(); + this.#protocol = this.#dataChannel.getProtocol(); // forward dataChannel events this.#dataChannel.onOpen(() => { @@ -131,11 +137,11 @@ export default class RTCDataChannel extends EventTarget implements globalThis.RT } get id(): number | null { - return this.#dataChannel.getId(); + return this.#id; } get label(): string { - return this.#dataChannel.getLabel(); + return this.#label; } get maxPacketLifeTime(): number | null { @@ -155,7 +161,7 @@ export default class RTCDataChannel extends EventTarget implements globalThis.RT } get protocol(): string { - return this.#dataChannel.getProtocol(); + return this.#protocol } get readyState(): globalThis.RTCDataChannelState { diff --git a/test/fixtures/event-promise.ts b/test/fixtures/event-promise.ts new file mode 100644 index 0000000..7e3851a --- /dev/null +++ b/test/fixtures/event-promise.ts @@ -0,0 +1,15 @@ +export interface EventPromiseOptions { + errorEvent?: string +} + +export async function eventPromise (emitter: EventTarget, event: string, opts?: EventPromiseOptions): Promise { + return new Promise((resolve, reject) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + emitter.addEventListener(event, (evt: any) => { + resolve(evt); + }); + emitter.addEventListener(opts?.errorEvent ?? 'error', (err) => { + reject(err); + }); + }); +} diff --git a/test/jest-tests/polyfill.test.ts b/test/jest-tests/polyfill.test.ts index 84b265a..4dfd7b9 100644 --- a/test/jest-tests/polyfill.test.ts +++ b/test/jest-tests/polyfill.test.ts @@ -2,6 +2,7 @@ import { expect, jest } from '@jest/globals'; import { RTCPeerConnection } from '../../src/polyfill/index'; import { PeerConnection } from '../../src/lib/index'; +import { eventPromise } from '../fixtures/event-promise'; describe('polyfill', () => { // Default is 5000 ms but we need more @@ -226,6 +227,51 @@ describe('polyfill', () => { }); }); + test('it can access datachannel informational fields after closing', async () => { + const peer1 = new RTCPeerConnection(); + const peer2 = new RTCPeerConnection(); + + const label = 'label' + const protocol = 'protocol' + + const dc: RTCDataChannel = peer1.createDataChannel(label, { + protocol + }); + + // Actions + const peer1Offer = await peer1.createOffer(); + await peer2.setRemoteDescription(peer1Offer); + + const peer2Answer = await peer2.createAnswer(); + await peer1.setRemoteDescription(peer2Answer); + + peer1.addEventListener('icecandidate', (e: RTCPeerConnectionIceEvent) => { + peer2.addIceCandidate(e.candidate); + }); + + peer2.addEventListener('icecandidate', (e: RTCPeerConnectionIceEvent) => { + peer1.addIceCandidate(e.candidate); + }); + + await eventPromise(dc, 'open'); + + const id = dc.id; + expect(dc.label).toEqual(label); + expect(dc.protocol).toEqual(protocol); + + peer1.close(); + peer2.close(); + + if (dc.readyState !== 'closed') { + await eventPromise(dc, 'close'); + } + + expect(dc.readyState).toEqual('closed'); + expect(dc.id).toEqual(id); + expect(dc.label).toEqual(label); + expect(dc.protocol).toEqual(protocol); + }); + test('it should accept a preconfigured PeerConnection', () => { const peerConnection = new PeerConnection('Peer', { iceServers: [],