I am mocking an ajax request using jasmine-ajax as follows
jasmine.Ajax.requests.mostRecent().respondWith({
"status": 200,
"responseText": '{}'
});
I am trying to get the 'Location' header for the request object passed to the ajax success callback as follows:
success(function(data, textStatus, request) {
var url = request.getResponseHeader('Location');
url = url.substring(...);
}
but it returns null and the jasmine test fails because substring function is called on null. What should I do?
Note: I can access the 'Location' header just fine if the ajax request is not mocked.
You could add that function to the object that you are returning:
jasmine.Ajax.requests.mostRecent().respondWith({
"status": 200,
"responseText": '{}',
"getResponseHeader": function(arg) { return 'customlocation';}
});
Related
I have the follwing code
cy.intercept({
method: "GET",
url: `**/features`
}).as("getFeatures");
cy.wait('#getFeatures').then(({response}) => {
if(response?.statusCode ===200){
expect(response.body.features).to.exist;
expect(response.body.features).to.contain('feature01');
// hier I would like to return the response.body oder response.body.features as an object to interact with the ui based on its value (wether the feature is activated or not)
}
})
Saving the body into a file is not an option because the tests will run in paralel and different tests may access invalid values of feature endpoint
EDIT: because I need this method more than once. I want to return the value of Body as an object the solution I am looking for is like
function visitUrl() : Object {
//intercept
return body
}
You can use alias and save the response body and use it later on.
cy.intercept({
method: 'GET',
url: `**/features`,
}).as('getFeatures')
cy.wait('#getFeatures').then(({response}) => {
if (response?.statusCode === 200) {
expect(response.body.features).to.exist
expect(response.body.features).to.contain('feature01')
cy.wrap(response.body.features).as('responseBodyFeatures')
}
})
cy.get('#responseBodyFeatures').then((features) => {
cy.log(features) //logs the features section from response body
})
I keep getting this Vue error: "ReferenceError: response is not defined" but when I check in the console, the data is all there.
I intend to use the data from the response to make pagination. Thanks in advance.
Methods
getAllUserData(){
let $this=this;
axios.get('api/members/getAllMembersData').then(response=>this.members=response.data.data);
$this.makePagination(response.meta,response.links);
},
makePagination(meta,links){
let pagination={
current_page:meta.current_page,
last_page:meta.last_page,
next_page_url:links.next,
prev_page_url:links.prev
}
this.pagination = pagination;
}
axios.get() is an async function. The code that follows this function will not be executed after the ajax request completes, but long before that. Because of this, the variable response does not exist yet.
All code that has to be executed when the ajax call completes has to be put in the .then() function of the call.
getAllUserData(){
axios.get('api/members/getAllMembersData').then(response => {
this.members = response.data.data;
this.makePagination(response.data.meta, response.data.links);
});
},
Your response is still inside the axios get method, therefore the makePagination function has to be called inside axios method as well (inside .then())
getAllUserData(){
let $this=this;
axios.get('api/members/getAllMembersData').then(response=>
this.members=response.data.data
$this.makePagination(response.data.meta,response.data.links);
},
makePagination(meta,links){
let pagination={
current_page:meta.current_page,
last_page:meta.last_page,
next_page_url:links.next,
prev_page_url:links.prev
}
this.pagination = pagination;
}
I have a service set up which makes all my AJAX calls. I want to test my login method, which sends an AJAX POST $http.post to a particular URL, which returns an objects with the result (login passed or failed). This result is an object. I have not return the code exactly to test the service, but I'm trying to test the URL first. This is how it looks right now:
'use strict';
describe('Service: Ajax', function () {
var service, httpBackend;
// load the service's module
beforeEach(module('mySampleApp'));
// instantiate service
beforeEach(inject(function (Ajax, _$httpBackend_) {
httpBackend = _$httpBackend_;
service = Ajax;
}));
it('Test AJAX call', function () {
httpBackend.expect('POST', 'http://myloginurl', {u: 'xyz', p: 'pass'}, { withCredentials: true})
.respond(201, 'success');
});
});
This passes. Now I tried putting a wrong URL, wrong username/password, but it still passes! How do I test this?
UPDATE:
Better written now:
//Ajax is my AJAX service
it('should test the login AJAX call', inject(function (Ajax) {
httpBackend.expect('POST', 'http://myloginurl')
.respond(200, "[{ status: 200, //some more data }]");
httpBackend.flush();
Ajax.authenticate({u: 'xyz', password: 'pass' })
.then(function(data){
expect(data.status).toBe(200);
});
}));
I get this:
PhantomJS 1.9.7 (Linux) Service: Ajax should test the login AJAX call FAILED
Error: No pending request to flush !
blah blah...
You need to put a
httpBackend.flush();
in that will throw an exception if the expected url wasn't called - thereby failing your test.
Also, I can't see that you're calling the code that does the Ajax request anywhere - you need to do that before calling flush().
So something like:
it('Test AJAX call', function () {
httpBackend.expect('POST', 'http://myloginurl', {u: 'xyz', p: 'pass'}, { withCredentials: true})
.respond(201, 'success');
service.functionThatMakesCallToServer();
httpBackend.flush();
});
If functionThatMakesCallToServer() calls the url in the httpBackend.expect(...) line, everything will be ok. If it doesn't httpBackend.flush() will throw an error as a call that was expected did not happen. The error will cause your test to fail.
I still don't understand how the Promise API works. I want to know if there's a way to get a data whenever I need it without calling multiple HTTP request. Here's an exemple :
Session Service :
All it does is either get the session object (which contains datas) or get session ID which returns a number.
app.factory('sessionFactory', ['$resource', 'requestFactory',
function ($resource, requestFactory) {
var oSession = {};
var session = {
/**
* Get session ID
* #return {Number}
*/
sessionID: function () {
if (typeof oSession.id !== "undefined") {
return oSession.id;
} else {
return requestFactory.getObject('/application/current_session').then(function (response) {
oSession = response;
return oSession.id;
});
}
},
/**
* Get session object (GET)
* #return {Object} data in JSON format
*/
getCurrentSession: function () {
if (!oSession.id) {
return requestFactory.getObject('/application/current_session').then(function (response) {
oSession = response;
return oSession;
});
}
}
};
return session;
}]);
Request HTTP Service :
This service only does HTTP request.
app.factory('requestFactory', ['$http', '$q', '$timeout',
function ($http, $q, $timeout) {
return {
getObject: function (jsonURL, params) {
// $q service object
var deferred = $q.defer();
// regular ajax request
$http({
method: 'GET',
url: jsonURL,
params: params
})
.success(function (result, status, headers, config) {
// promise resolve
deferred.resolve(result);
})
.error(function (result, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
deferred.reject('Erreur request : ' + status);
});
return deferred.promise;
}
};
}]);
So to get my Session Object, I do sessionFactory.getCurrentSession with callback function(then...) and it works perfect. Later on, I only need to get the session ID so I would do sessionFactory.sessionID, but it works only if I add the callback function (then...), why is that? I thought my global JavaScript object oSession already has data since the first HTTP request.
I want to prevent doing a spaghetti code and keep the code as clean as possible, with a more object approach. Is it possible?
It looks like you're trying to do too much with the promise API. It's already built into the $http service so you shouldn't need to invoke it yourself. Try this instead:
app.factory('requestFactory', ['$http',
function ($http) {
return {
getObject: function (jsonURL, params) {
// regular ajax request
return $http({
method: 'GET',
url: jsonURL,
params: params
})
.success(function (result, status, headers, config) {
return result;
})
.error(function (result, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
throw new Error('Erreur request : ' + status);
});
}
};
}]);
By returning the result of the $http call, you are in fact returning a promise. You can then chain additional resolution code onto the return value. See the "Chaining Promises" section of the $q documentation.
IF you want to cache your previous http response so that it will not make an http call again
you can use angular-cached-resource
bower install angular-cached-resource
angular.module('myApp',['ngCachedResource'])
instead of $resource use $cachedResource, it will cache the network call to local storage, every time you make a call it will resolve immediately even though it makes a call to backend and updated the cache.
you can also use angular-cache it will cache all your http get calls you can set timeout as well exclude url in its configuration
bower install angular-cache
Let's say I have an angular service that has this method:
this.query = function(params, successFn, errorFn) {
return $resource(backendUrl + '/myresource.json')
.query(params, successFn, errorFn);
};
Sometimes the rest API fails, so the errorFn is called. However, sometimes I might be sending invalid parameters and the Rest API would send a HTTP 200 with success : false. I know this is a bad practice but since the API is not to be changed, I'm left handling the error in the success callback.
As you may know, the success callback will always give me an array, so the JSON response :
{
'message' : 'invalid parameter x',
'success' : false
}
Would be exposed as the first parameter in the successFn as :
[ { 0 : 'i', '1' : 'n', '2' : 'v' .... }, {....} ]
Is there any way to get access to the original content returned from the API?
you can use $http instead of resource
// $http returns a promise, which has a then function, which also returns a promise
var promise = $http({
url: url,
method: "GET",
params: params
}).then(function (response) {
//do what you want to do with the response here
//to see what response contains print JSON.stringify(response)
});