Repair connectivity correctly v1
This commit is contained in:
@@ -11,6 +11,7 @@ import { type Page } from '@playwright/test';
|
||||
export async function installWebRTCTracking(page: Page): Promise<void> {
|
||||
await page.addInitScript(() => {
|
||||
const connections: RTCPeerConnection[] = [];
|
||||
const dataChannels: RTCDataChannel[] = [];
|
||||
const syntheticMediaResources: {
|
||||
audioCtx: AudioContext;
|
||||
source?: AudioScheduledSourceNode;
|
||||
@@ -18,20 +19,40 @@ export async function installWebRTCTracking(page: Page): Promise<void> {
|
||||
}[] = [];
|
||||
|
||||
(window as any).__rtcConnections = connections;
|
||||
(window as any).__rtcDataChannels = dataChannels;
|
||||
(window as any).__rtcRemoteTracks = [] as { kind: string; id: string; readyState: string }[];
|
||||
(window as any).__rtcSyntheticMediaResources = syntheticMediaResources;
|
||||
|
||||
const OriginalRTCPeerConnection = window.RTCPeerConnection;
|
||||
const trackDataChannel = (channel: RTCDataChannel) => {
|
||||
if (dataChannels.includes(channel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dataChannels.push(channel);
|
||||
};
|
||||
|
||||
(window as any).RTCPeerConnection = function(this: RTCPeerConnection, ...args: any[]) {
|
||||
const pc: RTCPeerConnection = new OriginalRTCPeerConnection(...args);
|
||||
const originalCreateDataChannel = pc.createDataChannel.bind(pc);
|
||||
|
||||
connections.push(pc);
|
||||
|
||||
pc.createDataChannel = ((label: string, options?: RTCDataChannelInit) => {
|
||||
const channel = originalCreateDataChannel(label, options);
|
||||
|
||||
trackDataChannel(channel);
|
||||
return channel;
|
||||
}) as RTCPeerConnection['createDataChannel'];
|
||||
|
||||
pc.addEventListener('connectionstatechange', () => {
|
||||
(window as any).__lastRtcState = pc.connectionState;
|
||||
});
|
||||
|
||||
pc.addEventListener('datachannel', (event: RTCDataChannelEvent) => {
|
||||
trackDataChannel(event.channel);
|
||||
});
|
||||
|
||||
pc.addEventListener('track', (event: RTCTrackEvent) => {
|
||||
(window as any).__rtcRemoteTracks.push({
|
||||
kind: event.track.kind,
|
||||
@@ -211,6 +232,66 @@ export async function waitForConnectedPeerCount(page: Page, expectedCount: numbe
|
||||
);
|
||||
}
|
||||
|
||||
/** Returns the number of tracked RTCDataChannels in the open state. */
|
||||
export async function getOpenDataChannelCount(page: Page): Promise<number> {
|
||||
return page.evaluate(
|
||||
() => ((window as any).__rtcDataChannels as RTCDataChannel[] | undefined)?.filter(
|
||||
(channel) => channel.readyState === 'open'
|
||||
).length ?? 0
|
||||
);
|
||||
}
|
||||
|
||||
/** Wait until the expected number of tracked RTCDataChannels are open. */
|
||||
export async function waitForOpenDataChannelCount(page: Page, expectedCount: number, timeout = 45_000): Promise<void> {
|
||||
await page.waitForFunction(
|
||||
(count) => ((window as any).__rtcDataChannels as RTCDataChannel[] | undefined)?.filter(
|
||||
(channel) => channel.readyState === 'open'
|
||||
).length === count,
|
||||
expectedCount,
|
||||
{ timeout }
|
||||
);
|
||||
}
|
||||
|
||||
/** Close every currently-open RTCDataChannel and return how many were closed. */
|
||||
export async function closeOpenDataChannels(page: Page): Promise<number> {
|
||||
return page.evaluate(() => {
|
||||
const channels = ((window as any).__rtcDataChannels as RTCDataChannel[] | undefined) ?? [];
|
||||
|
||||
let closed = 0;
|
||||
|
||||
for (const channel of channels) {
|
||||
if (channel.readyState !== 'open') {
|
||||
continue;
|
||||
}
|
||||
|
||||
channel.close();
|
||||
closed++;
|
||||
}
|
||||
|
||||
return closed;
|
||||
});
|
||||
}
|
||||
|
||||
/** Dispatch a synthetic data-channel error event on each open channel. */
|
||||
export async function dispatchDataChannelErrors(page: Page): Promise<number> {
|
||||
return page.evaluate(() => {
|
||||
const channels = ((window as any).__rtcDataChannels as RTCDataChannel[] | undefined) ?? [];
|
||||
|
||||
let dispatched = 0;
|
||||
|
||||
for (const channel of channels) {
|
||||
if (channel.readyState !== 'open') {
|
||||
continue;
|
||||
}
|
||||
|
||||
channel.dispatchEvent(new Event('error'));
|
||||
dispatched++;
|
||||
}
|
||||
|
||||
return dispatched;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume all suspended AudioContext instances created by the synthetic
|
||||
* media patch. Uses CDP `Runtime.evaluate` with `userGesture: true` so
|
||||
|
||||
Reference in New Issue
Block a user