Reputation: 1434
I'm writing an end-to-end test that simulates user authentication with Protractor. A user feels in her credentials and clicks a Submit button. As a result, the server returns an access token in a JSON response that can be used for other REST API calls. I'd like to save this token to a file.
There's a similar question on capturing a response of a GET request here, but I'm not sure it's a good idea to send another request after I click the button.
How can I capture the response after a button click?
Upvotes: 4
Views: 1665
Reputation: 13309
Here is my idea about how to catch HTTP responses. Protractor provides a method browser.addMockModule()
(docs) - it is used to add custom Angular modules to a page, which are usually used to mock outcoming requests and provide custom response. But we do not need to mock requests, it would be enough to just listen for whatever comes from a server. It can be achieved with the help of Angular HTTP interceptors. Interceptors are used to catch a request or a response and modify it for whatever needs before in gets to it's endpoint. We can use them to collect information about what is coming from the server, store it, and then let response go forward without changes. Since this custom module and spec tests will run on the same page, information about responses can be stored in some global property. Then, when button is clicked, it would be possible to inject custom script to a page to retrieve required responses via browser.executeScript()
(docs). Here is the source:
it('should intercept requests', function () {
// Inject custom Angular module on a page
// Script should be injected before you "browser.get()" the page
browser.addMockModule('e2eHttp', function () {
// Note: This function scope is not a Protractor environment
angular
.module('e2eHttp', [])
.config(function ($httpProvider) {
// add custom interceptor to all requests
$httpProvider.interceptors.push('e2eHttpInterceptor');
})
.factory('e2eHttpInterceptor', function () {
return {
response: function (response) {
// name of the global property to store responses
var global = 'e2eHttpResponses';
// responses will be grouped by url
// but you can use data from "response.config" to adapt it
// it has a lot of info about response headers, method, etc
var url = response.config.url;
window[global] = window[global] || {};
window[global][url] = window[global][url] || [];
window[global][url].push(response); // store response
// proceed without changing response
return response;
}
};
});
});
// Load the page
browser.get('#/auth/login');
$('#submit').click();
// If we are sure that response has come, then extract it
browser.executeScript(function () {
// Note: This function scope is not a Protractor environment
var global = 'e2eHttpResponses';
var uri = 'api/auth/login.json';
// extract array of stored responses for required uri
var responses = (window[global] && window[global][uri]) || [];
// return responses to spec
return responses;
}).then(function (responses) {
// and finally, we are now able to get all information we need
// about response, and in your case, save it to a file
console.log(responses);
var data = responses[0].data; // first response body as a string
});
// remove injected module not to break another specs
browser.removeMockModule('e2eHttp');
});
You can move setup and injection calls to some utility modules, so test specs would be clean.
Upvotes: 3