Skip to content

Commit 5dac210

Browse files
authored
Merge pull request #89 from envoy/cypress-request-migration
Replace deprecated request packages with @cypress/request
2 parents e0c5bba + d5742fb commit 5dac210

File tree

5 files changed

+742
-530
lines changed

5 files changed

+742
-530
lines changed

lib/EnvoyAPI.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const request = require('request-promise-native');
1+
const request = require('./request-wrapper');
22
const EnvoyResponseError = require('./EnvoyResponseError');
33

44
/**

lib/request-wrapper.js

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
const cypressRequest = require('@cypress/request');
2+
3+
// RequestError class based on request-promise-native's
4+
function RequestError(cause, options, response) {
5+
this.name = 'RequestError';
6+
this.message = String(cause);
7+
this.cause = cause;
8+
this.error = cause; // legacy attribute
9+
this.options = options;
10+
this.response = response;
11+
12+
if (Error.captureStackTrace) {
13+
Error.captureStackTrace(this);
14+
}
15+
}
16+
RequestError.prototype = Object.create(Error.prototype);
17+
RequestError.prototype.constructor = RequestError;
18+
19+
// StatusCodeError class for non-2xx HTTP responses
20+
function StatusCodeError(statusCode, body, options, response) {
21+
this.name = 'StatusCodeError';
22+
this.statusCode = statusCode;
23+
this.message = `${statusCode} - ${JSON && JSON.stringify ? JSON.stringify(body) : body}`;
24+
this.error = body; // legacy attribute
25+
this.options = options;
26+
this.response = response;
27+
28+
if (Error.captureStackTrace) {
29+
Error.captureStackTrace(this);
30+
}
31+
}
32+
StatusCodeError.prototype = Object.create(Error.prototype);
33+
StatusCodeError.prototype.constructor = StatusCodeError;
34+
35+
function normalizeRequestParams(options, callback) {
36+
if (typeof options === 'string' && typeof callback === 'object') {
37+
return Object.assign({ url: options }, callback);
38+
}
39+
if (typeof options === 'string') {
40+
return { url: options };
41+
}
42+
return options;
43+
}
44+
45+
function createErrorWithOptions(err, options, response) {
46+
return new RequestError(err, options, response);
47+
}
48+
49+
function resolveResponse(resolve, reject, response, body, options) {
50+
// Check for non-2xx status codes (request-promise-native's simple: true behavior)
51+
const simple = options.simple !== false;
52+
const is2xx = response && /^2/.test(String(response.statusCode));
53+
54+
if (simple && !is2xx && response) {
55+
reject(new StatusCodeError(response.statusCode, body, options, response));
56+
return;
57+
}
58+
59+
if (options.resolveWithFullResponse) {
60+
resolve(response);
61+
return;
62+
}
63+
resolve(body);
64+
}
65+
66+
// A wrapper that mimics request-promise-native behavior
67+
function createRequestWrapper(requestFn) {
68+
return function requestWrapper(options, callback) {
69+
const requestOptions = normalizeRequestParams(options, callback);
70+
71+
return new Promise((resolve, reject) => {
72+
requestFn(requestOptions, (err, response, body) => {
73+
if (err) {
74+
reject(createErrorWithOptions(err, requestOptions, response));
75+
return;
76+
}
77+
resolveResponse(resolve, reject, response, body, requestOptions);
78+
});
79+
});
80+
};
81+
}
82+
83+
const promisifiedRequest = createRequestWrapper(cypressRequest);
84+
85+
// Add defaults method to maintain compatibility with request-promise-native
86+
promisifiedRequest.defaults = function defaultHandler(defaultOptions) {
87+
const requestWithDefaults = cypressRequest.defaults(defaultOptions);
88+
89+
// A wrapper that also merges the default options for error handling
90+
const promisifiedWithDefaults = function promisifiedWithDefaults(options, callback) {
91+
const requestOptions = normalizeRequestParams(options, callback);
92+
93+
// Merge default options with request options for the error.options property
94+
const mergedOptions = Object.assign({}, defaultOptions, requestOptions);
95+
96+
// Maintain compatibility with request-promise-native:
97+
const isFullUrl = requestOptions.url
98+
&& (requestOptions.url.startsWith('http://') || requestOptions.url.startsWith('https://'));
99+
100+
if (defaultOptions.baseUrl && isFullUrl) {
101+
const error = new Error('options.uri must be a path when using options.baseUrl');
102+
return Promise.reject(createErrorWithOptions(error, mergedOptions));
103+
}
104+
105+
return new Promise((resolve, reject) => {
106+
requestWithDefaults(requestOptions, (err, response, body) => {
107+
if (err) {
108+
reject(createErrorWithOptions(err, mergedOptions, response));
109+
return;
110+
}
111+
resolveResponse(resolve, reject, response, body, mergedOptions);
112+
});
113+
});
114+
};
115+
116+
// Copy the defaults method to the new promisified version
117+
promisifiedWithDefaults.defaults = promisifiedRequest.defaults;
118+
119+
return promisifiedWithDefaults;
120+
};
121+
122+
module.exports = promisifiedRequest;

0 commit comments

Comments
 (0)