Handling typeError through Ember.onerror - ember.js

I would like to be able to be able to handle javascript errors in my Ember application and display a generic modal defined in my application's templates. I'm able to process errors by defining a function for Ember.onerror, but haven't been able to find a way to trigger an event or action against my application for certain error types, for instance a TypeError.
Below is a sample of how I've approached defining Ember.onerror
App.report_errors = (error) ->
console.log "error", error
# Would like to be able to use something like the below line
# to call an action on the application route
#send "showError"
# Log to api
Em.onerror = App.report_errors
Here is a full example fiddle illustrating what I would like to accomplish: http://jsfiddle.net/mandrakus/c8E3x/1/
Thanks!

This solution (courtesy Alex Speller) adds an errorReporter object which is injected during initialization with the ability to access the router and therefore router actions.
App.initializer
name: 'errorReporter'
initialize: (container) ->
container.injection 'reporter:error', 'router', 'router:main'
container.injection 'route', 'errorReporter', 'reporter:error'
reporter = container.lookup 'reporter:error'
Em.onerror = (error) ->
reporter.report error
App.ErrorReporter = Em.Object.extend
report: (error) ->
console.log "error", error
#Would like to be able to use something like the below line
#to call an action on the application route
#router.send "showError"
App.ApplicationRoute = Ember.Route.extend
actions:
error: (error) -> #errorReporter.report error
showError: ->
console.log "displaying error"
#the final application generate a modal or other notification
alert "Generic Error Message"

How about this?
App.report_errors = function (error) {
App.__container__.lookup("route:application").send("showError", error);
};
Two potential problems:
Using global App object. Not a big deal, unless you're trying to host two ember apps side-by-side
Using the hidden container property. This might change name/location in the future, but as I see it used all over the place, I doubt Ember team will remove it completely.

Related

Crossbar.io autobahn: Error with session.subscribe (self2._defer is not a function)

Was trying to do a simple subscription to a topic inside my connection.onopen function, i.e.
session.subscribe(viewServerTx, (eventData) => {
console.log(viewServerTx, eventData);
numEl.innerText = `${eventData}`;
});
but this same error keeps appearing:
LiveViewsComponent.tsx:31 TypeError: self2._defer is not a function
at Session.subscribe (session.js:1350:17)
at connection2.onopen (LiveViewsComponent.tsx:45:15)
at self2._session.onjoin (connection.js:292:21)
at Session.self2._socket.onmessage (session.js:916:21)
at websocket.onmessage (websocket.js:112:23) 'Exception raised from app code while firing Connection.onopen()'
userError # LiveViewsComponent.tsx:31
For context,
connection is made successfully but fails to make the subscription
I am using a Vite React-Typescript app and importing the "autobahn" library
*Anyone has any idea as to what could be happening?

apollo react: proper way to switch a query's params

In my app I have a sidebar with a list of "saved searches" and a central area that should show the results of a search. Whenever I click on a saved search link, I want to update the central area with the results of that search.
What is the proper way to do this with apollo-react?
I tried with this:
// SidebarConnector.js:
const withVideoSearch = graphql(
VIDEO_SEARCH_QUERY,
{
name: 'videoSearchQuery',
props: ({ videoSearchQuery }) => {
return ({
searchVideos: videoSearchQuery.refetch,
});
},
}
);
export default withVideoSearch(Sidebar);
My saved searches are doing a searchVideos({ query: "some query" }) on click which, based on the above, is doing a refetch for the VIDEO_SEARCH_QUERY query with different variables.
This works fine, the call is made to the graphql server and results are returned just fine.
For the main component that shows the list of results I use:
export default graphql(VIDEO_SEARCH_QUERY)(ResultList);
Initially the main component gets its results from the server as if the query was done without variables which is fine, exactly how I want it.
The problem is that every refetch seems to create a different entry in ROOT_QUERY in apollo's store and my main component is "locked" into the one without variables.
Here's what apollo's store looks like after the initial fetch and one of the refetches triggered from a saved search:
ROOT_QUERY
searchVideos({"query":"coke"}): [Video]
0:▾Video:arLaecAu5ns
searchVideos({"query":null}): [Video]
0:▾Video:3HXg-oVMA0c
So my question is how to either switch the main component to the "current search" or how to overwrite the store on every refresh so that there's only one key so the main component updates correctly.
For completeness here's my VIDEO_SEARCH_QUERY:
export const VIDEO_SEARCH_QUERY = gql`
query searchVideos($query: String) {
searchVideos(query: $query) {
...fVideo
}
}
${fVideo}
`;
Maybe I'm misunderstanding your use case, but it seems like there's no need to utilize refetch here. It would be simpler to persist whatever the selected search string is as state, pass that state down as a prop to your main component and then just use that prop as the variable in your GraphQL request. So the graphql call inside your ResultList component would look something like this:
const options = props => ({ variables: { query: props.searchString } })
export default graphql(VIDEO_SEARCH_QUERY, { options })(ResultList);
Then just have your onClick handler for each saved search set the state to whatever that search string is, and Apollo will do the rest. This is super easy with Redux -- just fire off the appropriate action. If you're not using Redux, you may have to lift the state up so it can then be passed down as a prop, but the concept is the same.

Qunit assert throws not working

I am trying to assert that a few steps in the code (visiting page, providing wrong card-number, password combination and clicking submit)should generate an error from the backend service - I have referred to this already..
and tried the suggestion of using Error Object as the second argument to assert.throws but that doesn't work for me.
i did see this link as well before posting my question,
My problem is - I don't have control over the code that throws the exception/error in this case. (I cannot change it to say Ember.assert etc) I just want to be able to catch an erroneous case.
Secondly, I don't have a component in this case. Its a straight forward API call that's made when click on submit is done, basically an action submitAuthForm is called in controller which calls ember cli mirage scenario that returns the following object problems object.
return new Response(401,{'X-Auth-Token': 'wrong-username-password-combination'},failResponse401);
and the returned object looks like
var failResponse401 = {
problems: [ {
field: null,
index: null,
value: null,
code: '0006',
subCode: '',
details: {},
_type: 'error'
} ]
};
We have a node_module dependency on an in-house exceptions kit that throws an Error object based on this.
Here's my Qunit test
test('ERROR_CASE_visiting /signon, provide cardNumber(2342314) and ' +
'password, submit and expect to see invalid cardnumber/password error',
function (assert) {
assert.expect(2);
assert.throws(
function () {
visit('/signon');
fillIn('#a8n-signon-card-number input', '2342314');
fillIn('#a8n-signon-password input', 'password');
click('#a8n-signon-submit-button button');
},
Error,
"Error Thrown"
);
});
I keep getting this error from Qunit
Error Thrown# 110 ms
Expected:
function Error( a ){
[code]
}
Result:
undefined
Diff:
function Error( a ){
[code]
}defined
Source:
at Object.<anonymous> (http://localhost:7357/assets/tests.js:175:12)
at runTest (http://localhost:7357/assets/test-support.js:3884:30)
at Test.run (http://localhost:7357/assets/test-support.js:3870:6)
at http://localhost:7357/assets/test-support.js:4076:12
at Object.advance (http://localhost:7357/assets/test-support.js:3529:26)
at begin (http://localhost:7357/assets/test-support.js:5341:20)
API rejected the request because of : []# 1634 ms
Expected:
true
Result:
false
Source:
Error: API rejected the request because of : []
at Class.init (http://localhost:7357/assets/vendor.js:172237:14)
at Class.superWrapper [as init] (http://localhost:7357/assets/vendor.js:55946:22)
at new Class (http://localhost:7357/assets/vendor.js:51657:19)
at Function._ClassMixinProps.create (http://localhost:7357/assets/vendor.js:51849:12)
at Function.createException (http://localhost:7357/assets/vendor.js:172664:16)
at Class.<anonymous> (http://localhost:7357/assets/vendor.js:133592:72)
at ComputedPropertyPrototype.get (http://localhost:7357/assets/vendor.js:32450:27)
at Object.get (http://localhost:7357/assets/vendor.js:37456:19)
at Class.get (http://localhost:7357/assets/vendor.js:50194:26)
at http://localhost:7357/assets/vendor.js:133645:30
Is there anything else that i can try to get it to work.
Is there someway i could somehow pass this test, by wrapping the returned response somehow in a way that it doesn't break my test altogether.
I found a workaround following this link
the user pablobm has posted a link to a helper
I used that to workaround this Qunit issue.

Ember makes unwanted call to backend in model hook

I want to be able to retrieve a certain conversation when its id is entered in the URL. If the conversation does not exist, I want to display an alert message with a record not found.
here is my model hook :
model: function(params){
return this.store.filter('conversation', { status : params.status}, function(rec){
if(params.status == 'all'){
return ((rec.get('status') === 'opened' || rec.get('status') === 'closed'));
}
else{
return (rec.get('status') === params.status); <--- Problem is here
}
});
}
For example, if I want to access a certain conversation directly, I could do :
dev.rails.local:3000/conversations/email.l#email.com#/convid
The problem is when I enter a conversation id which doesn't exist (like asdfasdf), ember makes call to an inexisting backend route.
It makes a call to GET conversation/asdfasdf. I'm about sure that it is only due to the record not existing. I have nested resources in my router so I'm also about sure that it tries to retrieve the conversation with a non existing id.
Basically, I want to verify the existence of the conversation before returning something from my hook. Keep in mind that my model hook is pretty much set and won't change, except for adding a validation on the existence of the conversation with the id in the url. The reason behind this is that the project is almost complete and everything is based on this hook.
Here is my router (some people are going to tell me you can't use nested resources, but I'm doing it and it is gonna stay like that so I have to work with it because I'm working on a project and I have to integrate ember in this section only and I have to use this setup) :
App.Router.map(function(){
// Routing list to raw namespace path
this.resource('conversations', { path : '/' }, function() {
this.resource('conversation', { path : '/:conversation_id'});
});
});
This also happens when I dont specify any id and I use the hashtag in my url like this :
dev.rails.local:3000/conversations/email.l#email.com#/ would make a call to conversation/
I know it is because of my nested resource. How can I do it?
By passing a query to filter (your { status : params.status}) you are asking Ember Data to do a server query. Try removing it.
From the docs at http://emberjs.com/api/data/classes/DS.Store.html#method_filter:
Optionally you can pass a query, which is the equivalent of calling find with that same query, to fetch additional records from the server. The results returned by the server could then appear in the filter if they match the filter function.
So, remove the query:
model: function(params){
return this.store.filter('conversation', function(rec) {
if (params.status == 'all') {
return rec.get('status') === 'opened' || rec.get('status') === 'closed';
} else {
return rec.get('status') === params.status;
}
});
}
Ok so here is what I did. I removed my nested resource because I realised I wasn't using it for any good reason other than redirecting my url. I decided to manually redirect my url using javascript window.location.
This removed the unwanted call (which was caused by the nested resource).
Thanks to torazaburo, you opened my eyes on many things.

Testing Ember (v1.0.0-rc.3) nested controllers using Mocha and Chai

I am trying to write test cases for controllers of an Ember (v1.0.0-rc.3) Application using Mocha and Chai. One of my controller is making use of another controller as follows
App.ABCController = Em.ObjectController.extend({
needs: ['application'],
welcomeMSG: function () {
return 'Hi, ' + this.get('controllers.application.name');
}.property(),
...
});
I wrote testCase as below:
describe 'ABCController', ->
expect = chai.expect
App = require '../support/setup'
abcController = null
before ->
App.reset()
ApplicationController = require 'controllers/application_controller'
ABCController = require 'controllers/abc_controller'
applicationController = ApplicationController.create()
abcController = ABCController.create()
describe '#welcomeMSG', ->
it 'should return Hi, \'user\'.', ->
msg = abcController.get('welcomeMSG')
expect(msg).to.be.equal('Hi, '+ applicationController.get('name'))
support/setup file is as follows
Em.testing = true
App = null
Em.run ->
App = Em.Application.create()
module.exports = App
Now whenever i try to run testcase i face error
"Before all" hook:
TypeError: Cannot call method 'has' of null
at verifyDependencies (http://localhost:3333/test/scripts/ember.js:27124:20)
at Ember.ControllerMixin.reopen.init (http://localhost:3333/test/scripts/ember.js:27141:9)
at superWrapper [as init] (http://localhost:3333/test/scripts/ember.js:1044:16)
at new Class (http://localhost:3333/test/scripts/ember.js:10632:15)
at Function.Mixin.create.create (http://localhost:3333/test/scripts/ember.js:10930:12)
at Function.Ember.ObjectProxy.reopenClass.create (http://localhost:3333/test/scripts/ember.js:11756:24)
at Function.superWrapper (http://localhost:3333/test/scripts/ember.js:1044:16)
at Context.eval (test/controllers/abc_controller_test.coffee:14:47)
at Hook.Runnable.run (test/vendor/scripts/mocha-1.8.2.js:4048:32)
at next (test/vendor/scripts/mocha-1.8.2.js:4298:10)
Please help me to resolve this issue. I will appreciate if someone provide me few links where i can study for latest ember.js application testing with mocha and chai.
Reading trough the docs I guess your problem is that your expect fails due to this to.be.equal. Try changing the assertion chain to this:
expect(msg).to.equal('Hi, '+ applicationController.get('name'))
Update
After reading your comment I guess the problem in your case is that when you do Ember.testing = true is equivalent to the before needed App.deferReadiness(), so it' obviously necessary to 'initialize' your App before using it, this is done with App.initialize() inside your global before hook. And lastly you call App.reset() inside your beforeEach hook's.
Please check also this blog post for more info on the update that introduced this change.
Hope it helps