diff --git a/packages/vue/.eslintrc.js b/packages/vue/.eslintrc.js index 46d8d10cc538..c8be6a5fdebb 100644 --- a/packages/vue/.eslintrc.js +++ b/packages/vue/.eslintrc.js @@ -3,4 +3,12 @@ module.exports = { browser: true, }, extends: ['../../.eslintrc.js'], + overrides: [ + { + files: ['vite.config.ts'], + parserOptions: { + project: ['tsconfig.test.json'], + }, + }, + ] }; diff --git a/packages/vue/package.json b/packages/vue/package.json index 371fc276001d..47165ebe6e5f 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -69,8 +69,8 @@ "clean": "rimraf build coverage sentry-vue-*.tgz", "fix": "eslint . --format stylish --fix", "lint": "eslint . --format stylish", - "test": "jest", - "test:watch": "jest --watch", + "test": "vitest run", + "test:watch": "vitest --watch", "yalc:publish": "ts-node ../../scripts/prepack.ts && yalc publish build --push --sig" }, "volta": { diff --git a/packages/vue/test/errorHandler.test.ts b/packages/vue/test/errorHandler.test.ts index 3245fa80a356..54ac440043ad 100644 --- a/packages/vue/test/errorHandler.test.ts +++ b/packages/vue/test/errorHandler.test.ts @@ -1,4 +1,5 @@ import { setCurrentClient } from '@sentry/browser'; +import { afterEach, describe, expect, test, vi } from 'vitest'; import { attachErrorHandler } from '../src/errorhandler'; import type { Operation, Options, ViewModel, Vue } from '../src/types'; @@ -7,7 +8,7 @@ import { generateComponentTrace } from '../src/vendor/components'; describe('attachErrorHandler', () => { describe('attachProps', () => { afterEach(() => { - jest.resetAllMocks(); + vi.resetAllMocks(); }); describe("given I don't want to `attachProps`", () => { @@ -325,13 +326,13 @@ const testHarness = ({ enableConsole, vm, }: TestHarnessOpts) => { - jest.useFakeTimers(); - const providedErrorHandlerSpy = jest.fn(); - const warnHandlerSpy = jest.fn(); - const consoleErrorSpy = jest.fn(); + vi.useFakeTimers(); + const providedErrorHandlerSpy = vi.fn(); + const warnHandlerSpy = vi.fn(); + const consoleErrorSpy = vi.fn(); const client: any = { - captureException: jest.fn(async () => Promise.resolve()), + captureException: vi.fn(async () => Promise.resolve()), }; setCurrentClient(client); @@ -339,7 +340,7 @@ const testHarness = ({ config: { silent: !!silent, }, - mixin: jest.fn(), + mixin: vi.fn(), }; if (enableErrorHandler) { @@ -380,7 +381,7 @@ const testHarness = ({ app.config.errorHandler(new DummyError(), vm, 'stub-lifecycle-hook'); // and waits for internal timers - jest.runAllTimers(); + vi.runAllTimers(); }, expect: { errorHandlerSpy: expect(providedErrorHandlerSpy), diff --git a/packages/vue/test/integration/VueIntegration.test.ts b/packages/vue/test/integration/VueIntegration.test.ts index 81e3b863a16e..bf4773e2154a 100644 --- a/packages/vue/test/integration/VueIntegration.test.ts +++ b/packages/vue/test/integration/VueIntegration.test.ts @@ -1,5 +1,6 @@ import type { Client } from '@sentry/types'; import { logger } from '@sentry/utils'; +import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { createApp } from 'vue'; import * as Sentry from '../../src'; @@ -15,10 +16,11 @@ describe('Sentry.VueIntegration', () => { const globalRequest = globalThis.Request; beforeAll(() => { - globalThis.fetch = jest.fn(); // @ts-expect-error This is a mock - globalThis.Response = jest.fn(); - globalThis.Request = jest.fn(); + globalThis.fetch = vi.fn(); + // @ts-expect-error This is a mock + globalThis.Response = vi.fn(); + globalThis.Request = vi.fn(); }); afterAll(() => { @@ -31,17 +33,17 @@ describe('Sentry.VueIntegration', () => { warnings = []; loggerWarnings = []; - jest.spyOn(logger, 'warn').mockImplementation((message: unknown) => { + vi.spyOn(logger, 'warn').mockImplementation((message: unknown) => { loggerWarnings.push(message); }); - jest.spyOn(console, 'warn').mockImplementation((message: unknown) => { + vi.spyOn(console, 'warn').mockImplementation((message: unknown) => { warnings.push(message); }); }); afterEach(() => { - jest.resetAllMocks(); + vi.resetAllMocks(); }); it('allows to initialize integration later', () => { diff --git a/packages/vue/test/integration/init.test.ts b/packages/vue/test/integration/init.test.ts index c0652ad37485..1653cf670271 100644 --- a/packages/vue/test/integration/init.test.ts +++ b/packages/vue/test/integration/init.test.ts @@ -1,3 +1,4 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { createApp } from 'vue'; import type { Options } from '../../src/types'; @@ -10,13 +11,13 @@ describe('Sentry.init', () => { beforeEach(() => { warnings = []; - jest.spyOn(console, 'warn').mockImplementation((message: unknown) => { + vi.spyOn(console, 'warn').mockImplementation((message: unknown) => { warnings.push(message); }); }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('does not warn when correctly setup (Vue 3)', () => { diff --git a/packages/vue/test/router.test.ts b/packages/vue/test/router.test.ts index 1a27e84961b1..a0db80b0d985 100644 --- a/packages/vue/test/router.test.ts +++ b/packages/vue/test/router.test.ts @@ -1,3 +1,5 @@ +import { afterEach, describe, expect, it, test, vi } from 'vitest'; + import * as SentryBrowser from '@sentry/browser'; import * as SentryCore from '@sentry/core'; import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core'; @@ -6,21 +8,21 @@ import type { Span, SpanAttributes } from '@sentry/types'; import type { Route } from '../src/router'; import { instrumentVueRouter } from '../src/router'; -const captureExceptionSpy = jest.spyOn(SentryBrowser, 'captureException'); -jest.mock('@sentry/core', () => { - const actual = jest.requireActual('@sentry/core'); +const captureExceptionSpy = vi.spyOn(SentryBrowser, 'captureException'); +vi.mock('@sentry/core', async (importOriginal) => { + const actual = await importOriginal() return { ...actual, - getActiveSpan: jest.fn().mockReturnValue({}), + getActiveSpan: vi.fn().mockReturnValue({}), }; }); const mockVueRouter = { - onError: jest.fn void]>(), - beforeEach: jest.fn void) => void]>(), + onError: vi.fn void]>(), + beforeEach: vi.fn void) => void]>(), }; -const mockNext = jest.fn(); +const mockNext = vi.fn(); const testRoutes: Record = { initialPageloadRoute: { matched: [], params: {}, path: '', query: {} }, @@ -60,11 +62,11 @@ const testRoutes: Record = { describe('instrumentVueRouter()', () => { afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('should return instrumentation that instruments VueRouter.onError', () => { - const mockStartSpan = jest.fn(); + const mockStartSpan = vi.fn(); instrumentVueRouter( mockVueRouter, { routeLabel: 'name', instrumentPageLoad: true, instrumentNavigation: true }, @@ -90,7 +92,7 @@ describe('instrumentVueRouter()', () => { ])( 'should return instrumentation that instruments VueRouter.beforeEach(%s, %s) for navigations', (fromKey, toKey, transactionName, transactionSource) => { - const mockStartSpan = jest.fn(); + const mockStartSpan = vi.fn(); instrumentVueRouter( mockVueRouter, { routeLabel: 'name', instrumentPageLoad: true, instrumentNavigation: true }, @@ -128,15 +130,15 @@ describe('instrumentVueRouter()', () => { 'should return instrumentation that instruments VueRouter.beforeEach(%s, %s) for pageloads', (fromKey, toKey, transactionName, transactionSource) => { const mockRootSpan = { - getSpanJSON: jest.fn().mockReturnValue({ op: 'pageload' }), - updateName: jest.fn(), - setAttribute: jest.fn(), - setAttributes: jest.fn(), + getSpanJSON: vi.fn().mockReturnValue({ op: 'pageload' }), + updateName: vi.fn(), + setAttribute: vi.fn(), + setAttributes: vi.fn(), }; - jest.spyOn(SentryCore, 'getRootSpan').mockImplementation(() => mockRootSpan as unknown as Span); + vi.spyOn(SentryCore, 'getRootSpan').mockImplementation(() => mockRootSpan as unknown as Span); - const mockStartSpan = jest.fn().mockImplementation(_ => { + const mockStartSpan = vi.fn().mockImplementation(_ => { return mockRootSpan; }); instrumentVueRouter( @@ -168,7 +170,7 @@ describe('instrumentVueRouter()', () => { ); it('allows to configure routeLabel=path', () => { - const mockStartSpan = jest.fn(); + const mockStartSpan = vi.fn(); instrumentVueRouter( mockVueRouter, { routeLabel: 'path', instrumentPageLoad: true, instrumentNavigation: true }, @@ -195,7 +197,7 @@ describe('instrumentVueRouter()', () => { }); it('allows to configure routeLabel=name', () => { - const mockStartSpan = jest.fn(); + const mockStartSpan = vi.fn(); instrumentVueRouter( mockVueRouter, { routeLabel: 'name', instrumentPageLoad: true, instrumentNavigation: true }, @@ -223,9 +225,9 @@ describe('instrumentVueRouter()', () => { it("doesn't overwrite a pageload transaction name it was set to custom before the router resolved the route", () => { const mockRootSpan = { - updateName: jest.fn(), - setAttribute: jest.fn(), - setAttributes: jest.fn(), + updateName: vi.fn(), + setAttribute: vi.fn(), + setAttributes: vi.fn(), name: '', getSpanJSON: () => ({ op: 'pageload', @@ -234,10 +236,10 @@ describe('instrumentVueRouter()', () => { }, }), }; - const mockStartSpan = jest.fn().mockImplementation(_ => { + const mockStartSpan = vi.fn().mockImplementation(_ => { return mockRootSpan; }); - jest.spyOn(SentryCore, 'getRootSpan').mockImplementation(() => mockRootSpan as unknown as Span); + vi.spyOn(SentryCore, 'getRootSpan').mockImplementation(() => mockRootSpan as unknown as Span); instrumentVueRouter( mockVueRouter, @@ -283,10 +285,10 @@ describe('instrumentVueRouter()', () => { 'should return instrumentation that considers the instrumentPageLoad = %p', (instrumentPageLoad, expectedCallsAmount) => { const mockRootSpan = { - updateName: jest.fn(), - setData: jest.fn(), - setAttribute: jest.fn(), - setAttributes: jest.fn(), + updateName: vi.fn(), + setData: vi.fn(), + setAttribute: vi.fn(), + setAttributes: vi.fn(), name: '', getSpanJSON: () => ({ op: 'pageload', @@ -295,9 +297,9 @@ describe('instrumentVueRouter()', () => { }, }), }; - jest.spyOn(SentryCore, 'getRootSpan').mockImplementation(() => mockRootSpan as unknown as Span); + vi.spyOn(SentryCore, 'getRootSpan').mockImplementation(() => mockRootSpan as unknown as Span); - const mockStartSpan = jest.fn(); + const mockStartSpan = vi.fn(); instrumentVueRouter( mockVueRouter, { routeLabel: 'name', instrumentPageLoad, instrumentNavigation: true }, @@ -321,7 +323,7 @@ describe('instrumentVueRouter()', () => { ])( 'should return instrumentation that considers the instrumentNavigation = %p', (instrumentNavigation, expectedCallsAmount) => { - const mockStartSpan = jest.fn(); + const mockStartSpan = vi.fn(); instrumentVueRouter( mockVueRouter, { routeLabel: 'name', instrumentPageLoad: true, instrumentNavigation }, @@ -339,7 +341,7 @@ describe('instrumentVueRouter()', () => { ); it("doesn't throw when `next` is not available in the beforeEach callback (Vue Router 4)", () => { - const mockStartSpan = jest.fn(); + const mockStartSpan = vi.fn(); instrumentVueRouter( mockVueRouter, { routeLabel: 'path', instrumentPageLoad: true, instrumentNavigation: true }, diff --git a/packages/vue/test/vendor/components.test.ts b/packages/vue/test/vendor/components.test.ts index 77b54889326a..d496ac607099 100644 --- a/packages/vue/test/vendor/components.test.ts +++ b/packages/vue/test/vendor/components.test.ts @@ -1,3 +1,4 @@ +import { beforeEach, describe, expect, it } from 'vitest'; import { formatComponentName } from '../../src/vendor/components'; describe('formatComponentName', () => { diff --git a/packages/vue/tsconfig.test.json b/packages/vue/tsconfig.test.json index af7e36ec0eda..4a990e19513a 100644 --- a/packages/vue/tsconfig.test.json +++ b/packages/vue/tsconfig.test.json @@ -1,11 +1,11 @@ { "extends": "./tsconfig.json", - "include": ["test/**/*"], + "include": ["test/**/*", "vite.config.ts"], "compilerOptions": { // should include all types from `./tsconfig.json` plus types for all test frameworks used - "types": ["jest"] + "types": [] // other package-specific, test-specific options } diff --git a/packages/vue/vite.config.ts b/packages/vue/vite.config.ts new file mode 100644 index 000000000000..6a035a7635e7 --- /dev/null +++ b/packages/vue/vite.config.ts @@ -0,0 +1,13 @@ +import type { UserConfig } from 'vitest'; + +import baseConfig from '../../vite/vite.config'; + +export default { + ...baseConfig, + test: { + // test exists, no idea why TS doesn't recognize it + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ...(baseConfig as UserConfig & { test: any }).test, + environment: 'jsdom', + }, +};