Catch 404 error when using store.findQuery - ember.js

I'm using Embers findQuery method and wonder how to catch 404 errors when there are no results?
this.store.findQuery('customer', { hasProjects: true, getArchivedProjects: archived }).then(function(customers) {
});
If the query is empty, the code inside this then function doesn't get fired, so I can't even check the type of customers.
Example:
this.store.findQuery('customer', { hasProjects: true, getArchivedProjects: archived }).then(function(customers) {
console.log('foo')
});
If the query returns a 404, console.log doesn't be fired.

The findQuery function returns a promise. You may then provide two functions to the then(), the first being the success path, the second being the failure path... for example:
this.store.findQuery('customer', { hasProjects: true, getArchivedProjects: archived }).then(function(customers) {
console.log('foo')
}, function(error) { /* do something with error */ });

Alternative answer:
Add a error hook to the corresponding route:
App.CustomersIndexRoute = Ember.Route.extend({
actions: {
error: function(reason) {
if (reason.status === 404) {
// do something ...
}
}
}
})
See: http://emberjs.com/guides/routing/asynchronous-routing/#toc_when-promises-reject.

Related

testing multiple http request using mocha

I've been trying to solve this issue for days;
create the test for this case using mocha:
app.post('/approval', function(req, response){
request.post('https://git.ecommchannel.com/api/v4/users/' + req.body.content.id + '/' + req.body.content.state + '?private_token=blabla', function (error, resp, body) {
if (resp.statusCode == 201) {
//do something
} else {
response.send("failed"), response.end();
}
});
} else {
response.send("failed"), response.end();
}
});
});
I've tried several ways, using supertest to test the '/approval' and using nock to test the post request to git api. But it always turn "statusCode" is undefined. I think that's because the request to git api in index.js is not inside a certain function(?)
So I can't implement something like this :
https://codeburst.io/testing-mocking-http-requests-with-nock-480e3f164851 or
https://scotch.io/tutorials/nodejs-tests-mocking-http-requests
const nockingGit = () => {
nock('https://git.ecommchannel.com/api/v4/users')
.post('/1/yes', 'private_token=blabla')
.reply(201, { "statusCode": 201 });
};
it('approval', (done) => {
let req = {
content: {
id: 1,
state: 'yes'
},
_id: 1
}
request(_import.app)
.post('/approval')
.send(req)
.expect(200)
.expect('Content-Type', /html/)
.end(function (err, res) {
if (!err) {
nockingGit();
} else {
done(err);
}
});
done();
})
Then I tried to use supertest as promise
it('approve-block-using-promise', () => {
return promise(_import.app)
.post('/approval')
.send(req = {
content: {
id: 1,
state: 'yes'
},
_id: 1
})
.expect(200)
.then(function(res){
return promise(_import.app)
.post("https://git.ecommchannel.com/api/v4/users/")
.send('1/yes', 'private_token=blabla')
.expect(201);
})
})
But it gives error: ECONNEREFUSED: Connection refused. I didn't find any solution to solve the error. Some sources said that it needs done() .. but it gives another error message, 'ensure "done()" is called" >.<
So then I've found another way, using async (https://code-examples.net/en/q/141ce32)
it('should respond to only certain methods', function(done) {
async.series([
function(cb) { request(_import.app).post('/approval')
.send(req = {
content: {
id: 1,
state: 'yes'
},
_id: 1
})
.expect(200, cb); },
function(cb) { request(_import.app).post('/https://git.ecommchannel.com/api/v4/users/').send('1/yes', 'private_token=blabla').expect(201, cb); },
], done);
});
and it gives this error : expected 201 "Created", got 404 "Not Found". Well, if I open https://git.ecommchannel.com/api/v4/users/1/yes?private_token=blabla in the browser it does return 404. But what I expect is I've injected the response to 201 from the unit test; so whatever the actual response is, the statusCode suppose to be 201, right?
But then since it gives that error, is it means the unit test really send the request to the api?
Pls help me to solve this; how to test the first code I shared.
I really new into unit test.
There are a few things wrong with your posted code, I'll try to list them out but I'm also including a full, passing example below.
First off, your call to git.ecommchannel in the controller, it's a POST with no body. While this isn't causing the errors you're seeing and is technically not incorrect, it is odd. So you should double check what the data you should be sending is.
Next, I'm assuming this was a copy/paste issue when you created the question, but the callback for the request in your controller is not valid JS. The brackets don't match up and the send "failed" is there twice.
Your Nock setup had two issues. First the argument to nock should only have origin, none of the path. So /api/v4/users had to be moved into the first argument of the post method. The other issue was with the second argument passed to post that is an optional match of the POST body. As stated above, you aren't currently sending a body so Nock will always fail to match and replace that request. In the example below, the private_token has been moved to match against the query string of the request, as that what was shown as happening.
The calling of nockingGit was happening too late. Nock needs to register the mock before you use Supertest to call your Express app. You have it being called in the end method, by that time it's too late.
The test labeled approve-block-using-promise has an issue with the second call to the app. It's calling post via Supertest on the Express app, however, the first argument to that post method is the path of the request you're making to your app. It has nothing to do with the call to git.ecommchannel. So in that case your Express app should have returned a 404 Not Found.
const express = require('express')
const nock = require('nock')
const request = require('request')
const supertest = require('supertest')
const app = express()
app.use(express.json())
app.post('/approval', function(req, response) {
const url = 'https://git.ecommchannel.com/api/v4/users/' + req.body.content.id + '/' + req.body.content.state
request.post({
url,
qs: {private_token: 'blabla'}
// body: {} // no body?
},
function(error, resp, body) {
if (error) {
response.status(500).json({message: error.message})
} else if (resp.statusCode === 201) {
response.status(200).send("OK")
} else {
response.status(500).send("failed").end();
}
});
});
const nockingGit = () => {
nock('https://git.ecommchannel.com')
.post('/api/v4/users/1/yes')
.query({private_token: 'blabla'})
.reply(201, {"data": "hello world"});
};
it('approval', (done) => {
const reqPayload = {
content: {
id: 1,
state: 'yes'
},
_id: 1
}
nockingGit();
supertest(app)
.post('/approval')
.send(reqPayload)
.expect(200)
.expect('Content-Type', /html/)
.end(function(err) {
done(err);
})
})

Ember promise isPending not firing if thenable

I want to show a loading spinner in an ember component when I load some data from the store. If there is an error from the store, I want to handle it appropriately.
Here is a snippet of my current code:
cachedCampaignDataIsPending: computed.readOnly('fetchCachedCampaignData.isPending'),
fetchCachedCampaignData: computed('campaign', function() {
return this.get('store').findRecord('cachedCampaignMetric').then( (cachedMetrics) => {
this.set('cachedCampaignData', cachedMetrics);
}, () => {
this.set('errors', true);
});
}),
This will properly set the errors to true if the server responds with an error, however, the cachedCampaignDataIsPending is not acting properly. It does not get set to true.
However, if I rewrite my code to make the computed property not be thenable, then it does fire propertly.
fetchCachedCampaignData: computed('campaign', function() {
return this.get('store').findRecord('cachedCampaignMetric');
}),
Anyone know the reason why, or how to make it fire properly, using the then/catch logic?
Thanks.
Update
I found that this works for me and gives me what I need.
cachedCampaignDataIsPending: computed.readOnly('fetchCachedCampaignData.isPending'),
fetchCachedCampaignData: computed('campaign', function() {
let promise = this.get('store').findRecord('cachedCampaignMetric');
promise.then( (cachedMetrics) => {
this.set('cachedCampaignData', cachedMetrics);
}, () => {
this.set('errors', true);
});
return promise;
}),

No "status" in error hook

According to this page, you can have an "error" action in the actions hash in the application route which looks something like this:
actions: {
error: function(error, transition) {
if (error && error.status === 400) {
// error substate and parent routes do not handle this error
return this.transitionTo('modelNotFound');
}
// Return true to bubble this event to any parent route.
return true;
}
}
However, when the server returns a 403 (or presumably any other error status) the "error" argument does not have a "status" property. The only way I can get the status is like this:
actions: {
error: function(error, transition) {
var status = error.errors[0].status;
if(status == '403') {
return this.transitionTo('index');
}
// substate implementation when returning `true`
return true;
}
}
Not a big deal, but it seems wrong to do error.errors[0].status. Am I doing something wrong here?
As I understand, ember tries to pass errors in some 'general' format, suitable for all cases. And in some cases backend may respond with more than one error. I think that's the reason why we have an array of errors in error action.

Async validation never returns in loopback

I have an async validation in one of my models in which I query for a related object to validate it's existence. The problem is that the request is timing out on this validation and the server never responds.
module.exports = function(Ip) {
// Required fields
Ip.validatesPresenceOf('server_id');
...
Ip.validateAsync('server_id', isExistingServer, {
message: 'invalid server'
});
function isExistingServer(err, done) {
var ServerModel = Ip.app.models.Server;
var self = this;
process.nextTick(function() {
ServerModel.findById(self.server_id, function(e, server) {
console.log(_.isNull(server));// this actually prints false
return _.isNull(server) ? err() : done();
});
});
}
};
Because you need execute done(); then err();
According to documentation you should call done() after err. This is the example in docs:
User.validateAsync('name', customValidator, {message: 'Bad name'});
function customValidator(err, done) {
process.nextTick(function () {
if (this.name === 'bad') err();
done();
});
});
Note that as there is no return before the call to err(), done will also be called.

Assertion Failed: You must use Ember.set() without using set anywhere in the code

I am using breeze js as my database layer. I am able to add new record and save it to the database. I am getting the following error "Assertion Failed: You must use Ember.set()" when i try to save the data. the data gets saved but my success callback does not fired. Just calling manager.saveChanges() will trigger the error message. The strangest part is i am not using "set" anywhere in my code.
App.AddRoute = Ember.Route.extend({
deactivate: function () {
manager.rejectChanges();
},
model: function () {
return manager.createEntity('OSIPI_ChangeRequest_Input');
}
});
App.AddController = Ember.ObjectController.extend({
init: function () {
manager.saveChanges();
},
actions: {
validate: function () {
$('#btn-submit').trigger('click');
},
submit: function () {
var self = this;
if (manager.hasChanges()) {
manager.saveChanges().then(function () {
}).fail(function (msg) {
});
};
}
}
});
I figure it out.
Breeze js is still tracking the changes. I just need to reset the ember model by using the
this.set('content',null) before executing the manager.saveChanges();
Everything is working as I wanted to.