-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Track and allow querying in-flight requests #186
Changes from 21 commits
e53e296
4d5a49b
cb6c4d2
e5c8158
06bec12
d543255
2ac7125
46ff17e
0eb905a
37ff5c8
d39a8cb
5a7222a
e8971c5
87d3d01
0399024
98b87b5
7cefc9d
5074b90
d23bfab
caabd77
c3bfb5e
ded6f2b
36ca0dc
03874f5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
errorShots | ||
node_modules | ||
test/logs | ||
test/**/logs | ||
test/**/dist |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,9 +2,19 @@ | |
|
||
const interceptor = require('./lib/interceptor'); | ||
|
||
const issueDeprecation = (map, key, what) => { | ||
if (!map[key]) { | ||
console.warn( | ||
`[wdio-intercept-service]: ${what} is deprecated and will no longer work in v5` | ||
); | ||
map[key] = true; | ||
} | ||
}; | ||
|
||
class WebdriverAjax { | ||
constructor() { | ||
this._wdajaxExpectations = null; | ||
this._deprecations = {}; | ||
} | ||
|
||
beforeTest() { | ||
|
@@ -34,8 +44,9 @@ class WebdriverAjax { | |
'assertExpectedRequestsOnly', | ||
assertExpectedRequestsOnly.bind(this) | ||
); | ||
browser.addCommand('hasPendingRequests', hasPendingRequests); | ||
browser.addCommand('getRequest', getRequest); | ||
browser.addCommand('getRequests', getRequest); | ||
browser.addCommand('getRequests', getRequests); | ||
|
||
function setup() { | ||
return browser.executeAsync(interceptor.setup); | ||
|
@@ -50,15 +61,22 @@ class WebdriverAjax { | |
return browser; | ||
} | ||
|
||
function assertRequests() { | ||
function assertRequests(options = {}) { | ||
const expectations = this._wdajaxExpectations; | ||
|
||
if (!expectations.length) { | ||
return Promise.reject( | ||
new Error('No expectations found. Call .expectRequest() first') | ||
); | ||
} | ||
return getRequest().then((requests) => { | ||
|
||
// Don't let users request pending requests: | ||
if (options.includePending) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very nice catch here, providing a less frustrating experience :) |
||
throw new Error( | ||
'[wdio-intercept-service]: passing `includePending` option to `assertRequests` is not supported!' | ||
); | ||
} | ||
return getRequests(options).then((requests) => { | ||
if (expectations.length !== requests.length) { | ||
return Promise.reject( | ||
new Error( | ||
|
@@ -135,13 +153,33 @@ class WebdriverAjax { | |
}); | ||
} | ||
|
||
function assertExpectedRequestsOnly(inOrder = true) { | ||
function assertExpectedRequestsOnly(orderOrOptions) { | ||
const expectations = this._wdajaxExpectations; | ||
let inOrder = true; | ||
let options = {}; | ||
if (typeof orderOrOptions === 'boolean') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Honestly, I think I would be OK with changing the API (like in the readme) and bumping the major version There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I vastly prefer the approach of Ember.JS, where the framework's policy is that users should be able to upgrade to the next major versions without their app breaking so as long as their app runs the previous version without encountering deprecation warnings. That is, a semver major bump should never add functionality, it should only remove already-deprecated functionality. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah okay, I see your point. The downside here is that the actual API is not necessarily 100% consistent with the actual code but that might only cause confusion for people who actually work on the code and not for the ones using it. All in all I'd be fine with this. |
||
issueDeprecation( | ||
this._deprecations, | ||
'inOrder', | ||
'Calling `assertExpectedRequestsOnly` with a boolean parameter' | ||
); | ||
inOrder = orderOrOptions; | ||
} else if (orderOrOptions && typeof orderOrOptions === 'object') { | ||
options = orderOrOptions; | ||
inOrder = 'inOrder' in orderOrOptions ? orderOrOptions.inOrder : true; | ||
delete options.inOrder; | ||
} | ||
|
||
return getRequest().then((requests) => { | ||
const clonedRequests = [...requests]; | ||
// Don't let users request pending requests: | ||
if (options.includePending) { | ||
throw new Error( | ||
'[wdio-intercept-service]: passing `includePending` option to `assertExpectedRequestsOnly` is not supported!' | ||
); | ||
} | ||
return getRequests(options).then((requests) => { | ||
const clonedRequests = requests.slice(); | ||
|
||
let matchedRequestIndexes = []; | ||
const matchedRequestIndexes = []; | ||
for (let i = 0; i < expectations.length; i++) { | ||
const ex = expectations[i]; | ||
|
||
|
@@ -192,7 +230,7 @@ class WebdriverAjax { | |
} else if ( | ||
inOrder && | ||
JSON.stringify(matchedRequestIndexes) !== | ||
JSON.stringify(matchedRequestIndexes.concat().sort()) | ||
JSON.stringify(matchedRequestIndexes.slice().sort()) | ||
) { | ||
return Promise.reject( | ||
new Error('Requests not received in the expected order') | ||
|
@@ -214,13 +252,16 @@ class WebdriverAjax { | |
return this._wdajaxExpectations; | ||
} | ||
|
||
async function getRequest(index) { | ||
let request; | ||
if (index > -1) { | ||
request = await browser.execute(interceptor.getRequest, index); | ||
} else { | ||
request = await browser.execute(interceptor.getRequest); | ||
} | ||
function getRequests(options = {}) { | ||
return getRequest(undefined, options); | ||
} | ||
|
||
async function getRequest(index, options = {}) { | ||
const request = await browser.execute( | ||
interceptor.getRequest, | ||
index > -1 ? index : undefined, | ||
options | ||
); | ||
if (!request) { | ||
if (index != null) { | ||
return Promise.reject( | ||
|
@@ -239,22 +280,35 @@ class WebdriverAjax { | |
return transformRequest(request); | ||
} | ||
|
||
function hasPendingRequests() { | ||
return browser.execute(interceptor.hasPending); | ||
} | ||
|
||
function transformRequest(req) { | ||
if (!req) { | ||
return; | ||
} | ||
|
||
return { | ||
const transformed = { | ||
url: req.url, | ||
method: req.method && req.method.toUpperCase(), | ||
body: parseBody(req.requestBody), | ||
headers: normalizeRequestHeaders(req.requestHeaders), | ||
response: { | ||
body: parseBody(req.requestBody), | ||
pending: true, | ||
}; | ||
// Check for a '__fulfilled' property on the retrieved request, which is | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice. |
||
// set by the interceptor only when the response completes. Before this | ||
// flag is set, the request is still being processed (e.g. a large response | ||
// body is downloading) and therefore is pending. | ||
if (req.__fulfilled) { | ||
transformed.pending = false; | ||
transformed.response = { | ||
headers: parseResponseHeaders(req.headers), | ||
body: parseBody(req.body), | ||
statusCode: req.statusCode, | ||
}, | ||
}; | ||
}; | ||
} | ||
return transformed; | ||
} | ||
|
||
function normalizeRequestHeaders(headers) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍