testplane
Version:
Tests framework based on mocha and wdio
261 lines • 12 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WSDriverRequestAgent = void 0;
const http_1 = require("http");
const node_util_1 = require("node:util");
const debug_1 = require("./debug");
const error_1 = require("./error");
const constants_1 = require("./constants");
const types_1 = require("./types");
const logger = __importStar(require("../../utils/logger"));
const ws_connection_1 = require("../../ws-connection");
const constants_2 = require("../../ws-connection/constants");
const error_2 = require("../../ws-connection/error");
const response_1 = require("./response");
const request_1 = require("./request");
const utils_1 = require("../../ws-connection/utils");
class WSDriverRequestAgent {
constructor(wsdWsEndpoint, { sessionId, headers, requestTimeout, clientSupportedCompressionTypes }) {
headers ||= {};
headers[constants_1.WSD_ACCEPT_ENCODING_HEADER] = clientSupportedCompressionTypes.join(", ");
this._wsConnection = new ws_connection_1.WsConnection(wsdWsEndpoint, {
headers,
debugFn: debug_1.debugWSDriver,
retries: {
count: constants_1.WSD_CONNECTION_RETRIES,
baseDelay: constants_1.WSD_CONNECTION_RETRY_BASE_DELAY,
},
timeouts: {
request: requestTimeout,
createSession: constants_1.WSD_CONNECTION_TIMEOUT,
},
errors: {
ConnectionEstablishment: error_1.WSDriverRequestAgentEstablishmentError,
ConnectionBreak: error_1.WSDriverRequestAgentBreakError,
ConnectionTerminated: error_1.WSDriverRequestAgentTerminatedError,
ConnectionTimeout: error_1.WSDriverRequestAgentTimeoutError,
RequestTimeout: error_1.WSDriverRequestTimeoutError,
},
onMessage: this._onMessage.bind(this),
});
this._clientSupportedCompressionTypes = clientSupportedCompressionTypes;
this._sessionId = sessionId;
this._sessionPrefix = `/session/${sessionId}/`;
}
/** @description Creates WSDriverRequestAgent without establishing it */
static create({ sessionId, sessionCaps, headers = {}, browserConfig, }) {
if (!sessionCaps["se:wsdriver"]) {
throw new error_1.WSDriverError({ message: "Couldn't determine wsdriver endpoint" });
}
if (!sessionCaps["se:wsdriverVersion"]) {
throw new error_1.WSDriverError({ message: "Couldn't determine wsdriver supported versions" });
}
const wsdriverEndpoint = sessionCaps["se:wsdriver"];
const wsdriverSupportedVersions = sessionCaps["se:wsdriverVersion"].split(", ").map(Number).filter(Boolean);
const requestTimeout = browserConfig.httpTimeout;
const supportedVersions = wsdriverSupportedVersions.reduce((acc, val) => {
acc[val] = true;
return acc;
}, {});
const clientSupportedCompressionTypes = ["zstd" in process.versions ? "zstd" : null, "gzip"].filter(Boolean);
return new this(wsdriverEndpoint, {
sessionId,
headers,
requestTimeout,
clientSupportedCompressionTypes,
supportedVersions,
});
}
close() {
this._wsConnection.close();
}
async _onMessage(data, isBinary) {
if (!isBinary) {
this._wsConnection.forceReconnect(`Unsupported data type: Expected binary, received text: ${(0, node_util_1.inspect)(data)}`);
return;
}
const incomingMessage = await (0, response_1.parseWsDriverIncomingMessage)(data).catch((err) => err);
if (!incomingMessage) {
// Valid, but unsupported
return;
}
if (incomingMessage instanceof Error) {
// Invalid message
this._wsConnection.forceReconnect(incomingMessage.message);
return;
}
const message = incomingMessage;
if (debug_1.debugWSDriver.enabled) {
const header = message.rawBody.readUint8(1);
(0, debug_1.debugWSDriver)(`< ${(0, node_util_1.inspect)({
sessionId: this._sessionId,
requestId: message.requestId,
header: header.toString(2).padStart(8, "0"),
statusCode: message.statusCode,
body: message.body,
}, {
depth: 3,
maxStringLength: 150,
breakLength: Infinity,
compact: true,
})}`);
}
if (message.isProtocolError) {
logger.error("wsdriver: Protocol error occured while parsing message:", message);
this._wsConnection.provideResponseFor(message.requestId, new error_1.WSDriverRequestError({
message: "Protocol error: " + (0, node_util_1.inspect)(message.body),
requestId: message.requestId,
code: constants_2.WS_ERROR_CODE.PROTOCOL_ERROR,
}));
this._wsConnection.forceReconnect("Protocol error: " + (0, node_util_1.inspect)(message.body));
return;
}
if (message.body instanceof Error) {
logger.error("wsdriver: Malformed response:", message.body);
this._wsConnection.provideResponseFor(message.requestId, new error_1.WSDriverRequestError({
message: message.body.message,
requestId: message.requestId,
code: constants_2.WS_ERROR_CODE.MALFORMED_RESPONSE,
}));
}
this._wsConnection.provideResponseFor(message.requestId, message);
}
async _getRequestCompressionType() {
if (typeof this._serverSupportedCompressionType !== "undefined") {
return this._serverSupportedCompressionType;
}
const { responseHeaders } = await this._getConnectionProperties();
if (!responseHeaders || !responseHeaders[constants_1.WSD_ACCEPT_ENCODING_HEADER]) {
return (this._serverSupportedCompressionType = types_1.WsDriverCompression.None);
}
const serverAcceptEncodingHeaders = responseHeaders[constants_1.WSD_ACCEPT_ENCODING_HEADER].concat(", ");
const serverAcceptEncodings = serverAcceptEncodingHeaders.split(", ");
for (const clientSupportedEncoding of this._clientSupportedCompressionTypes) {
if (serverAcceptEncodings.includes(clientSupportedEncoding)) {
if (clientSupportedEncoding === "zstd") {
return (this._serverSupportedCompressionType = types_1.WsDriverCompression.ZSTD);
}
else if (clientSupportedEncoding === "gzip") {
return (this._serverSupportedCompressionType = types_1.WsDriverCompression.GZIP);
}
}
}
return (this._serverSupportedCompressionType = types_1.WsDriverCompression.None);
}
_getConnectionProperties() {
return this._wsConnection.getConnectionProperties();
}
/** @description Performs high-level WSDriver request with timeout */
async request(url, options) {
let requestId;
let result;
for (let retriesLeft = constants_1.WSD_REQUEST_RETRIES; retriesLeft >= 0; retriesLeft--) {
requestId = this._wsConnection.getRequestId();
const requestMessage = await (0, request_1.constructWsDriverRequest)(url, options, {
requestId,
sessionPrefix: this._sessionPrefix,
compressionType: await this._getRequestCompressionType(),
});
if (debug_1.debugWSDriver.enabled) {
const header = requestMessage.readUint8(1);
const commandEndIdx = requestMessage.indexOf(0, 8);
const command = requestMessage.subarray(8, commandEndIdx).toString();
(0, debug_1.debugWSDriver)(`> ${(0, node_util_1.inspect)({
sessionId: this._sessionId,
requestId,
header: header.toString(2).padStart(8, "0"),
method: options.method,
command,
body: options.json,
}, {
depth: 3,
maxStringLength: 150,
breakLength: Infinity,
compact: true,
})}`);
}
result = (await this._wsConnection.makeRequest(requestId, requestMessage).catch((err) => err));
if (result instanceof error_1.WSDriverRequestTimeoutError) {
const requestError = new Error(result.message);
requestError.stack = result.stack;
// error code should be "ETIMEDOUT" for webdriver to be able to retry
requestError.code = "ETIMEDOUT";
throw requestError;
}
if (!(result instanceof error_2.WsError) || !result.isRetryable() || retriesLeft <= 0) {
break;
}
if (debug_1.debugWSDriver.enabled) {
const header = requestMessage.readUint8(1);
const commandEndIdx = requestMessage.indexOf(0, 8);
const command = requestMessage.subarray(8, commandEndIdx).toString();
(0, debug_1.debugWSDriver)(`⟳ ${(0, node_util_1.inspect)({
sessionId: this._sessionId,
requestId,
header: header.toString(2).padStart(8, "0"),
method: options.method,
command,
body: options.json,
errorMessage: result.message,
retriesLeft: retriesLeft,
})}`);
}
await (0, utils_1.exponentiallyWait)({
baseDelay: constants_1.WSD_REQUEST_RETRY_BASE_DELAY,
attempt: constants_1.WSD_REQUEST_RETRIES - retriesLeft,
});
}
if (result instanceof error_2.WsError) {
throw result;
}
const response = {
url: url.toString(),
method: options.method,
requestId,
statusCode: result.statusCode,
statusMessage: http_1.STATUS_CODES[result.statusCode],
req: {
id: requestId,
method: options.method,
path: options.path,
host: url.host,
},
request: {
id: requestId,
options,
requestUrl: url,
},
ok: result.statusCode >= 200 && result.statusCode < 300,
rawBody: result.rawBody,
body: result.body,
};
response.req.res = response;
response.request.response = response;
return response;
}
}
exports.WSDriverRequestAgent = WSDriverRequestAgent;
//# sourceMappingURL=index.js.map