fix: support connectOverCDP over https (#8703)
This commit is contained in:
parent
e5e461c0de
commit
152f6c6f1c
|
|
@ -34,6 +34,7 @@ import { TimeoutSettings } from '../../utils/timeoutSettings';
|
||||||
import { helper } from '../helper';
|
import { helper } from '../helper';
|
||||||
import { CallMetadata } from '../instrumentation';
|
import { CallMetadata } from '../instrumentation';
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
|
import https from 'https';
|
||||||
import { registry } from '../../utils/registry';
|
import { registry } from '../../utils/registry';
|
||||||
|
|
||||||
const ARTIFACTS_FOLDER = path.join(os.tmpdir(), 'playwright-artifacts-');
|
const ARTIFACTS_FOLDER = path.join(os.tmpdir(), 'playwright-artifacts-');
|
||||||
|
|
@ -219,8 +220,9 @@ async function urlToWSEndpoint(endpointURL: string) {
|
||||||
if (endpointURL.startsWith('ws'))
|
if (endpointURL.startsWith('ws'))
|
||||||
return endpointURL;
|
return endpointURL;
|
||||||
const httpURL = endpointURL.endsWith('/') ? `${endpointURL}json/version/` : `${endpointURL}/json/version/`;
|
const httpURL = endpointURL.endsWith('/') ? `${endpointURL}json/version/` : `${endpointURL}/json/version/`;
|
||||||
|
const request = endpointURL.startsWith('https') ? https : http;
|
||||||
const json = await new Promise<string>((resolve, reject) => {
|
const json = await new Promise<string>((resolve, reject) => {
|
||||||
http.get(httpURL, resp => {
|
request.get(httpURL, resp => {
|
||||||
if (resp.statusCode! < 200 || resp.statusCode! >= 400) {
|
if (resp.statusCode! < 200 || resp.statusCode! >= 400) {
|
||||||
reject(new Error(`Unexpected status ${resp.statusCode} when connecting to ${httpURL}.\n` +
|
reject(new Error(`Unexpected status ${resp.statusCode} when connecting to ${httpURL}.\n` +
|
||||||
`This does not look like a DevTools server, try connecting via ws://.`));
|
`This does not look like a DevTools server, try connecting via ws://.`));
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,44 @@ import { playwrightTest as test, expect } from './config/browserTest';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { getUserAgent } from '../lib/utils/utils';
|
import { getUserAgent } from '../lib/utils/utils';
|
||||||
|
import WebSocket from 'ws';
|
||||||
|
|
||||||
test.slow(true, 'All connect tests are slow');
|
test.slow(true, 'All connect tests are slow');
|
||||||
|
|
||||||
|
test('should connect over wss', async ({browserType , startRemoteServer, httpsServer}) => {
|
||||||
|
const remoteServer = await startRemoteServer();
|
||||||
|
|
||||||
|
const oldValue = process.env['NODE_TLS_REJECT_UNAUTHORIZED'];
|
||||||
|
// https://stackoverflow.com/a/21961005/552185
|
||||||
|
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
|
||||||
|
try {
|
||||||
|
httpsServer.onceWebSocketConnection((ws, request) => {
|
||||||
|
const remote = new WebSocket(remoteServer.wsEndpoint(), [], {
|
||||||
|
perMessageDeflate: false,
|
||||||
|
maxPayload: 256 * 1024 * 1024, // 256Mb,
|
||||||
|
});
|
||||||
|
const remoteReadyPromise = new Promise<void>((f, r) => {
|
||||||
|
remote.once('open', f);
|
||||||
|
remote.once('error', r);
|
||||||
|
});
|
||||||
|
remote.on('close', () => ws.close());
|
||||||
|
remote.on('error', error => ws.close());
|
||||||
|
remote.on('message', message => ws.send(message));
|
||||||
|
ws.on('message', async message => {
|
||||||
|
await remoteReadyPromise;
|
||||||
|
remote.send(message);
|
||||||
|
});
|
||||||
|
ws.on('close', () => remote.close());
|
||||||
|
ws.on('error', () => remote.close());
|
||||||
|
});
|
||||||
|
const browser = await browserType.connect(`wss://localhost:${httpsServer.PORT}/ws`);
|
||||||
|
expect(browser.version()).toBeTruthy();
|
||||||
|
await browser.close();
|
||||||
|
} finally {
|
||||||
|
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = oldValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('should be able to reconnect to a browser', async ({browserType, startRemoteServer, server}) => {
|
test('should be able to reconnect to a browser', async ({browserType, startRemoteServer, server}) => {
|
||||||
const remoteServer = await startRemoteServer();
|
const remoteServer = await startRemoteServer();
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -286,6 +286,39 @@ playwrightTest('should report all pages in an existing browser', async ({ browse
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
playwrightTest('should connect via https', async ({ browserType, browserOptions, httpsServer }, testInfo) => {
|
||||||
|
const port = 9339 + testInfo.workerIndex;
|
||||||
|
const browserServer = await browserType.launch({
|
||||||
|
...browserOptions,
|
||||||
|
args: ['--remote-debugging-port=' + port]
|
||||||
|
});
|
||||||
|
const json = await new Promise<string>((resolve, reject) => {
|
||||||
|
http.get(`http://localhost:${port}/json/version/`, resp => {
|
||||||
|
let data = '';
|
||||||
|
resp.on('data', chunk => data += chunk);
|
||||||
|
resp.on('end', () => resolve(data));
|
||||||
|
}).on('error', reject);
|
||||||
|
});
|
||||||
|
httpsServer.setRoute('/json/version/', (req, res) => {
|
||||||
|
res.writeHead(200);
|
||||||
|
res.end(json);
|
||||||
|
});
|
||||||
|
const oldValue = process.env['NODE_TLS_REJECT_UNAUTHORIZED'];
|
||||||
|
// https://stackoverflow.com/a/21961005/552185
|
||||||
|
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
|
||||||
|
try {
|
||||||
|
const cdpBrowser = await browserType.connectOverCDP(`https://localhost:${httpsServer.PORT}/`);
|
||||||
|
const contexts = cdpBrowser.contexts();
|
||||||
|
expect(contexts.length).toBe(1);
|
||||||
|
for (let i = 0; i < 3; i++)
|
||||||
|
await contexts[0].newPage();
|
||||||
|
await cdpBrowser.close();
|
||||||
|
} finally {
|
||||||
|
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = oldValue;
|
||||||
|
await browserServer.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
playwrightTest('should return valid browser from context.browser()', async ({ browserType, browserOptions }, testInfo) => {
|
playwrightTest('should return valid browser from context.browser()', async ({ browserType, browserOptions }, testInfo) => {
|
||||||
const port = 9339 + testInfo.workerIndex;
|
const port = 9339 + testInfo.workerIndex;
|
||||||
const browserServer = await browserType.launch({
|
const browserServer = await browserType.launch({
|
||||||
|
|
|
||||||
2
utils/testserver/index.d.ts
vendored
2
utils/testserver/index.d.ts
vendored
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
type ServerResponse = import('http').ServerResponse;
|
type ServerResponse = import('http').ServerResponse;
|
||||||
type IncomingMessage = import('http').IncomingMessage;
|
type IncomingMessage = import('http').IncomingMessage;
|
||||||
|
import WebSocket from 'ws';
|
||||||
|
|
||||||
export class TestServer {
|
export class TestServer {
|
||||||
static create(dirPath: string, port: number, loopback?: string): Promise<TestServer>;
|
static create(dirPath: string, port: number, loopback?: string): Promise<TestServer>;
|
||||||
|
|
@ -30,6 +31,7 @@ export class TestServer {
|
||||||
setRedirect(from: string, to: string);
|
setRedirect(from: string, to: string);
|
||||||
waitForRequest(path: string): Promise<IncomingMessage & { postBody: Promise<Buffer> }>;
|
waitForRequest(path: string): Promise<IncomingMessage & { postBody: Promise<Buffer> }>;
|
||||||
waitForWebSocketConnectionRequest(): Promise<IncomingMessage>;
|
waitForWebSocketConnectionRequest(): Promise<IncomingMessage>;
|
||||||
|
onceWebSocketConnection(handler: (ws: WebSocket, request: IncomingMessage) => void);
|
||||||
sendOnWebSocketConnection(data: string);
|
sendOnWebSocketConnection(data: string);
|
||||||
reset();
|
reset();
|
||||||
serveFile(request: IncomingMessage, response: ServerResponse);
|
serveFile(request: IncomingMessage, response: ServerResponse);
|
||||||
|
|
|
||||||
|
|
@ -323,6 +323,10 @@ class TestServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onceWebSocketConnection(handler) {
|
||||||
|
this._wsServer.once('connection', handler);
|
||||||
|
}
|
||||||
|
|
||||||
waitForWebSocketConnectionRequest() {
|
waitForWebSocketConnectionRequest() {
|
||||||
return new Promise(fullfil => {
|
return new Promise(fullfil => {
|
||||||
this._wsServer.once('connection', (ws, req) => fullfil(req));
|
this._wsServer.once('connection', (ws, req) => fullfil(req));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue