diff --git a/packages/vue/src/router.ts b/packages/vue/src/router.ts index d8f87f14ad5d..25408f24f6b6 100644 --- a/packages/vue/src/router.ts +++ b/packages/vue/src/router.ts @@ -39,7 +39,7 @@ export type Route = { interface VueRouter { onError: (fn: (err: Error) => void) => void; - beforeEach: (fn: (to: Route, from: Route, next: () => void) => void) => void; + beforeEach: (fn: (to: Route, from: Route, next?: () => void) => void) => void; } /** @@ -129,7 +129,12 @@ export function vueRouterInstrumentation( }); } - next(); + // Vue Router 4 no longer exposes the `next` function, so we need to + // check if it's available before calling it. + // `next` needs to be called in Vue Router 3 so that the hook is resolved. + if (next) { + next(); + } }); }; } diff --git a/packages/vue/test/router.test.ts b/packages/vue/test/router.test.ts index 2e8fd9a01d0d..044228181f50 100644 --- a/packages/vue/test/router.test.ts +++ b/packages/vue/test/router.test.ts @@ -9,7 +9,7 @@ const captureExceptionSpy = jest.spyOn(SentryBrowser, 'captureException'); const mockVueRouter = { onError: jest.fn void]>(), - beforeEach: jest.fn void) => void]>(), + beforeEach: jest.fn void) => void]>(), }; const mockStartTransaction = jest.fn(); @@ -324,4 +324,30 @@ describe('vueRouterInstrumentation()', () => { expect(mockStartTransaction).toHaveBeenCalledTimes(expectedCallsAmount + 1); }, ); + + it("doesn't throw when `next` is not available in the beforeEach callback (Vue Router 4)", () => { + const instrument = vueRouterInstrumentation(mockVueRouter, { routeLabel: 'path' }); + instrument(mockStartTransaction, true, true); + const beforeEachCallback = mockVueRouter.beforeEach.mock.calls[0][0]; + + const from = testRoutes.normalRoute1; + const to = testRoutes.namedRoute; + beforeEachCallback(to, from, undefined); + + // first startTx call happens when the instrumentation is initialized (for pageloads) + expect(mockStartTransaction).toHaveBeenLastCalledWith({ + name: '/login', + metadata: { + source: 'route', + }, + data: { + params: to.params, + query: to.query, + }, + op: 'navigation', + tags: { + 'routing.instrumentation': 'vue-router', + }, + }); + }); });