Vue JS How to catch errors globally and display them in a top level component - vue.js

I have set up Vue so that I have a top level AppLayout component which just includes a Navigation Menu component, the router-view and, which uses v-if to optionally display an ErrorDisplay component if the error data item is set. I set this from an err state variable in the Vuex store.
That is where I want to get to. However, I think the problem is more fundamental.
In a lower component, I have a submit function that gets called when I click the submit button. To test error handling I have put
throw new Error('Cannot Submit');
In my Main.js I have
handlers for window.orerror, window.addEventListner, Vue.config.errorhandler, Vue.config.warnhandler
All of these should just call the errHandler function, which just calls an action to update the err variable in the state. The hope being that this will then result in the ErrorDisplay component showing on my top level component.
However, I have console.log statements as the first statement in all the above handlers and in my errHandler function. None of these console.logs are getting executed.
In the Console in Chrome, I am just seeing
[vue warn]: Error in v-on handler: "Error: Cannot Submit"
So it is getting the text from my throw, but none of the error handlers seem to be capturing this?

Vue provides Global configuration config.errorHandler to capture error inside Vue components Globally.
As per Official Docs
Assign a handler for uncaught errors during component to render function and watchers. The handler gets called with the error and the Vue instance.
This is how it can be used:
Vue.config.errorHandler = function (err, vm, info) {
// handle error
// `info` is a Vue-specific error info, e.g. which lifecycle hook
// the error was found in. Only available in 2.2.0+
}
Official docs
Hope this helps!

Did more research and I think someone may have already raised a bug report with Vue for this
PR on Vue
https://github.com/vuejs/vue/pull/5709
So it looks like the problem is that the way that I am trying to test this isn't being caught.

Related

Nuxt js application freezing without any reason

I have Navigation component in my nuxt application and it use window object and I know it has problem with SSR.
I have imported this component in default layout. But I commented this component in default.vue layout, but still gives error and freezing!
error message:
window is not defined
I'm confused.
Try it with this:
if (process.client) {
// put your code that should be executed on the client side here
}

Problem displaying components that use $route with vue-styleguidist

I have some components that use this.$route internally, for various things. Some simplified examples would be, using this.$route.name to lookup a i18n string for the page:
<h1>New {{ $t($route.name + '.label') }}</h1>
or watching the $route and loading something:
watch: {
$route: {
handler: 'loadItem',
immediate: true
}
}
Whenever these components appear in vue-styleguidist, I get various errors in the browser console and nothing renders for the component example:
index.js?1ef8:1 [Vue warn]: Error in callback for immediate watcher "$route": "TypeError: Cannot read property 'id' of undefined"
found in
---> <MyComponent> at src/components/MyComponent.vue
<Anonymous>
<Root>
I am deliberately not importing vue-router or my routes objects into the styleguide, because this isn't supported - and it causes lots of problems with redirects, route guards, etc... which aren't relevant to the style guide.
What I really want to do, I think, is to mock this.$route inside the components when they appear in the styleguide - but I can't figure out how to do that.
Another option would be to pass the route information into the components as props. This would properly decouple the components from the router and fix the issue, but it will involve changes to every component and route.
So, I ended up refactoring all my components to pass in the route properties that they were using as properties. This properly decouple the components from the router and fix the issue, but it was a lot of work.

Suppress Vue warnings in unit tests

I am trying to suppress my warnings in my tests following the config listed here: https://vue-test-utils.vuejs.org/api/config.html#silent, which is as follows:
import { config } from '#vue/test-utils';
// this should actually be the default but the default is not working
config.silent = true;
However, I am still seeing the warning in the test results:
TheQueue
✓ should show the queue bar if there are items queued
✓ should show the correct count of queued items in queued bar
[Vue warn]: Avoid mutating a prop directly since the value will be
overwritten whenever the parent component re-renders. Instead, use a
data or computed property based on the prop's value. Prop being
mutated: "mdTemplateData"
found in
---> <MdTab>
<MdContent>
<MdTabs>
<MdDrawer>
<TheQueue> at src/components/the-queue/TheQueue.vue
<Root>
It's worth noting that I do not see this error in normal usage of the app. This only pops up in tests (otherwise I would attempt to fix the actual suggested issue).
What am I doing wrong here and why can I not suppress these warning? Or am I misunderstanding what silent is supposed to do?
According to the VueJS docs - https://vue-test-utils.vuejs.org/api/config.html#silent
silent
type: Boolean
default: true
It suppresses warnings triggered by Vue while mutating component's
observables (e.g. props). When set to false, all warnings are visible
in the console. This is a configurable way which relies on
Vue.config.silent.
which relies on Vue.config.silent, so all you need is to import vue package and set it's config.silent to false
import Vue from `vue`
Vue.config.silent = true;
I put a working example here in my Github, it's just a fork of official example but it doesn't show warnings during the tests.
https://github.com/al1b/vue-test-utils-getting-started
For more information:
If you check the source code:
warn = (msg, vm) => {
const trace = vm ? generateComponentTrace(vm) : ''
if (config.warnHandler) {
config.warnHandler.call(null, msg, vm, trace)
} else if (hasConsole && (!config.silent)) {
console.error(`[Vue warn]: ${msg}${trace}`)
}
}

Vuex how to handle api error notification?

I started working with Vuex 2 weeks ago and I realized that Vuex is very good to handle the state of the app. But, it is difficult to handle the error of API calls. When I get data from the server, I dispatch an action. When data is successfully returned, of course, everything is fine. But when an error happens, I change state, I don't know how to detect it through the state from Vuejs components to notify to the user. Could anyone give me some advice?
I typically have the following parts:
A component for displaying the notification, typically an alert or a snackbar or similar, e.g. error-notification. I use this component on a high level, directly below the root app component. This depends on your layout.
A property in vuex indicating the error state, typically an error object w/ error code & message, e.g. error
One mutation in the store for raising an error setting the error property, e.g. raiseError
One mutation in the store for dismissing an error clearing the error property, e.g. dismissError
Using these, you need to:
Display error-notification based on the error in the store: <error-notification v-if="$store.state.error :error="$store.state.error"/>
When an error occurs, call raiseError mutation (in your API callback): vm.$store.commit('raiseError', { code: 'ERR_FOO', msg: 'A foo error ocurred'})
In error-notification, call the dismissError mutation when the notification is closed.
You can also return a promise in your action so that if you call it from component you can catch the error there and display a notification as needed:
in your store:
//action
const fetch = (context) => {
return api.fetchTodos() //api here returns a promise. You can also do new Promise(...)
.then((response) => {
context.commit('SET_TODOS', response);
})
};
in vue component:
this.$store.dispatch('todos/fetch', modifiedTodo)
.catch(error => {
//show notification
})

How to catch component unmount caused by live reload

[edit - I thought I was using Hot Reloading, but I am actually using Live Reload]
I have a native plugin that needs to do some clean up each time it is finished with. Basically I want to prevent these errors:
Calling JS function after bridge has been destroyed: RCTDeviceEventEmitter.emit(..)
componentWillUnmount() doesn't get called.
Live reloading will restart the app and load the app back to the initial route when a file changes. ComponentWillUnmount won't be called.
When you reload, what happens behind the scenes is that the react context is getting destroyed, and a new one is being created.
That error get's thrown whenever a Native Module is trying to do work, by using the old react context.
You could use something like this:
Error Boundary in react
Just wrap the error prone code inside the ErrorBoundary component, e.g.
<ErrorBoundary><childComponentCausingError></ErrorBoundary>
And in the ErrorBoundary component, you could just catch the error in componentDidCatch = (error, info) => {
}
componentDidCatch() is a lifecycle method in React.