feature
You can't intercept HTTP requests
Add API to intercept HTTP requests:
RequestHook abstract class from which implementations could inherit;t.addRequestHook, test.useRequestHook and fixture.useRequestHook methods.t.removeRequestHook methodsHaving this mechanism we can implement RequestLogger (#1270) and RequestMock (#1271)
Just want to add my use case for this feature.
I'm currently building a SPA that has a .net web api backend.
TestCafe seems to be awesome for functional UI testing, but we have another type of testing that we perform: API testing in a regression environment.
At the moment we're trialling using SoapUI for this kind of testing but are finding it a little clunky.
Our entire application requires a user to be authenticated.
Testing the API which requires authentication can be achieved in SoapUI, but we have to jump through some hoops by:
All of this is trivial to achieve in TestCafe as it's actually running in the browser.
In our regression environment we then call our API and compare the results to a saved json file. As it's a financial application, some of the saved results can be quite large and property level testing is not appropriate - we usually just want to ensure that the entire response is the same as the previous test run.
I'd like to use TestCafe to login, navigate to a report screen, fill out the report parameters, run the report and then intercept the xhr request for the results - this might be an xhr request that I'd like to wait several minutes for.
I'd then like to do jest-style snapshot testing of the json results i.e.
t.expect(jsonResults).toMatchSnapshot();
I'd be happy taking a dependency on another library (think Ava rely on Jest to do a similar assertion) to do that snapshot.
If I could do this in TestCafe, then I'd have one coherent strategy and framework for all functional UI and API testing which would be 💯
Is there any movement on this issue? Looks like it's planned for development. Any timeframe on this?
Hi @oneillci,
Thanks for your interest.
We've done some preparations for this feature in our proxy and we plan implement this in the next release iteration (after the current one). It can take about a couple of months.
Would love to use this feature too!
fixture.requestHooks(...)test.requestHooks(...)t.addRequestHooks(...), t.removeRequestHooks(...)where ... is rest parameter. Also passed array will be flatten to plain list.
Examples of usage
fixture.requestHooks(hook1);
test.requestHooks(hook1, hook2, ...);
fixture.requestHooks([hook1, hook2], hook3);
test.requestHooks([hook1, hook2], hook3, [hook4, hook5]);
RequestLogger - allows to collect http requests by specified rules (see RequestFilterRule section).RequestMock - allows to return test responses for specified http requestsRequestHook - the base class, allows to implement a custom logic to intercept http requests.RequestLogger(filter, logOptions)
filter - rule for filtering http requests (see RequestFilterRule description below)
logOptions - determinate which parts of request should collect.
Default values for logOptions:
{
logRequestHeaders: false,
logRequestBody: false,
stringifyRequestBody: false,
logResponseHeaders: false,
logResponseBody: false,
stringifyResponseBody: false
}
i.e. by default the RequestLogger collects only url, statusCode, userAgent, sessionId(internal) request properties.
|Name | Returned type | Description |
|-------------------------- | ------------------- | ------------------------------------------------------|
|async contains(predicate)| Promise | Finds requests by predicate and returns true/false depending on result |
|async count(predicate) |Promise | Finds requests by predicate and returns their count. |
|clear () | None | Clears collected requests |
| Name | Type | Description
|----------|-------|----------
|requests| Array | returns collected requests as Array
For async function the build-in Smart Assertion Query mechanism will be applied.
Example
import { RequestLogger } from 'testcafe';
const logger = RequestLogger('https://example.com');
fixture `test`
.page('https://example.com');
test
.requestHooks(logger)
('test', async t => {
await t.expect(logger.contains(r => r.response.statusCode === 200)).ok();
});
We build our API depending on nock library.
RequestMock configures with pairs of methods .onRequestTo(requestFilterRule).respond(responseMock).
Example
var mock = RequestMock()
.onRequestTo(requestFilterRule1)
.respond(responseMock1)
.onRequestTo(requestFilterRule2)
.respond(responseMock2)
where information about RequestFilterRule see below, ResponseMock - allows to construct response using various arguments.
Example
import { RequestMock } from 'testcafe';
const requestMock = RequestMock()
.onRequestTo('http://external-service.com/api/users'}) /*see RequestFilterRule*/
.respond({data: 123}) /* JSON response */
.onRequestTo(...)
.respond('The error is occured!!!') /*HTML response*/
.onRequestTo (...)
.respond(null, 204) /*custom statusCode*/
.onRequestTo(...)
.respond('<html_markup>', 200, { 'server': 'nginx/1.10.3' }) /* custom headers */
.onRequestTo(...)
.respond(function (req, res){ /* respond function */
res.headers[‘x-calculated-header’] = ‘calculated-value’;
res.statusCode = ‘200’;
const responseBody = fs.readFileSync(req.params['filename']).toString();
res.setBody(responseBody);
});
fixture `Fixture`
.page(‘http://example.com/’)
.rquestHooks(requestMock);
test('test', () => {
await t.click(‘body’);
})
````
## RequestFilterRule
Allows to specify request filtering rule for requests.
It's a public term that implemented with an internal class.
In public API we will use a simple object construction syntax.
**Examples**
```js
/*String*/
'http://example.com' -> RequestFilterRule(`'http://example.com'`)
/*Regular expession*/
/example.com/ -> RequestFilterRule(`/example.com/`)
/*Object with properties*/
{ url: 'http://example.com', method: 'GET', isAjax: false } -> RequestFilterRule(`{ url: 'http://example.com', method: 'GET', isAjax: false }`)
/*Custom function*/
RequestFilterRule(function (request) {
return request.url === 'http://example.com' &&
request.method === 'post' &&
request.isAjax &&
request.body === '{ test: true }' &&
request.headers['content-type'] === 'application/json';
}
@miherlosev is this functionality available somewhere now, or is this just the planned interface?
@curtisblackwell This is in progress now. @miherlosev already have created a pull request but it requires some time to finish it. If you are interested in this we'll be able to provide you with a dev build once this feature is merged
This looks really promising. I have a question though. Will you be able to assert that a request-hook has been triggered?
Will you be able to assert that a request-hook has been triggered?
I am not sure understand your question.
For which case does it need?
@AlexanderMoskovkin understood, thank you. I'm interested, but it sounds like timing may be an issue.
Thinking about it, it's probably not actually needed for integration tests.
Will you release a dev version so that we can try out the request hooks feature?
@elgreco247
Thank you for your interest in this feature.
Â
The Request Hooks feature significantly affects the TestCafe subsystems. First, we will perform internal testing. After that a public development version will be released.
I notice that at least some of this feature is present in the alpha 2 build. Could you explain to me how to use it to achieve what I want to achieve.
https://testcafe-discuss.devexpress.com/t/testcafe-not-always-catching-requests-from-browser/818/4
that is:-
Our webapp gets a series of images when a report is run.
When I run the report via test cafe each image is GOT twice, once without the proxy wrapper and without our internal auth cookie, and once with the proxy wrapper (the cookie is not visible but it works anyway, so I'm assuming some sort of proxy magic). We need to be able to prevent testcafe from attempting to get these images without the correct authorisation. Because doing so sets off alarms in our data dog as they look like attacks. Without being able to do this we will be forced to throw away a few months of work and switch to a different technology.
Feature Request Hooks is ready for testing. Anyone can try this.
Before testing you need to install the latest alpha version - [email protected].
Final documentation is in progress, but you can already use this PR.
@zoejobson
I've answer for your https://github.com/DevExpress/testcafe/issues/1341#issuecomment-385405328 in https://testcafe-discuss.devexpress.com/t/testcafe-not-always-catching-requests-from-browser/818/10
The TypeScript typings will be added in separate PR.
This thread has been automatically locked since it is closed and there has not been any recent activity. Please open a new issue for related bugs or feature requests. We recommend you ask TestCafe API, usage and configuration inquiries on StackOverflow.
Most helpful comment
Request Hook
API for adding/removing
fixture.requestHooks(...)test.requestHooks(...)t.addRequestHooks(...),t.removeRequestHooks(...)where
...is rest parameter. Also passed array will be flatten to plain list.Examples of usage
Exporting classes
RequestLogger- allows to collect http requests by specified rules (seeRequestFilterRulesection).RequestMock- allows to return test responses for specified http requestsRequestHook- the base class, allows to implement a custom logic to intercept http requests.RequestLogger
RequestLogger(filter, logOptions)filter- rule for filtering http requests (seeRequestFilterRuledescription below)logOptions- determinate which parts of request should collect.Default values for
logOptions:i.e. by default the
RequestLoggercollects onlyurl,statusCode,userAgent,sessionId(internal) request properties.API
Methods
|Name | Returned type | Description |
|-------------------------- | ------------------- | ------------------------------------------------------|
|
async contains(predicate)|Promise| Finds requests by predicate and returnstrue/falsedepending on result ||
async count(predicate)|Promise| Finds requests by predicate and returns their count. ||
clear ()| None | Clears collected requests |Properties
| Name | Type | Description
|----------|-------|----------
|
requests| Array | returns collected requests asArrayFor
asyncfunction the build-inSmart Assertion Query mechanismwill be applied.Example
Request Mock
API
We build our API depending on nock library.
RequestMockconfigures with pairs of methods.onRequestTo(requestFilterRule).respond(responseMock).Example
where information about
RequestFilterRulesee below,ResponseMock- allows to construct response using various arguments.Example