Description
Details
There is no documented wsLocalSuport
capability on the PlayWright page: https://www.browserstack.com/docs/automate/playwright/playwright-capabilities
I am having a similar issue to #106. Our test suite uses the ws
package to spin up a web socket server which our AUT connects to when under test.
Everything works fine locally, and I have followed the advice on that thread, but still get the following error inside BrowserStack logs:
ERROR: WebSocket connection to 'wss://bs-local.com:12516/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
ERROR: CloseEvent
Here is the web socket and server implementation:
import { Page } from '@playwright/test';
import fs from 'fs';
import https from 'https';
import { Mockmock } from 'mockmock';
import WebSocket, { WebSocketServer } from 'ws';
import { ClientData } from '../test-data';
import { isBrowserStack } from './browserstack';
const MM = Mockmock.instance;
/**
* Sets up a dummy WebSocket server that responds with web socket data
*/
const setUpWebSocketServer = (port: number, socketId: string) => {
const server = https.createServer({
cert: fs.readFileSync('playwright/support/certs/cert.pem'),
key: fs.readFileSync('playwright/support/certs/key.pem'),
});
server.listen(port, () => {
console.log(`HTTPS server listening on port ${port}`);
});
const wss = new WebSocketServer({ server, verifyClient: () => true });
// replays mocked data every 250ms
wss.on('connection', (ws: WebSocket) => {
// recursively replays mocked data until we run out of msgs
const recursivelySendData = () => {
const frame = MM.replay(socketId, 'data');
if (typeof frame === 'undefined') {
return;
}
ws.send(JSON.stringify(frame.mock));
setTimeout(recursivelySendData, 250);
};
recursivelySendData();
ws.on('error', (err) => {
console.error(`Connetion error: ${err.message} with name ${err.name}:
${err.stack}`);
});
});
};
/**
* Here we link PlayWright logic and MockMock by intercepting all WebSocket requests.
* This is called by the setUp() method.
*
* @param page the page instance
* @param port defaults to 3030
* @param url defaults to appropriate environment websocket Url
*/
export const interceptWebSocketRequests = async (
page: Page,
port = 3030,
url = ClientData.websocketUrl
) => {
const socketId = 'wsData';
const host = isBrowserStack() ? 'bs-local.com' : 'localhost';
const wssUrl = MM.isReplaying ? `wss://${host}:${port}` : url;
// if Mockmock is recording sniff all websocket frames and save them
if (MM.isRecording) {
page.on('websocket', (ws) => {
ws.on('framereceived', (data) => {
MM.record(socketId, JSON.parse(data.payload.toString()));
});
});
}
// if Mockmock replaying we set up a local webwocket server and route traffic to it
if (MM.isReplaying) {
// intercept the payments form, replace the wss url, and relax CS policies
await page.route(`${ClientData.paymentsUrl}/**`, async (route) => {
console.log(
`Intercepted payments URL request to ${route.request().url()}`
);
const response = await route.fetch();
const frameHtml = await response.text();
const body = frameHtml.replace(ClientData.websocketUrl, wssUrl);
const headers = response.headers();
const csp = headers['content-security-policy'];
// make csp more permissive
headers['content-security-policy'] = csp.replace(
"connect-src 'self'",
"connect-src 'self' localhost:* wss://localhost:* bs-local.com:* wss://bs-local.com:*"
);
console.log(`Fulfilling with
wss url: ${wssUrl}
edited body has wss url: ${body.includes(wssUrl)}
headers: ${JSON.stringify(headers)}
`);
await route.fulfill({ response, body, headers });
});
setUpWebSocketServer(port, socketId);
}
};
Expected Behavior
The AUT, when it submits the payment form, should connect to the local secure web socket server and work the same way it does when running the tests locally.
Actual Behavior
The web socket server errors when a connection attempt is made.
ERROR: WebSocket connection to 'wss://bs-local.com:46300/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
ERROR: CloseEvent
Steps to Reproduce the Problem
-
Create a test file that acts as an AUT that connects to the secure web socket server - I can't share our application code as it's IP, but that part shouldn't be too hard.
-
Write a test that triggers the AUT connecting to your ws secure web socket server.
Platform details
- playwright version: 1.33.0
- node version: 18.9.1
- os type and version: Ubuuntu 22.04.2 LTS