UNPKG

askui

Version:

Reliable, automated end-to-end-testing that depends on what is shown on your screen instead of the technology you are running on

137 lines (136 loc) 6.72 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import got from 'got'; import { CookieJar } from 'tough-cookie'; import { logger } from '../../lib'; import { Credentials } from './credentials'; import { httpClientErrorHandler } from './custom-errors'; function buildRetryLog(requestUrl, errorCode, statusCode, errorMessage, delayInMs, delayReason, attemptCount) { const failureReasons = []; if (statusCode !== undefined && statusCode >= 400) { failureReasons.push(`status code ${statusCode}`); } if (errorCode !== undefined) { failureReasons.push(`error code ${errorCode}`); } if (failureReasons.length === 0) { failureReasons.push('unknown error'); } const requestText = requestUrl ? `Request to ${requestUrl}` : 'Request'; return (`${requestText} failed with ${failureReasons.join(', ')}.` + ` Retrying in ${delayInMs} ms... (based on ${delayReason}; attempt ${attemptCount})` + `\nFull message:\n${errorMessage}`); } export class HttpClientGot { constructor(token, customHeaders, cookies = {}, proxyAgents) { this.token = token; this.customHeaders = customHeaders; this.cookies = cookies; this.proxyAgents = proxyAgents; this.headers = {}; this.urlsToRetry = []; this.initHeaders(token, customHeaders); const gotExtendOptions = this.buildGotExtendOptions(proxyAgents); this.askuiGot = got.extend(gotExtendOptions); } buildGotExtendOptions(proxyAgents) { const gotExtendOptions = { retry: { calculateDelay: ({ attemptCount, retryOptions, error, retryAfter, }) => { var _a, _b, _c; if (!this.shouldRetryOnError(error)) { return 0; } if (attemptCount > retryOptions.limit) { return 0; } const hasMethod = retryOptions.methods.includes(error.options.method); const hasErrorCode = retryOptions.errorCodes.includes(error.code); const hasStatusCode = error.response && retryOptions.statusCodes.includes(error.response.statusCode); if (!hasMethod || (!hasErrorCode && !hasStatusCode)) { return 0; } if (error.response) { if (retryAfter) { if (retryOptions.maxRetryAfter === undefined || retryAfter > retryOptions.maxRetryAfter) { return 0; } logger.debug(buildRetryLog((_a = error.request) === null || _a === void 0 ? void 0 : _a.requestUrl, error.code, error.response.statusCode, error.message, retryAfter, 'retry-after header', attemptCount)); return retryAfter; } if (error.response.statusCode === 413) { return 0; } } const baseDelayInMs = 1000; const noiseToPreventCollisions = Math.random() * 100; const delayInMs = Math.min(Math.pow(2, (attemptCount - 1)) * baseDelayInMs + noiseToPreventCollisions, Number.MAX_SAFE_INTEGER); logger.debug(buildRetryLog((_b = error.request) === null || _b === void 0 ? void 0 : _b.requestUrl, error.code, (_c = error.response) === null || _c === void 0 ? void 0 : _c.statusCode, error.message, delayInMs, 'retry-after header', attemptCount)); return delayInMs; }, limit: 5, maxRetryAfter: 10 * 60, methods: ['POST', 'GET', 'PUT', 'HEAD', 'DELETE', 'OPTIONS', 'TRACE'], }, }; if (proxyAgents) { gotExtendOptions.agent = proxyAgents; } return gotExtendOptions; } shouldRetryOnError(error) { var _a; return (((_a = error.request) === null || _a === void 0 ? void 0 : _a.options.method) !== 'POST' || this.shouldRetryPostRequest(error.request)); } shouldRetryPostRequest(request) { return (request !== undefined && this.urlsToRetry.includes(request.requestUrl)); } initHeaders(token, customHeaders = {}) { const credentials = token ? new Credentials(token) : undefined; this.headers = Object.assign(Object.assign({}, (credentials ? { Authorization: `Basic ${credentials === null || credentials === void 0 ? void 0 : credentials.base64Encoded}` } : {})), customHeaders); } injectHeadersAndCookies(url, options) { const cookieJar = new CookieJar(); Object.keys(this.cookies) .map((key) => `${key}=${this.cookies[key]}`) .forEach((cookie) => { cookieJar.setCookieSync(cookie, url); }); return Object.assign(Object.assign({}, options), { cookieJar, headers: this.headers }); } post(url, data) { return __awaiter(this, void 0, void 0, function* () { const options = this.injectHeadersAndCookies(url, { json: data, responseType: 'json', throwHttpErrors: false, }); const { body, statusCode, headers } = yield this.askuiGot.post(url, options); if (headers['deprecation'] !== undefined) { logger.warn(headers['deprecation']); } if (statusCode !== 200) { throw httpClientErrorHandler(statusCode, JSON.stringify(body)); } return { body, headers }; }); } get(url_1) { return __awaiter(this, arguments, void 0, function* (url, options = { responseType: 'json' }) { const response = yield this.askuiGot.get(url, this.injectHeadersAndCookies(url, options)); return response.body; }); } }