From 2ffaae4f301e4760fd0fa0baa75cb2faad250583 Mon Sep 17 00:00:00 2001 From: Yousif Ahmed Date: Wed, 3 Jan 2024 10:03:42 +0000 Subject: [PATCH] fix errorInfo metadata in Vue 3.4+ --- CHANGELOG.md | 6 ++++++ packages/plugin-vue/src/vue.js | 7 ++++++- packages/plugin-vue/test/index.test.ts | 28 +++++++++++++++++++++++++- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b5ab059bf..fe0fedcd42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,14 @@ ## TBD +### Changed + - (react-native) Update bugsnag-cocoa from v6.27.3 to [v6.28.0](https://github.com/bugsnag/bugsnag-cocoa/blob/master/CHANGELOG.md#6280-2023-12-13) +### Fixed + +- (plugin-vue) Fix errorInfo metadata in Vue 3.4+ [#2062](https://github.com/bugsnag/bugsnag-js/pull/2062) + ## v7.22.2 (2023-11-21) ### Changed diff --git a/packages/plugin-vue/src/vue.js b/packages/plugin-vue/src/vue.js index f65b90ae56..7687b27e9b 100644 --- a/packages/plugin-vue/src/vue.js +++ b/packages/plugin-vue/src/vue.js @@ -5,8 +5,13 @@ module.exports = (app, client) => { const handledState = { severity: 'error', unhandled: true, severityReason: { type: 'unhandledException' } } const event = client.Event.create(err, true, handledState, 'vue error handler', 1) + // In Vue 3.4+, the info param is a link to the Vue error docs in prod, so we need to extract the error code from it + // https://github.com/vuejs/core/pull/9165/commits/c261beab2c0a26e401f2c3d5eae2e4c41de6fe4d + const code = typeof info === 'string' && info.indexOf('-') > 0 ? info.split('-')[1] : info + const errorInfo = ErrorTypeStrings[code] || info + event.addMetadata('vue', { - errorInfo: ErrorTypeStrings[info] || info, + errorInfo, component: vm ? formatComponentName(vm, true) : undefined, props: (vm && vm.$options) ? vm.$options.propsData : undefined }) diff --git a/packages/plugin-vue/test/index.test.ts b/packages/plugin-vue/test/index.test.ts index d058f6a18b..18bc7e6181 100644 --- a/packages/plugin-vue/test/index.test.ts +++ b/packages/plugin-vue/test/index.test.ts @@ -80,6 +80,32 @@ describe('bugsnag vue', () => { errorHandler(new Error('oops'), { $parent: null, $options: {} }, 1) }) + it('handles URL info paramater', done => { + const mockVueApp: Vue3App = { + use: (plugin) => { + plugin.install(mockVueApp) + }, + config: { errorHandler: undefined } + } + const client = new Client({ apiKey: 'API_KEYYY', plugins: [new BugsnagVuePlugin()] }) + // eslint-disable-next-line + mockVueApp.use(client.getPlugin('vue')!) + client._setDelivery(client => ({ + sendEvent: (payload) => { + expect(payload.events[0].errors[0].errorClass).toBe('Error') + expect(payload.events[0].errors[0].errorMessage).toBe('oops') + expect(payload.events[0]._metadata.vue).toBeDefined() + expect(payload.events[0]._metadata.vue.component).toBe('MyComponent') + expect(payload.events[0]._metadata.vue.errorInfo).toBe('render function') + done() + }, + sendSession: () => {} + })) + expect(typeof mockVueApp.config.errorHandler).toBe('function') + const errorHandler = mockVueApp.config.errorHandler as unknown as Vue3ErrorHandler + errorHandler(new Error('oops'), { $options: { name: 'MyComponent' } }, 'https://vuejs.org/errors/#runtime-1') + }) + it('tolerates unmappable info paramater', done => { const mockVueApp: Vue3App = { use: (plugin) => { @@ -106,7 +132,7 @@ describe('bugsnag vue', () => { errorHandler(new Error('oops'), { $options: { name: 'MyComponent' } }, 'abcz') }) - it('tolerates tolerates anonymous components', done => { + it('tolerates anonymous components', done => { const mockVueApp: Vue3App = { use: (plugin) => { plugin.install(mockVueApp)